base-entity.java.ftl 通用基类实体模板

以下是符合 企业级 Java 开发规范、遵循 MyBatis-Plus 最佳实践 的两个核心实体类模板文件:

  • entity.java.ftl(具体业务实体类)
  • base-entity.java.ftl(通用基类实体)

这两个模板均不包含 OpenAPI 注解(遵循前文规范:Entity 不应耦合 API 层),但包含完整的 JPA/MyBatis-Plus 注解、逻辑删除、自动填充等企业级特性,并附有详尽的中文注释,可直接用于 MyBatis-Plus Generator 代码生成。


✅ 1. base-entity.java.ftl(通用基类实体模板)

package ${package.Entity};

<#-- 导入必要注解 -->
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableLogic;
import lombok.Data;
import lombok.experimental.Accessors;

import java.io.Serializable;
import java.time.LocalDateTime;

/**
 * <p>
 * 通用基类实体
 * </p>
 *
 * <p>
 * 【设计目标】
 * 1. 统一管理所有实体的公共字段(如创建时间、更新时间、逻辑删除等)
 * 2. 避免在每个业务实体中重复定义相同字段
 * 3. 与 MyBatis-Plus 自动填充、逻辑删除等插件无缝集成
 * </p>
 *
 * <p>
 * 【关键特性说明】
 * - {@code id}:主键(由子类通过 {@code @TableId} 声明具体策略)
 * - {@code createTime}:创建时间,插入时自动填充
 * - {@code updateTime}:更新时间,插入和更新时自动填充
 * - {@code deleted}:逻辑删除标识(0-未删除,1-已删除)
 * </p>
 *
 * <p>
 * 【重要原则】
 * - 此类为抽象基类,不应直接实例化
 * - 所有业务实体应继承此类
 * - 字段命名采用下划线转驼峰(如 create_time → createTime)
 * - 不包含任何 OpenAPI/Swagger 注解(Entity 不应暴露给 API 层)
 * </p>
 *
 * @author ${author}
 * @since ${date}
 */
@Data
@Accessors(chain = true)
public abstract class BaseEntity implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * 创建时间
     * <p>
     * 使用 MyBatis-Plus 的自动填充功能:
     * - 插入时自动设为当前时间
     * - 更新时保持不变
     * </p>
     */
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;

    /**
     * 更新时间
     * <p>
     * 使用 MyBatis-Plus 的自动填充功能:
     * - 插入时设为当前时间
     * - 每次更新时自动刷新为当前时间
     * </p>
     */
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;

    /**
     * 逻辑删除标识
     * <p>
     * - 0:未删除(正常状态)
     * - 1:已删除(逻辑删除)
     * </p>
     * <p>
     * 配合 MyBatis-Plus 的 {@code @TableLogic} 注解和全局配置,
     * 所有查询操作会自动追加 {@code AND deleted = 0} 条件,
     * 所有删除操作会自动转为 {@code UPDATE ... SET deleted = 1}。
     * </p>
     */
    @TableLogic
    @TableField(fill = FieldFill.INSERT) // 插入时默认为 0(未删除)
    private Integer deleted = 0;
}

✅ 2. entity.java.ftl(具体业务实体类模板)

package ${package.Entity};

<#-- 导入必要注解 -->
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;

import java.io.Serializable;
<#if entitySerialVersionUID>
import java.util.UUID;
</#if>

/**
 * <p>
 * ${table.comment!} 实体类
 * </p>
 *
 * <p>
 * 【设计说明】
 * 1. 继承 {@link BaseEntity},自动获得公共字段(createTime, updateTime, deleted)
 * 2. 使用 Lombok 简化 getter/setter/toString 等样板代码
 * 3. 通过 MyBatis-Plus 注解映射数据库表结构
 * 4. 主键策略、字段映射、逻辑删除等均由注解声明
 * </p>
 *
 * <p>
 * 【关键注解说明】
 * - {@code @TableName}:指定数据库表名(若类名与表名不一致)
 * - {@code @TableId}:标识主键字段及生成策略
 * - {@code @TableField}:映射普通字段(可指定列名、填充策略、是否参与查询等)
 * - {@code @TableLogic}:已在基类中定义,此处无需重复
 * </p>
 *
 * <p>
 * 【重要原则】
 * - 此类为持久层模型(ORM Entity),仅用于数据库操作
 * - **绝不直接用于 Controller 层返回或接收参数**(应使用 DTO/VO)
 * - **不包含任何 OpenAPI/Swagger 注解**(避免 API 层耦合)
 * - 字段应与数据库表结构严格对应
 * </p>
 *
 * @author ${author}
 * @since ${date}
 */
@Data
@EqualsAndHashCode(callSuper = true) // 包含父类字段参与 equals/hashCode
@Accessors(chain = true) // 支持链式调用:new User().setId(1).setName("张三")
@TableName("${table.name}") // 指定数据库表名
public class ${entity} extends BaseEntity implements Serializable {

    private static final long serialVersionUID = <#if entitySerialVersionUID>${entitySerialVersionUID}<#else>1L</#if>;

<#-- 遍历表字段生成属性 -->
<#list table.fields as field>
<#-- 跳过基类已定义的字段(createTime, updateTime, deleted) -->
<#if !(field.name == 'create_time' || field.name == 'update_time' || field.name == 'deleted')>
    <#-- 主键字段特殊处理 -->
    <#if field.keyFlag>
    /**
     * ${field.comment!}
     * <p>
     * 主键字段,使用 ${table.pk.name} 策略(通常为自增或雪花ID)
     * </p>
     */
    @TableId(value = "${field.name}", type = IdType.${table.pk.name})
    private ${field.propertyType} ${field.propertyName};
    <#else>
    /**
     * ${field.comment!}
     */
    <#-- 若字段名与属性名不一致,需显式指定 value -->
    <#if field.name != field.propertyName>
    @TableField("${field.name}")
    <#else>
    @TableField
    </#if>
    private ${field.propertyType} ${field.propertyName};
    </#if>
</#if>
</#list>

    /**
     * 【扩展建议】以下为常见业务场景示例(按需取消注释)
     */

    /*
    // 示例:枚举字段(数据库存 code,Java 用 Enum)
    private Integer status; // 数据库存 0/1

    // 转换方法(或使用 MyBatis-Plus TypeHandler)
    public UserStatus getStatusEnum() {
        return UserStatus.fromCode(this.status);
    }

    // 示例:JSON 字段(存储复杂对象)
    @TableField(typeHandler = JacksonTypeHandler.class)
    private Map<String, Object> metadata;
    */
}

🔍 关键设计说明与最佳实践

1. 分层架构严格分离
  • Entity:仅用于 DAO/Service 层,绝不暴露给 Controller
  • DTO/VO:专用于 API 层,包含 OpenAPI 注解
  • 🔄 通过 MapStructBeanUtils 在 Service 层进行 Entity ↔ DTO/VO 转换
2. MyBatis-Plus 特性集成
特性实现方式说明
自动填充@TableField(fill = FieldFill.INSERT)配合 MetaObjectHandler
逻辑删除@TableLogic + 全局配置查询自动过滤已删除数据
主键策略@TableId(type = IdType.ASSIGN_ID)支持雪花ID、自增等
字段映射@TableField("column_name")处理下划线命名
3. Lombok 使用规范
  • @Data:生成 getter/setter/toString/equals/hashCode
  • @EqualsAndHashCode(callSuper = true):确保继承关系下 equals 正确
  • @Accessors(chain = true):支持链式调用,提升可读性
4. 序列化安全
  • 实现 Serializable 接口(分布式缓存、RPC 场景需要)
  • 显式定义 serialVersionUID(避免反序列化失败)
5. 字段过滤策略
  • 模板中自动跳过基类字段(create_time, update_time, deleted
  • 避免字段重复定义

🛠️ 配套配置建议

(1) MyBatis-Plus 全局配置(application.yml)
mybatis-plus:
  global-config:
    db-config:
      logic-delete-value: 1    # 逻辑已删除值
      logic-not-delete-value: 0 # 逻辑未删除值
      id-type: assign_id       # 全局主键策略(雪花ID)
  configuration:
    map-underscore-to-camel-case: true # 下划线转驼峰
(2) 自动填充处理器(MetaObjectHandler)
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
    @Override
    public void insertFill(MetaObject metaObject) {
        this.strictInsertFill(metaObject, "createTime", LocalDateTime::now, LocalDateTime.class);
        this.strictInsertFill(metaObject, "updateTime", LocalDateTime::now, LocalDateTime.class);
        this.strictInsertFill(metaObject, "deleted", () -> 0, Integer.class);
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        this.strictUpdateFill(metaObject, "updateTime", LocalDateTime::now, LocalDateTime.class);
    }
}

📦 项目结构示例

src/main/java
└── com.example.demo
    └── entity
        ├── BaseEntity.java      ← 通用基类
        └── User.java            ← 业务实体(继承 BaseEntity)

✅ 这两份模板体现了 “持久层模型纯净化”“分层架构严格化” 的企业级开发思想:

  • Entity 专注数据持久化,无任何 API 层污染
  • 通过继承复用公共字段,减少重复代码
  • 与 MyBatis-Plus 深度集成,开箱即用
  • 为未来扩展(如审计字段、多租户)预留空间

可作为团队标准模板,在 MyBatis-Plus Generator 中直接使用。

ABP框架从4.0版本升级5.0版本, 应用程序构建编译成功完成, 但在运行时报错,如何解决? 完整报错日志如下: [19:04:52 FTL] Host terminated unexpectedly! Volo.Abp.AbpInitializationException: An error occurred during ConfigureServices phase of the module TeamWork.EntityFrameworkCore.TeamWorkEntityFrameworkCoreModule, TeamWork.EntityFrameworkCore, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null. See the inner exception for details. ---> System.TypeLoadException: Method 'GetListAsync' in type 'Volo.Abp.Domain.Repositories.EntityFrameworkCore.EfCoreRepository`2' from assembly 'Volo.Abp.EntityFrameworkCore, Version=50.0.7.0, Culture=neutral, PublicKeyToken=null' does not have an implementation. at Volo.Abp.EntityFrameworkCore.DependencyInjection.EfCoreRepositoryRegistrar.GetRepositoryType(Type dbContextType, Type entityType, Type primaryKeyType) at Volo.Abp.Domain.Repositories.RepositoryRegistrarBase`1.GetDefaultRepositoryImplementationType(Type entityType) at Volo.Abp.Domain.Repositories.RepositoryRegistrarBase`1.RegisterDefaultRepository(Type entityType) at Volo.Abp.Domain.Repositories.RepositoryRegistrarBase`1.RegisterDefaultRepositories() at Volo.Abp.Domain.Repositories.RepositoryRegistrarBase`1.AddRepositories() at Microsoft.Extensions.DependencyInjection.AbpEfCoreServiceCollectionExtensions.AddAbpDbContext[TDbContext](IServiceCollection services, Action`1 optionsBuilder) at TeamWork.EntityFrameworkCore.TeamWorkEntityFrameworkCoreModule.ConfigureServices(ServiceConfigurationContext context) in D:\gitsrc\NewBusinessColl\teamwork-git\src\TeamWork.EntityFrameworkCore\TeamWorkEntityFrameworkCoreModule.cs:line 24 at Volo.Abp.AbpApplicationBase.ConfigureServices() --- End of inner exception stack trace --- at Volo.Abp.AbpApplicationBase.ConfigureServices() at Volo.Abp.AbpApplicationBase..ctor(Type startupModuleType, IServiceCollection services, Action`1 optionsAction) at Volo.Abp.AbpApplicationWithExternalServiceProvider..ctor(Type startupModuleType, IServiceCollection services, Action`1 optionsAction) at Volo.Abp.AbpApplicationFactory.Create(Type startupModuleType, IServiceCollection services, Action`1 optionsAction) at Volo.Abp.AbpApplicationFactory.Create[TStartupModule](IServiceCollection services, Action`1 optionsAction) at Microsoft.Extensions.DependencyInjection.ServiceCollectionApplicationExtensions.AddApplication[TStartupModule](IServiceCollection services, Action`1 optionsAction) at TeamWork.HttpApi.Host.Startup.ConfigureServices(IServiceCollection services) in D:\gitsrc\NewBusinessColl\teamwork-git\src\TeamWork.Host\Startup.cs:line 17 at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor, Boolean wrapExceptions) at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) at Microsoft.AspNetCore.Hosting.ConfigureServicesBuilder.InvokeCore(Object instance, IServiceCollection services) at Microsoft.AspNetCore.Hosting.ConfigureServicesBuilder.<>c__DisplayClass9_0.<Invoke>g__Startup|0(IServiceCollection serviceCollection) at Microsoft.AspNetCore.Hosting.ConfigureServicesBuilder.Invoke(Object instance, IServiceCollection services) at Microsoft.AspNetCore.Hosting.ConfigureServicesBuilder.<>c__DisplayClass8_0.<Build>b__0(IServiceCollection services) at Microsoft.AspNetCore.Hosting.GenericWebHostBuilder.UseStartup(Type startupType, HostBuilderContext context, IServiceCollection services, Object instance) at Microsoft.AspNetCore.Hosting.GenericWebHostBuilder.<>c__DisplayClass13_0.<UseStartup>b__0(HostBuilderContext context, IServiceCollection services) at Microsoft.Extensions.Hosting.HostBuilder.CreateServiceProvider() at Microsoft.Extensions.Hosting.HostBuilder.Build() at TeamWork.HttpApi.Host.Program.Main(String[] args) in D:\gitsrc\NewBusinessColl\teamwork-git\src\TeamWork.Host\Program.cs:line 36
06-12
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

龙茶清欢

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值