需求
使用 MyBatis 插入或修改某條記錄時,能自動設定資料表裡的 create_time 和 update_time 欄位,即自動給實體類物件的 createTime 和 updateTime 屬性賦值。(如果使用 MyBatis-Plus,該功能很容易實現,現在針對的場景是僅使用 MyBatis)
解決方案
使用AOP的思想,在執行新增或修改前,用反射獲取方法的第一個引數,給它的 createTime 和 updateTime 屬性賦值 。(約定:方法的第一個引數是要操作的實體類)
程式碼
1、自定義註解:
/**
* 標識 需要自動填充的方法
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoFill {
OperationType value();
}
2、列舉類:指定方法型別是 insert 還是 update,insert 操作需要 同時設定 createTime 和 updateTime,update操作只設定 updateTime 。
/**
* 操作型別
*/
public enum OperationType {
UPDATE,
INSERT
}
3、切面:
/**
* 自定義切面 自動填充公共欄位
*/
@Aspect
@Component
public class AutoFillAspect {
/**
* 切入點
* * com.example.mapper.*.*(..) 需要能定位到mapper介面的位置
* com.example.autofill.AutoFill 是上面寫的自定義註解的路徑
*/
@Pointcut("execution(* com.example.mapper.*.*(..)) && @annotation(com.example.autofill.AutoFill)")
public void autoFillPointCut() {
}
/**
* 前置通知,insert update之前 填充時間
*/
@Before("autoFillPointCut()")
public void autoFill(JoinPoint joinPoint) throws Exception {
//獲取到當前被攔截的方法上的資料庫操作型別
MethodSignature signature = (MethodSignature) joinPoint.getSignature();//方法簽名物件
AutoFill autoFill = signature.getMethod().getAnnotation(AutoFill.class);//獲得方法上的註解物件
OperationType operationType = autoFill.value();//獲得資料庫操作型別 insert update
// insert update 方法引數是實體類 需要放在第一個
// 獲取實體引數物件
Object[] args = joinPoint.getArgs();
if (args == null || args.length == 0) {
return;
}
Object entity = args[0];
// 為 createTime 和 updateTime 屬性賦值
LocalDateTime localDateTime = LocalDateTime.now();
if (operationType == OperationType.INSERT) {
// insert 操作 兩個時間都賦值
Method setCreateTime = entity.getClass().getMethod(SET_CREATE_TIME, LocalDateTime.class);
Method setUpdateTime = entity.getClass().getMethod(SET_UPDATE_TIME, LocalDateTime.class);
setCreateTime.invoke(entity, localDateTime);
setUpdateTime.invoke(entity, localDateTime);
} else if (operationType == OperationType.UPDATE) {
// update 操作 只設定更新時間
Method setUpdateTime = entity.getClass().getMethod(SET_UPDATE_TIME, LocalDateTime.class);
setUpdateTime.invoke(entity, localDateTime);
}
}
}
測試案例
實體類:
import lombok.Data;
import java.time.LocalDateTime;
@Data
public class User{
private Long id;
private String name;
private LocalDateTime createTime;
private LocalDateTime updateTime;
}
mapper介面:
/**
* 新增使用者
*/
@AutoFill(value = OperationType.INSERT)
Integer addUser(User user);
xml檔案:
<insert id="addUser" parameterType="user" useGeneratedKeys="true" keyProperty="id">
insert into user(name, create_time, update_time)
values (#{name}, #{createTime}, #{updateTime})
</insert>
測試方法:
@Resource
private UserMapper userMapper;
void test(){
User user = new User();
user.setName("張三"); // 無需手動設定 createTime 和 updateTime 屬性
userMapper.addUser(user);
}