以下是符合 企业级 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 注解
- 🔄 通过 MapStruct 或 BeanUtils 在 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 中直接使用。
183

被折叠的 条评论
为什么被折叠?



