当前位置: 首页 > news >正文

SpringBoot 公共字段自动填充

在某些业务场景中,重复字段如create_time、update_time等频繁出现在每个实体类中。这种重复不仅增加了代码的冗余度,还导致了维护成本的上升。每次编写服务方法时,都需要手动设置这些字段,既费时又容易出错。特别是当字段变更时,需要在多个地方进行同步修改,增加了出错的风险。而且在更新操作中,若遗漏这些字段,可能会导致数据的不一致,给系统带来潜在的风险。

本文将分享一套经过生产验证的自动化方案,涵盖MyBatis-Plus、AOP等核心策略,助你彻底摆脱公共字段维护的烦恼。

方式一:MyBatis-Plus自动填充

  • 配置元对象处理器
@Slf4j
@Component
public class AutoFillHandler implements MetaObjectHandler {// 插入时自动填充@Overridepublic void insertFill(MetaObject metaObject){this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());this.strictInsertFill(metaObject, "createUser", String.class, getCurrentUser());this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());this.strictUpdateFill(metaObject, "updateUser", String.class, getCurrentUser());}// 更新时自动填充@Overridepublic void updateFill(MetaObject metaObject){this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());this.strictUpdateFill(metaObject, "updateUser", String.class, getCurrentUser());}// 获取当前用户(从安全上下文)private String getCurrentUser(){
//        return Optional.ofNullable(SecurityContextHolder.getContext())
//                .map(SecurityContext::getAuthentication)
//                .map(Authentication::getName)
//                .orElse("system");return "admin";}
}
  • 实体类注解配置
@Data
public class BaseEntity{@TableField(fill = FieldFill.INSERT)private LocalDateTime createTime;@TableField(fill = FieldFill.INSERT_UPDATE)private LocalDateTime updateTime;@TableField(fill = FieldFill.INSERT)private String createUser;@TableField(fill = FieldFill.INSERT_UPDATE)private String updateUser;
}

方式二:AOP统一处理

  • 自定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface AutoFill {OperationType value();
}
  • 切面实现
@Aspect
@Component
@Slf4j
public class AutoFillAspect{@Autowiredprivate ObjectMapper objectMapper;@Around("@annotation(autoFill)")public Object around(ProceedingJoinPoint pjp, AutoFill autoFill)throws Throwable {Object[] args = pjp.getArgs();for (Object arg : args) {if (arg instanceof BaseEntity) {fillFields((BaseEntity) arg, autoFill.value());}}return pjp.proceed(args);}private void fillFields(BaseEntity entity, OperationType type){String currentUser = getCurrentUser();LocalDateTime now = LocalDateTime.now();if (type == OperationType.INSERT) {entity.setCreateTime(now);entity.setCreateUser(currentUser);}entity.setUpdateTime(now);entity.setUpdateUser(currentUser);}// 获取当前用户(支持多线程环境)private String getCurrentUser(){return Optional.ofNullable(RequestContextHolder.getRequestAttributes()).map(attrs -> (ServletRequestAttributes) attrs).map(ServletRequestAttributes::getRequest).map(req -> req.getHeader("X-User-Id")).orElse("system");}
}

业务实现

  • 准备SQL
CREATE TABLE t_order (id BIGINT NOT NULL AUTO_INCREMENT COMMENT '订单ID',user_id BIGINT NOT NULL COMMENT '用户ID',order_number VARCHAR(50) NOT NULL COMMENT '订单编号',order_date DATETIME NOT NULL COMMENT '订单日期',total_amount DECIMAL(10, 2) NOT NULL COMMENT '订单总金额',status VARCHAR(20) NOT NULL COMMENT '订单状态',shipping_address VARCHAR(255) NOT NULL COMMENT '收货地址',payment_method VARCHAR(50) NOT NULL COMMENT '支付方式',shipping_date DATETIME COMMENT '发货日期',delivery_date DATETIME COMMENT '送达日期',create_time DATETIME NOT NULL COMMENT '创建时间',update_time DATETIME NOT NULL COMMENT '更新时间',create_user VARCHAR(50) NOT NULL COMMENT '创建用户',update_user VARCHAR(50) NOT NULL COMMENT '更新用户',PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单表';
  • 订单实体类
@Data
@TableName("t_order")
public class Order extends BaseEntity{@TableId(type = IdType.ASSIGN_ID)private Long id;  // 订单IDprivate Long userId;  // 用户IDprivate String orderNumber;  // 订单编号@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")private LocalDateTime orderDate;  // 订单日期private BigDecimal totalAmount;  // 订单总金额private String status;  // 订单状态private String shippingAddress;  // 收货地址private String paymentMethod;  // 支付方式@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")private LocalDateTime shippingDate;  // 发货日期@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")private LocalDateTime deliveryDate;  // 送达日期
}
  • OrderMapper
@Mapper
public interface OrderMapper extends BaseMapper<Order> {
}
  • IOrderService
@Service
public class IOrderService extends ServiceImpl<OrderMapper, Order> {@Resourceprivate OrderMapper orderMapper;public void insert(Order order) {orderMapper.insert(order);}public void update(Order order) {orderMapper.updateById(order);}
}
  • OrderController
@RestController
@RequestMapping("order")
public class OrderController {@Autowiredprivate IOrderService orderService;@ApiOperation("插入订单")@PostMapping("/insert")// 使用AOP填充时用@AutoFill注解// @AutoFill(OperationType.INSERT)public ResponseEntity<String> insert(@RequestBody Order order){orderService.insert(order);return ResponseEntity.ok("success");}@ApiOperation("修改订单")@PostMapping("/update")// 使用AOP填充时用@AutoFill注解// @AutoFill(OperationType.UPDATE)public ResponseEntity<String> update(@RequestBody Order order){orderService.update(order);return ResponseEntity.ok("success");}
}

操作日志

  • 准备SQL
CREATE TABLE `t_log` (`id` BIGINT NOT NULL COMMENT '主键ID',`operator` VARCHAR(255) NOT NULL COMMENT '操作人',`operation_type` VARCHAR(255) NOT NULL COMMENT '操作类型',PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='日志表';
  • 定义切面
@Aspect
@Component
public class OperationLogAspect{@Autowiredprivate LogService logService;@AfterReturning("@annotation(autoFill)")public void logOperation(AutoFill autoFill){LogEntry log = new LogEntry();log.setOperator("admin");log.setOperationType(autoFill.value().name());logService.save(log);}
}

这样,在新增或修改订单时,都会记录当前操作日志。


文章转载自:

http://0HPMuUrq.znmwb.cn
http://JS2qfCrB.znmwb.cn
http://tzdsJUC9.znmwb.cn
http://7IKEDaCy.znmwb.cn
http://ajJqISvy.znmwb.cn
http://cDBHN5WT.znmwb.cn
http://8Znqwj5o.znmwb.cn
http://cGjJpTNe.znmwb.cn
http://FwIu8ES2.znmwb.cn
http://AecCbm5o.znmwb.cn
http://piFQx3zY.znmwb.cn
http://kAcgYnyc.znmwb.cn
http://sNMiG8EH.znmwb.cn
http://wdUp9IIB.znmwb.cn
http://eWjWIy4m.znmwb.cn
http://ZsDHCgqk.znmwb.cn
http://QyQOCrr7.znmwb.cn
http://uK4m7qX8.znmwb.cn
http://hMDkxnLr.znmwb.cn
http://hHuY0Lrj.znmwb.cn
http://phGEuC3G.znmwb.cn
http://pCZ2poVW.znmwb.cn
http://HYoP6Pee.znmwb.cn
http://G4YWUGdB.znmwb.cn
http://4VuuZ6rZ.znmwb.cn
http://DwYLt56A.znmwb.cn
http://mitOFq7K.znmwb.cn
http://63MH9zH8.znmwb.cn
http://TzZp9ikX.znmwb.cn
http://zlPxBdyx.znmwb.cn
http://www.dtcms.com/a/372596.html

相关文章:

  • 《计算》第一二章读书笔记
  • 多模态大模型---第1节
  • 删除字符串中的空格
  • STM32 开发(三十三)STM32F103 片内资源 —— 直接存储 DMA 实战 编码详解
  • MGSM:大模型多语言数学推理的“试金石”
  • 卫星直连服务:从稀疏星座到全球覆盖的未来通信革命
  • FastAPI:像搭建餐厅一样设计API
  • 基于CNN-SE Attention和SHAP可解释性分析的故障诊断matlab
  • 企业级 Django 日志配置示例
  • URL 重写机制深度解析
  • OneCode可视化动作参数类型详解(一):核心枚举类ActionTypeEnum深度解析
  • Proxychains 配置全解析:从入门到高级应用
  • 第13章 非参数检验【9】:非参数检验和参数检验
  • (二)蓝牙架构概述-通俗易懂
  • [手写系列]Go手写db — — 第三版(实现分组、排序、聚合函数等)
  • 【74LS112+08同步十六进制和九进制0-8、8-0显示】2022-12-3
  • C++在控制台打印不同颜色的文本:让日志输出更炫酷
  • ego(3)---根据关键点求解B样条控制点
  • AutoHotkey下载安装并运行第一个脚本
  • ASP4644S电源芯片在商业卫星载荷通讯项目中的成本效益分析
  • HTTPS优化简单总结
  • 磁共振成像原理(理论):信号产生和探测(3)
  • 写程序or打游戏(组合计数)
  • 生成式AI基石之一:变分自编码器(VAE)详解:从架构到数学的深度指南
  • VXLAN集中式网关实验案例
  • 培训学校押金原路退回-企业自动运营——东方仙盟
  • Ubuntu系统的备份和恢复方法
  • 【已解决】Linux中程序脚本可以手动执行成功,但加在rc.local中不能开机自启
  • 芯片--低压差线性稳压器
  • C++逆向输出一个字符串(四)