ป้ายกำกับ: Spatie

Spring Security: EntitySpring Security: Entity

เพื่อให้สอดคล้องกับโครงสร้างตารางแบบ Laravel Jetstream + Spatie ที่เราวางแผนไว้ใน Flyway Migration ไฟล์ Entity ใน Spring Boot จะต้องใช้การ Mapping แบบ Many-to-Many โดยมีรายละเอียดดังนี้ครับ


Permission Entity

ตัวนี้จะเก็บสิทธิ์ย่อย ๆ เช่น post-create, user-delete
src/main/java/com/example/demo/entity/Permission.java

package com.example.demo.entity;

import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;
import java.util.Set;

@Entity
@Table (name = "permissions") @Getter @Setter
public class Permission {
 @Id
 @GeneratedValue (strategy = GenerationType.IDENTITY) private Long id;

 @Column (unique = true, nullable = false) private String name;

 @Column (name = "guard_name") private String guardName = "web";

 @ManyToMany (mappedBy = "permissions") private Set<Role> roles;
}

Role Entity

ตัวนี้จะเชื่อมต่อไปยัง Permission แบบ Many-to-Many (เหมือน role_has_permissions ใน Laravel)
src/main/java/com/example/demo/entity/Role.java

package com.example.demo.entity;

import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;
import java.util.Set;

@Entity
@Table (name = "roles") @Getter @Setter
public class Role {
 @Id
 @GeneratedValue (strategy = GenerationType.IDENTITY) private Long id;

 @Column (unique = true, nullable = false) private String name;

 @Column (name = "guard_name") private String guardName = "web";

 @ManyToMany (fetch = FetchType.EAGER) @JoinTable (name = "role_has_permissions",
 joinColumns = @JoinColumn (name = "role_id") ,
 inverseJoinColumns = @JoinColumn (name = "permission_id")) private Set<Permission> permissions;
}

User Entity

ตัวนี้จะเก็บข้อมูลผู้ใช้และเชื่อมกับ Role (เหมือน model_has_roles ใน Laravel)
src/main/java/com/example/demo/entity/User.java

package com.example.demo.entity;

import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;
import java.time.LocalDateTime;
import java.util.Set;

@Entity
@Table (name = "users") @Getter @Setter
public class User {
 @Id
 @GeneratedValue (strategy = GenerationType.IDENTITY) private Long id;

 @Column (unique = true, nullable = false) private String username;

 @Column (nullable = false) private String password;

 @Column (unique = true) private String email;

 @Column (name = "full_name", columnDefinition = "nvarchar (255) ") private String fullName;

 @Column (name = "profile_photo_path", columnDefinition = "nvarchar (2048) ") private String profilePhotoPath;

 @Column (name = "created_at") private LocalDateTime createdAt;

 @Column (name = "updated_at") private LocalDateTime updatedAt;

 @ManyToMany (fetch = FetchType.EAGER) @JoinTable (name = "model_has_roles",
 joinColumns = @JoinColumn (name = "model_id") ,
 inverseJoinColumns = @JoinColumn (name = "role_id")) private Set<Role> roles;

 @PrePersist
 protected void onCreate () {
 createdAt = LocalDateTime.now () ;
 }

 @PreUpdate
 protected void onUpdate () {
 updatedAt = LocalDateTime.now () ;
 }
}

ข้อควรทราบเพิ่มเติม

  • เปลี่ยน com.example.demo เป็นชื่อ Package จริงที่คุณตั้งไว้ในโปรเจกต์
  • Lombok: ผมใช้ @Getter และ @Setter จาก Library Lombok เพื่อให้ Code ดูสะอาด (ถ้าโปรเจกต์คุณไม่ได้ลงไว้ ให้ใช้การ Generate Getter/Setter ปกติแทนครับ)
  • Naming Strategy: ใน Java มักใช้ camelCase (เช่น fullName) แต่ใน Database SQL Server ผมตั้งชื่อให้เป็น snake_case (เช่น full_name) ตามสไตล์ Laravel โดยใช้ @Column (name = "...") เป็นตัวเชื่อม
  • FetchType.EAGER: ตั้งค่าไว้ที่ Roles เพื่อให้เวลาโหลด User มาแล้ว สามารถดึงสิทธิ์มาเช็คใน Security Context ได้ทันที (คล้ายกับ $user->load ('roles') ใน Laravel)