mybatis-plus 实体类注解解释
package com.xxx.x.xx.model;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.Version;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
@Data
public class MybatisBaseModel implements Serializable {
private static final long serialVersionUID = 1L;
@TableField(fill = FieldFill.INSERT)
private Long createBy;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@TableField(fill = FieldFill.INSERT)
private Date createDt;
@TableField(fill = FieldFill.INSERT)
private Long createOrgan;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Long updateBy;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateDt;
@TableLogic
@TableField(fill = FieldFill.INSERT)
private String isDelete;
@TableField(fill = FieldFill.INSERT)
private Long sortOrder;
@Version
@TableField(fill = FieldFill.INSERT)
private Long rowVersion;
}
package com.zzz.z.zzz.model;
import com.alibaba.fastjson.annotation.JSONField;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.xxx.x.xx.model.MybatisBaseModel;
import com.purvar.petou.ei.common.BigDecimalSerializer;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
@Data
@TableName("DEMO_MY_INFO")
public class DemoMyModel extends MybatisBaseModel {
@ApiModelProperty(value = "主键ID")
@TableId
private Long id;
@ApiModelProperty(value = "金额累计总额(万元)")
@JSONField(serializeUsing = BigDecimalSerializer.class)
private BigDecimal totalReturnInvestmentAmount;
@ApiModelProperty(value = "出资基准日")
@DateTimeFormat(pattern = "yyyy-MM-dd")
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd")
private Date capitalContributionBasisDate;
@ApiModelProperty(value = 项目个数(个)")
private Integer projectCount;
@ApiModelProperty(value = "备注")
private String remarks;
@ApiModelProperty(value = "其他项目详情")
@TableField(exist = false)
private List<ReturnInvestmentProjectsOtherModel> otherModels;
}
我们先看父类里面的注解
@Data
@Data 是 Lombok 框架提供的一个注解,它相当于一键生成实体类中常用的样板代码(getter、setter、toString 等),帮你省去手动编写这些方法的繁琐工作
@Data 是一个组合注解,它相当于同时加上了以下注解:
| 等价注解 | 作用 |
|---|---|
@Getter | 为所有字段生成 getter 方法 |
@Setter | 为所有字段生成 setter 方法 |
@ToString | 生成 toString() 方法 |
@EqualsAndHashCode | 生成 equals() 和 hashCode() 方法 |
@RequiredArgsConstructor | 生成包含 final 字段和 @NonNull 字段的构造方法 |
@Data 经常和其他 Lombok 注解一起使用:
import lombok.*;
@Data
@NoArgsConstructor // 无参构造
@AllArgsConstructor // 全参构造
@Builder // 建造者模式
@Accessors(chain = true) // 链式调用(setter 返回 this)
public class User {
private Long id;
private String name;
private Integer age;
}
@TableField(fill = FieldFill.INSERT)
@TableField(fill = FieldFill.INSERT) 是 MyBatis-Plus 提供的字段自动填充功能,用于在插入数据时自动为某个字段赋值,无需手动设置。
| 部分 | 说明 |
|---|---|
@TableField | MyBatis-Plus 的字段注解 |
fill | 指定自动填充策略 |
FieldFill.INSERT | 仅在插入(INSERT)时自动填充该字段 |
如何生效?——需要配合 MetaObjectHandler
package com.xx.xx.common.mybatis.config;
import com.baomidou.mybatisplus.autoconfigure.ConfigurationCustomizer;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.purvar.ezgo.common.mybatis.injector.EzgoSqlInjector;
import com.purvar.ezgo.common.mybatis.properties.TenantProperties;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Date;
/**
* mybatis-plus配置文件
*/
@Configuration
@EnableConfigurationProperties(TenantProperties.class)
public class MybatisPlusConfiguration {
/**
* 配置全局map的key转小写
*
* @return ConfigurationCustomizer
*/
public ConfigurationCustomizer configurationCustomizer() {
return new ConfigurationCustomizer() {
@Override
public void customize(MybatisConfiguration configuration) {
configuration.setObjectWrapperFactory(new MapWrapperFactory());
}
};
}
/**
* 自定义sql注入器
*
* @return
*/
@Bean
public EzgoSqlInjector ezgoSqlInjector() {
return new EzgoSqlInjector();
}
/**
* mybatis-plus插件配置
*
* @return MybatisPlusInterceptor
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// mybatis-plus分页插件
interceptor.addInnerInterceptor(paginationInnerInterceptor());
//添加乐观锁插件
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
public PaginationInnerInterceptor paginationInnerInterceptor() {
PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();
// 设置最大单页限制数量,默认 500 条,-1 不受限制
paginationInnerInterceptor.setMaxLimit(-1L);
// 分页合理化
paginationInnerInterceptor.setOverflow(true);
return paginationInnerInterceptor;
}
/**
* mybatis-plus自动填充策略
*
* @return MetaObjectHandler
*/
@Bean
public MetaObjectHandler mybatisObjectHandler() {
return new MetaObjectHandler() {
@Override
public void insertFill(MetaObject metaObject) {
Date now = new Date();
Long userId = 1L;
this.strictInsertFill(metaObject, "createBy", Long.class, userId);
this.strictInsertFill(metaObject, "updateBy", Long.class, userId);
this.strictInsertFill(metaObject, "createDt", Date.class, now);
this.strictInsertFill(metaObject, "updateDt", Date.class, now);
this.strictInsertFill(metaObject, "isDelete", String.class, "0");
}
@Override
public void updateFill(MetaObject metaObject) {
Date now = new Date();
Long userId = 1L;
this.strictUpdateFill(metaObject, "updateBy", Long.class, userId);
this.strictUpdateFill(metaObject, "updateDt", Date.class, now);
}
};
}
}
| 策略 | 说明 | 适用字段 |
|---|---|---|
FieldFill.DEFAULT | 默认不填充 | — |
FieldFill.INSERT | 仅插入时填充 | create_time、create_by |
FieldFill.UPDATE | 仅更新时填充 | update_time、update_by |
FieldFill.INSERT_UPDATE | 插入和更新都填充 | version(乐观锁版本号) |
- 必须注册 MetaObjectHandler:只加注解不写处理器,填充不会生效。
- 手动赋值会覆盖自动填充:如果你在代码中手动设置了字段值,会以手动值为准。
- 字段名匹配:strictInsertFill 第一个参数传的是实体类的属性名(驼峰),MyBatis-Plus 会自动映射到数据库列名(下划线)。
- Spring Boot 自动扫描:MetaObjectHandler 实现类需要加上 @Component,让 Spring 管理。
@TableField(fill = FieldFill.XXX) 的自动填充功能,只有在使用 MyBatis-Plus
提供的内置方法时才会生效。如果你自己写自定义 SQL(XML 或 @Select/@Insert 等注解),自动填充不会触发。
使用 MyBatis-Plus 内置的 CRUD 方法时,自动填充会生效:
// ✅ 这些方法会触发自动填充
userMapper.insert(user);
userMapper.updateById(user);
userService.save(user);
userService.updateById(user);
哪些情况不会生效?
- 自定义 XML SQL
自定义注解 SQL
- 自定义注解 SQL
@Mapper
public interface UserMapper extends BaseMapper<User> {
// ❌ 不会触发自动填充
@Insert("INSERT INTO user (name, age) VALUES (#{name}, #{age})")
void insertUser(User user);
}
// ❌ 不会触发自动填充
@Update("UPDATE user SET name = #{name} WHERE id = #{id}")
void updateName(@Param("id") Long id, @Param("name") String name);
| 使用方式 | 自动填充是否生效 |
|---|---|
mapper.insert(entity) | ✅ 生效 |
service.save(entity) | ✅ 生效 |
mapper.updateById(entity) | ✅ 生效 |
| 自定义 XML SQL | ❌ 不生效 |
@Insert / @Update 注解 SQL | ❌ 不生效 |
@JSONField(serializeUsing = BigDecimalSerializer.class)
@JSONField(serializeUsing = BigDecimalSerializer.class) 是 FastJSON(阿里巴巴的 JSON 序列化/反序列化库)中的注解,用于自定义某个字段的序列化方式。
| 部分 | 说明 |
|---|---|
@JSONField | FastJSON 提供的字段级注解,控制 JSON 序列化/反序列化行为 |
serializeUsing | 指定自定义序列化器(Serializer),控制该字段输出为 JSON 时的格式 |
BigDecimalSerializer.class | 一个实现了 FastJSON 序列化接口的类,专门处理 BigDecimal 类型的格式化输出 |
为什么需要它?
BigDecimal 默认的 JSON 序列化输出可能不符合业务需求,常见问题:
- 科学计数法:new BigDecimal(“10000000000”) 可能被序列化为 1.0E+10
- 多余的尾零:new BigDecimal(“10.50”) 序列化为 10.50,但前端可能只需要 10.5
- null 值处理:null 的 BigDecimal 输出为 null,但业务可能希望输出 “0” 或 “”
通过 serializeUsing 指定自定义序列化器,可以统一控制输出格式。
package com.xxxx.xx.xx.common;
import com.alibaba.fastjson.serializer.JSONSerializer;
import com.alibaba.fastjson.serializer.ObjectSerializer;
import com.alibaba.fastjson.serializer.SerializeWriter;
import java.io.IOException;
import java.lang.reflect.Type;
import java.math.BigDecimal;
public class BigDecimalSerializer implements ObjectSerializer {
@Override
public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType, int features) throws IOException {
SerializeWriter out = serializer.out;
if (object == null) {
out.writeNull();
return;
}
if (object != null) {
BigDecimal value = (BigDecimal) object;
serializer.write(value.stripTrailingZeros().toPlainString());
}
}
}
测试效果:
Order order = new Order();
order.setId(1L);
order.setOrderNo("NO20260715001");
order.setAmount(new BigDecimal("10000000000")); // 10位数字
order.setPrice(new BigDecimal("10.50"));
String json = JSON.toJSONString(order);
// 输出:{"id":1,"orderNo":"NO20260715001","amount":"10000000000","price":"10.5"}
// ✅ 没有科学计数法,price 去掉了尾零
其他常见的 @JSONField 用法
public class User {
// 指定 JSON 中的字段名
@JSONField(name = "user_name")
private String userName;
// 格式化日期
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
// 序列化时忽略该字段(不输出到 JSON)
@JSONField(serialize = false)
private String password;
// 反序列化时忽略该字段(不从 JSON 读取)
@JSONField(deserialize = false)
private String internalFlag;
// 控制字段输出顺序
@JSONField(ordinal = 1)
private Long id;
}
@DateTimeFormat(pattern = “yyyy-MM-dd”)
方向:反序列化(请求参数 → Java 对象)
用于将前端传来的字符串解析为 Java 的日期类型(Date、LocalDate、LocalDateTime 等)。
@GetMapping("/list")
public List<Order> list(
@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate startDate,
@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate endDate) {
// 前端请求:/list?startDate=2026-07-01&endDate=2026-07-15
// Spring 会自动把字符串 "2026-07-01" 解析为 LocalDate 对象
}
注意:@DateTimeFormat 只影响请求参数的解析,对返回 JSON 没有任何作用。
@JsonFormat(timezone = “GMT+8”,pattern = “yyyy-MM-dd”)
这是 Jackson 提供的注解,控制 Java 日期对象输出为 JSON 时的格式。
@Data
public class Order {
private Long id;
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd")
private Date createTime;
}
Order order = new Order();
order.setId(1L);
order.setCreateTime(new Date());
String json = new ObjectMapper().writeValueAsString(order);
// 输出:{"id":1,"createTime":"2026-07-15"}
@JSONField(format = “yyyy-MM-dd HH:mm:ss”)
方向:序列化 + 反序列化(双向)
这是 FastJSON 提供的注解,format 属性同时控制序列化和反序列化的日期格式。
import com.alibaba.fastjson.annotation.JSONField;
@Data
public class Order {
private Long id;
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
}
// 序列化:Java → JSON
Order order = new Order();
order.setId(1L);
order.setCreateTime(new Date());
String json = JSON.toJSONString(order);
// 输出:{"id":1,"createTime":"2026-07-15 10:30:45"}
// 反序列化:JSON → Java
String jsonInput = "{\"id\":2,\"createTime\":\"2026-07-14 08:00:00\"}";
Order order2 = JSON.parseObject(jsonInput, Order.class);
// createTime 会被正确解析为 Date 对象
| 注解 | 所属框架 | 作用方向 | 典型场景 |
|---|---|---|---|
@DateTimeFormat | Spring Framework | 入参:字符串 → Java 日期对象 | 前端传日期字符串给后端 |
@JsonFormat | Jackson | 出参:Java 日期对象 → JSON 字符串 | 后端返回 JSON 给前端 |
@JSONField | FastJSON | 出参/入参:Java 日期对象 ↔ JSON 字符串 | 后端返回 JSON 给前端(使用 FastJSON 时) |
实际项目中常见的组合
Spring Boot + Jackson(默认)
@Data
public class Order {
private Long id;
@DateTimeFormat(pattern = "yyyy-MM-dd") // 接收前端参数
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd") // 返回给前端
private LocalDate orderDate;
}
或:
Spring Boot + FastJSON(替换了默认 JSON 处理器)
@Data
public class Order {
private Long id;
@DateTimeFormat(pattern = "yyyy-MM-dd") // 接收前端参数(Spring 负责)
@JSONField(format = "yyyy-MM-dd") // 返回给前端(FastJSON 负责)
private LocalDate orderDate;
}
只设置 @JSONField(format = “yyyy-MM-dd HH:mm:ss”)
-
作为响应返回给前端(✅ 完全够用)
-
通过 @RequestBody 接收前端 JSON(✅ 够用)
效果:FastJSON 会根据 @JSONField(format = …) 自动将字符串解析为 LocalDateTime。✅ 没问题 -
通过 URL 参数或表单接收(❌ 不够用)
前端请求:/list?startTime=2026-07-15 10:00:00&endTime=2026-07-15 18:00:00
效果:❌ 会报错。因为 URL 参数的解析是 Spring MVC 负责的,它用的是 @DateTimeFormat,完全不会看 @JSONField。
| 场景 | 是否需要 @DateTimeFormat | 是否需要 @JSONField |
|---|---|---|
| 返回 JSON 给前端 | ❌ 不需要 | ✅ 需要 |
@RequestBody 接收 JSON | ❌ 不需要(@JSONField 同时管反序列化) | ✅ 需要 |
@RequestParam / @ModelAttribute 接收参数 | ✅ 需要 | ❌ 不起作用 |
- 如果你的日期字段只出现在请求体和响应体中(前后端通过 JSON 交互),单独用 @JSONField(format = …) 就够了。
- 如果日期字段还会作为 URL 参数或表单参数传入,就必须额外加上 @DateTimeFormat。
我们可以理解一下
后端给前端, 前端给后端, 如果传递的是一个对象, 那他们必须通过序列化和反序列化处理
用 对象传值 @JSONField(format = “yyyy-MM-dd HH:mm:ss”)是可以的, 但过不是对象呢? 前端路由上传了一个日期 @RequestParam 则需要手动加上 才能解析@DateTimeFormat(pattern = “yyyy-MM-dd HH:mm:ss”)
下面的例子更直观一些.
场景一:
只写@JSONField(format = “yyyy-MM-dd”)
// 接收 JSON 请求体
@PostMapping("/order")
public void create(@RequestBody Order order) {
// 前端传 {"orderDate": "2026-07-15"}
// FastJSON 自动按 format 解析 → ✅ 生效
}
// 返回 JSON 响应
@GetMapping("/order/{id}")
public Order get(@PathVariable Long id) {
return orderService.getById(id);
// FastJSON 自动按 format 格式化 → ✅ 生效
}
这种情况下,orderDate 的进出都走 JSON,@JSONField 同时管序列化和反序列化,确实不需要 @DateTimeFormat。
场景二:Order 用于接收表单或 URL 参数(❌ 只写 @JSONField 不够)
@Data
public class OrderQuery {
private String name;
@JSONField(format = "yyyy-MM-dd") // ❌ 这里不起作用!
private LocalDate startDate;
}
// 前端请求:/list?name=张三&startDate=2026-07-01
@GetMapping("/list")
public List<Order> list(OrderQuery query) { // Spring 用 @ModelAttribute 方式绑定
// ❌ startDate 会绑定失败,报类型转换错误
}
原因:OrderQuery query 这种写法,Spring 是通过 @ModelAttribute 机制(表单/URL 参数绑定)来填充对象的,这个过程由 Spring 的 DataBinder 负责,它完全不认识 @JSONField,只看 @DateTimeFormat。
属性上什么也不写
普通属性什么都不写,默认就能正常序列化和反序列化。
更多推荐



所有评论(0)