农产品网站建设方案,余杭区建设局网站,哪里有服务好的网站建设公司,网站建设属于技术活吗公共字段自动填充
问题分析 我们在进行一些新增修改操作时#xff0c;我们需要设置创建时间、创建人、修改时间、修改人等字段。 这些字段属于公共字段#xff0c;也就是也就是在我们的系统中很多表中都会有这些字段#xff0c;如下#xff1a;
序号字段名含义数据类型1c…公共字段自动填充
问题分析 我们在进行一些新增修改操作时我们需要设置创建时间、创建人、修改时间、修改人等字段。 这些字段属于公共字段也就是也就是在我们的系统中很多表中都会有这些字段如下
序号字段名含义数据类型1create_time创建时间datetime2create_user创建人idbigint3update_time修改时间datetime4update_user修改人idbigint
而针对于这些字段我们的赋值方式为
1). 在新增数据时, 将createTime、updateTime 设置为当前时间, createUser、updateUser设置为当前登录用户ID。
2). 在更新数据时, 将updateTime 设置为当前时间, updateUser设置为当前登录用户ID。
如下操作 目前,在我们的项目中处理这些字段都是在每一个业务方法中进行赋值操作,如下:
新增员工方法 /*** 新增员工** param employeeDTO*/public void save(EmployeeDTO employeeDTO) {//.......................////设置当前记录的创建时间和修改时间employee.setCreateTime(LocalDateTime.now());employee.setUpdateTime(LocalDateTime.now());//设置当前记录创建人id和修改人idemployee.setCreateUser(BaseContext.getCurrentId());//目前写个假数据后期修改employee.setUpdateUser(BaseContext.getCurrentId());///employeeMapper.insert(employee);}编辑员工方法 /*** 编辑员工信息** param employeeDTO*/public void update(EmployeeDTO employeeDTO) {//........................................///employee.setUpdateTime(LocalDateTime.now());employee.setUpdateUser(BaseContext.getCurrentId());///employeeMapper.update(employee);}如果都按照上述的操作方式来处理这些公共字段, 需要在每一个业务方法中进行操作, 编码相对冗余、繁琐那能不能对于这些公共字段在某个地方统一处理来简化开发呢
答案是可以的我们使用AOP切面编程实现功能增强来完成公共字段自动填充功能。
实现思路
在实现公共字段自动填充也就是在插入或者更新的时候为指定字段赋予指定的值使用它的好处就是可以统一对这些字段进行处理避免了重复代码。在上述的问题分析中我们提到有四个公共字段需要在新增/更新中进行赋值操作, 具体情况如下:
序号字段名含义数据类型操作类型1create_time创建时间datetimeinsert2create_user创建人idbigintinsert3update_time修改时间datetimeinsert、update4update_user修改人idbigint
实现步骤
1). 自定义注解 AutoFill用于标识需要进行公共字段自动填充的方法
2). 自定义切面类 AutoFillAspect统一拦截加入了 AutoFill 注解的方法通过反射为公共字段赋值
3). 在 Mapper 的方法上加入 AutoFill 注解
若要实现上述步骤需掌握以下知识
枚举、注解、AOP、反射
第一步自定义注解 AutoFill
/*** 自定义注解用于标识某个方法需要进行功能字段自动填充处理*/
Target(ElementType.METHOD) //指定注解只能加在方法上
Retention(RetentionPolicy.RUNTIME) //用于描述注解的生命周期
public interface AutoFill {//指定一个属性指定当前数据库的操作类型使用枚举OperationType value();}OperationType是定义的一个公共枚举
/*** 数据库操作类型*/
public enum OperationType {/*** 更新操作*/UPDATE,/*** 插入操作*/INSERT}第二步:自定义切面 AutoFillAspect
Aspect //添加切面注解
Component //标识一个类作为组件被Spring管理
Slf4j
public class AutoFillAspect {/*** description 定义一个切入点* author 小辰* throws//参数是写切入点表达式 * 返回值是所有的 com.sy.mapper 拦截mapper包中的方法 .* 包下所有的类 .* 所有的方法 (..) 匹配所有的参数类型 annotation(com.sy.annotation.AutoFill) 也要满足AutoFill中定义的方法才生效其他方法不生效* time 2023/8/5 12:26*/Pointcut(execution(* com.sy.mapper.*.*(..)) annotation(com.sy.annotation.AutoFill))public void autoFillPointCut(){}//在执行sql之前使用所以用前置通知.在通知中进行公共字段赋值Before(autoFillPointCut()) //指定切入点public void autoFill(JoinPoint joinPoint){//通过连接点可以获取到拦截方法和方法参数log.info(开始公共字段自动填充...);//获取到当前被拦截的方法上的数据库操作类型MethodSignature signature (MethodSignature)joinPoint.getSignature();//方法签名对象AutoFill autoFill signature.getMethod().getAnnotation(AutoFill.class);//获得方法上的注解对象OperationType operationType autoFill.value();//获得数据库操作类型//获取到当前被拦截的方法的参数---实体对象 为了方便操作做一个约定将实体类参数放第一位Object[] args joinPoint.getArgs();if(args null || args.length0){return;}Object entity args[0];//准备赋值的数据LocalDateTime now LocalDateTime.now();Long currentId BaseContext.getCurrentId();//根据当前不同的操作类型为对应的属性通过反射来赋值if (operationType OperationType.INSERT){//填充四个公共字段赋值try {Method setCreateTime entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);Method setCrateUser entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class);Method setUpdateTime entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);Method setUpdateUser entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);//通过反射为对象属性赋值setCreateTime.invoke(entity,now);setCrateUser.invoke(entity,currentId);setUpdateTime.invoke(entity,now);setUpdateUser.invoke(entity,currentId);} catch (Exception e) {e.printStackTrace();}}else if(operationType OperationType.UPDATE){//为两个公共字段赋值try {Method setUpdateTime entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);Method setUpdateUser entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);//通过反射为对象赋值setUpdateTime.invoke(entity,now);setUpdateUser.invoke(entity,currentId);} catch (Exception e) {e.printStackTrace();}}}
}第三步:在Mapper接口的方法上加入 自定义注解AutoFill
分别在新增和修改方法添加AutoFill()注解
/*** 插入数据* param category*/Insert(insert into category(type, name, sort, status, create_time, update_time, create_user, update_user) VALUES (#{type}, #{name}, #{sort}, #{status}, #{createTime}, #{updateTime}, #{createUser}, #{updateUser}))AutoFill(value OperationType.INSERT)void insert(Category category);/*** 根据id修改分类* param category*/AutoFill(value OperationType.UPDATE)void update(Category category);第四步注解之前的赋值代码
同时将业务层为公共字段赋值的代码注释掉。 最后调试代码运行成功
结束