本例項目實踐過程中,數據模型創建包含公共字段(創建時間createTime,最後更新時間last_updated_time),爲了開發人員方便,打算自動填充時間公共字段;本例數據庫採用oceanbase; 以下2種方式,可以處理以下場景問題
1. 從數據庫表創建角度解決,表創建時給時間字段加上默認值,例如下面案例
CREATE TABLE TEST (
ID VARCHAR(100) DEFAULT NULL,
CREATE_TIME DATETIME(6) DEFAULT CURRENT_TIMESTAMP(6),
LAST_UPDATE_TIME DATETIME(6) DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
PRIMARY KEY (`ID`)
);
2. 在mybatis攔截器層解決
本案例 dao層 insert 或者 update 方法參數是實體,如果參數是其他類型參數,比如Map類型,也可以在攔截器實現
解決思路,在生成的實例類中的時間字段標記註解,在mybatis攔截器鏈執行Executor 階段填充時間
1)自定義註解
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD })
public @interface CreateTime {
String value() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD })
public @interface UpdateTime {
String value() default "";
}
2) 添加攔截器
@Intercepts({ @Signature(type = Executor.class, method = "update", args = { MappedStatement.class, Object.class }) })
public class GenerateTimeIntercepter implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
// sql 類型
SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();
// 獲取參數
Object parameter = invocation.getArgs()[1];
// 獲取私有成員變量
Field[] declaredFields = parameter.getClass().getDeclaredFields();
for (Field field : declaredFields) {
if (field.getAnnotation(CreateTime.class) != null) {
// insert 語句插入 createTime
if (SqlCommandType.INSERT.equals(sqlCommandType)) {
field.setAccessible(true);
field.set(parameter, new Date());
}
}
if (field.getAnnotation(UpdateTime.class) != null) {
// insert 或 update 語句插入 updateTime
if (SqlCommandType.INSERT.equals(sqlCommandType) || SqlCommandType.UPDATE.equals(sqlCommandType)) {
field.setAccessible(true);
field.set(parameter, new Date());
}
}
}
return invocation.proceed();
}
@Override
public Object plugin(Object target) {
if (target instanceof org.apache.ibatis.executor.Executor) {
return Plugin.wrap(target, this);
}
return target;
}
@Override
public void setProperties(Properties properties) {
}
參數類型是Map
@Intercepts({ @Signature(type = Executor.class, method = "update", args = { MappedStatement.class, Object.class }) })
public class GenerateTimeIntercepter implements Interceptor {
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public Object intercept(Invocation invocation) throws Throwable {
MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
// sql 類型
SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();
// 獲取參數
Object parameter = invocation.getArgs()[1];
if (parameter instanceof Map) {
//支持批量batchInsert 插入時間字段
Set<Entry<String, Object>> entrySet = ((Map<String, Object>) parameter).entrySet();
for (Entry<String, Object> set : entrySet) {
Object value = set.getValue();
if (value instanceof List) {
List tempList = (List) value;
for (int i = 0; i < tempList.size(); i++) {
Object obj = tempList.get(i);
Field[] declaredFields = obj.getClass().getDeclaredFields();
fillTime(declaredFields, sqlCommandType, obj);
}
}
}
}else {
// update 或者insert 執行此段邏輯
// 獲取私有成員變量
Field[] declaredFields = parameter.getClass().getDeclaredFields();
// 填充時間字段值
fillTime(declaredFields, sqlCommandType, parameter);
}
return invocation.proceed();
}
public void fillTime(Field[] declaredFields, SqlCommandType sqlCommandType, Object parameter) throws Throwable {
for (Field field : declaredFields) {
if (field.getAnnotation(CreateTime.class) != null) {
// insert 語句插入 createTime
if (SqlCommandType.INSERT.equals(sqlCommandType)) {
field.setAccessible(true);
field.set(parameter, new Date());
}
}
if (field.getAnnotation(UpdateTime.class) != null) {
// insert 或 update 語句插入 updateTime
if (SqlCommandType.INSERT.equals(sqlCommandType) || SqlCommandType.UPDATE.equals(sqlCommandType)) {
field.setAccessible(true);
field.set(parameter, new Date());
}
}
}
3. 注入攔截器
@Configuration
public class MybatisConfiguration {
/**
* 自定義插入CreateTime ,UpdateTime 時間
* @return
*/
@Bean
public GenerateTimeIntercepter generateTimeIntercepter() {
return new GenerateTimeIntercepter();
}
}