Class TenantAwareEntity

java.lang.Object
io.leandev.appfuse.jpa.tenant.TenantAwareEntity
All Implemented Interfaces:
TenantAware

@MappedSuperclass public abstract class TenantAwareEntity extends Object implements TenantAware

租戶感知實體基類

所有需要多租戶數據隔離的 Entity 都應繼承此類(或其子類)。 此類提供以下功能:

  • 自動注入當前租戶 ID(@PrePersist
  • 防止跨租戶數據更新(@PreUpdate
  • 支援 Hibernate Filter 自動過濾查詢結果

使用方式

方式 1:直接繼承(不需要審計功能)

@Entity
@Table(name = "products")
public class Product extends TenantAwareEntity {
    // ...
}

方式 2:建立應用層基類加入審計功能(推薦)

@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class AuditableTenantEntity extends TenantAwareEntity {

    @CreatedBy
    @Column(name = "created_by", updatable = false)
    private String createdBy;

    @CreatedDate
    @Column(name = "created_date", updatable = false)
    private Instant createdDate;

    @LastModifiedBy
    @Column(name = "last_modified_by")
    private String lastModifiedBy;

    @LastModifiedDate
    @Column(name = "last_modified_date")
    private Instant lastModifiedDate;
}

Hibernate Filter 啟用

需要在 AOP 或 Interceptor 中啟用 filter:

@Aspect
@Component
public class TenantFilterAspect {

    @PersistenceContext
    private EntityManager entityManager;

    @Before("@within(org.springframework.transaction.annotation.Transactional)")
    public void enableTenantFilter(JoinPoint joinPoint) {
        if (TenantContext.hasTenantContext()) {
            String tenantId = TenantContext.getCurrentTenantId();
            TenantFilterSupport.enableFilter(entityManager, tenantId);
        }
    }
}

設計說明

  • tenantId 使用 String 欄位而非 @ManyToOne 關聯,避免不必要的 JOIN 查詢
  • 不包含審計欄位,讓應用層自行決定是否需要審計功能
  • 不包含 @Id 欄位,讓子類自行定義主鍵策略
See Also:
  • Constructor Details

    • TenantAwareEntity

      public TenantAwareEntity()
  • Method Details

    • getTenantId

      public String getTenantId()
      Description copied from interface: TenantAware
      取得此 Entity 所屬的租戶 ID
      Specified by:
      getTenantId in interface TenantAware
      Returns:
      租戶 ID
    • setTenantId

      public void setTenantId(String tenantId)
      Description copied from interface: TenantAware

      設定此 Entity 所屬的租戶 ID

      通常在 @PrePersist 時自動設定,不應手動呼叫。

      Specified by:
      setTenantId in interface TenantAware
      Parameters:
      tenantId - 租戶 ID
    • onPrePersist

      protected void onPrePersist()

      在持久化前自動注入租戶 ID

      如果 tenantId 為 null,從 TenantContext 自動取得當前租戶 ID。 如果 tenantId 已設定,則驗證是否與當前上下文一致。

    • onPreUpdate

      protected void onPreUpdate()

      在更新前驗證租戶 ID

      防止跨租戶更新(安全性保障)。