1. 写一个类,implements Interceptor(mybatis 提供的拦截接口)。然后在类上使用
@Intercepts 注解和
@Signature 定义需要拦截的sql语句。
2. 最后,在 mybatis-config.xml 文件中添加该 插件:
代码如下,实现的是将入库的Date进行时间转换,以及出数据库的Date进行时间转换。具体的出入库时间转换规则,在下面代码中的TODO部分替换即可:
import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
/**
*
*/
@Intercepts({
@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}),
@Signature(type = Executor.class,method = "query", args = { MappedStatement.class, Object.class,
RowBounds.class, ResultHandler.class }),
@Signature(type = Executor.class,method = "query", args = { MappedStatement.class, Object.class,
RowBounds.class, ResultHandler.class, CacheKey.class,BoundSql.class })
})
public class MybatisDateInterceptor implements Interceptor {
private static Logger logger = LoggerFactory.getLogger(MybatisDateInterceptor.class);
/**
* 获取sql语句
*
* @param invocation
* @return
*/
public static String getSqlByInvocation(Invocation invocation) {
final Object[] args = invocation.getArgs();
MappedStatement ms = (MappedStatement) args[0];
Object parameterObject = args[1];
BoundSql boundSql = ms.getBoundSql(parameterObject);
return boundSql.getSql();
}
@Override
public Object intercept(Invocation invocation) throws InvocationTargetException, IllegalAccessException {
// 如果非海外版本,不进行时间转换
// if (!OverseasUtils.isOverseas()){
// return invocation.proceed();
// }
String processSql = getSqlByInvocation(invocation);
logger.info("原始sql==>{}", processSql);
Object[] args = invocation.getArgs();
MappedStatement mappedStatement = (MappedStatement) args[0];
SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();
Object result;
if (sqlCommandType == SqlCommandType.INSERT || sqlCommandType == SqlCommandType.UPDATE || sqlCommandType == SqlCommandType.DELETE ) {
logger.info("接收到sql 类型 {}",sqlCommandType);
result = doInsertUpdate(args, invocation);
} else if (sqlCommandType == SqlCommandType.SELECT) {
logger.info("接收到sql 类型 {}",sqlCommandType);
result = doSelect(args, invocation);
}else {
// do nothing
result = invocation.proceed();
}
return result;
}
private Object doInsertUpdate(Object[] args, Invocation invocation) throws InvocationTargetException, IllegalAccessException {
logger.info("检查所有字段的 Date类型");
convertAllLocalDateToDBTime(args);
Object result = invocation.proceed();
convertAllDBDateToLocalTime(args);
return result;
}
private Object doSelect(Object[] args, Invocation invocation) throws InvocationTargetException, IllegalAccessException {
convertAllLocalDateToDBTime(args);
Object result = invocation.proceed();
convertAllDBDateToLocalTime(args);
convertAllDBDateToLocalTime(new Object[]{result});
return result;
}
// private void tranDateProperty(Object arg) {
// try {
// Field[] declaredFields = arg.getClass().getDeclaredFields();
// for (Field field : declaredFields) {
// Class<?> type = field.getType();
// if (Date.class == field.getType()) {
// field.setAccessible(true);
// System.out.println(type);
// String name = field.getName();
// Object temp = field.get(arg);
// if (temp != null) {
// Date value = (Date) field.get(arg);
// System.out.println(value.getTime());
// Date date = DateTimeCalculatorUtil.reduceAccuracyToSecond(value);
// System.out.println(date.getTime());
// field.set(arg, date);
// // BeanUtils.setProperty(arg,name,date);
// }
// }
// }
// } catch (Exception e) {
// logger.error("日期数据转换出现了异常==>data:{}==>e:{}", JSONObject.toJSONString(), e);
// }
// }
@Override
public Object plugin(Object target) {
// 当目标类是StatementHandler类型时,才包装目标类,否者直接返回目标本身,减少目标被代理的次数
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
}
// public void convertAllLocalDateToDBTime(Object obj) {
// Field[] declaredFields = obj.getClass().getDeclaredFields();
// for (Field field : declaredFields) {
// Class<?> type = field.getType();
// if (type.equals(Date.class)) {
// field.setAccessible(true);
// try {
// Object temp = field.get(obj);
// if (temp != null) {
// Date localDate = (Date) temp;
// Date DBDate = DateUtil.local2DBDate(localDate);
// field.set(obj, DBDate);
// }
// } catch (IllegalArgumentException | IllegalAccessException e) {
// logger.error(e.getMessage());
// }
// }
// }
// }
private void convertAllLocalDateToDBTime(Object[] args) {
for (Object arg : args){
if (arg instanceof Map) {
//如果是map,有两种情况:(1)使用@Param多参数传入,由Mybatis包装成map。(2)原始传入Map
Collection<?> values = ((Map<?, ?>) arg).values();
values.parallelStream().forEach(this::transLocalDateToDBDate);
} else if (arg instanceof List) {
List<?> list = (List<?>) arg;
if (!list.isEmpty()) {
list.parallelStream().forEach(this::transLocalDateToDBDate);
}
} else {
transLocalDateToDBDate(arg);
}
}
}
private void convertAllDBDateToLocalTime(Object[] args) {
for (Object arg : args) {
if (arg instanceof Map) {
//如果是map,有两种情况:(1)使用@Param多参数传入,由Mybatis包装成map。(2)原始传入Map
Collection<?> values = ((Map<?, ?>) arg).values();
values.parallelStream().forEach(this::transDBDateToLocalDate);
} else if (arg instanceof List) {
List<?> list = (List<?>) arg;
if (!list.isEmpty()) {
list.parallelStream().forEach(this::transDBDateToLocalDate);
}
} else {
transDBDateToLocalDate(arg);
}
}
}
private void transLocalDateToDBDate(Object obj) {
if (obj == null || obj.getClass() == null) return;
Field[] declaredFields = obj.getClass().getDeclaredFields();
for (Field field : declaredFields) {
Class<?> type = field.getType();
if (type.equals(Date.class)) {
field.setAccessible(true);
try {
Object temp = field.get(obj);
if (temp != null) {
Date localDate = (Date) temp;
logger.info("Local 时间: " + localDate.toString());
// TODO: 在这里换成你要做的入库时间转换。
// Date DBDate = DateUtil.local2DBDate(localDate);
Date DBDate = new Date(localDate.getTime() + 24 * 60 * 60 * 1000);
logger.info("Local 时间 加一天后的 时间: " + DBDate.toString());
field.set(obj, DBDate);
}
} catch (IllegalArgumentException | IllegalAccessException e) {
logger.error(e.getMessage());
}
}
}
}
private void transDBDateToLocalDate(Object obj) {
if (obj == null || obj.getClass() == null) return;
Field[] declaredFields = obj.getClass().getDeclaredFields();
for (Field field : declaredFields) {
Class<?> type = field.getType();
if (type.equals(Date.class)) {
field.setAccessible(true);
try {
Object temp = field.get(obj);
if (temp != null) {
Date DBDate = (Date) temp;
logger.info("DB 时间: " + DBDate.toString());
// TODO: 在这里换成你要做的出库时间转换。
// Date DBDate = DateUtil.DB2LocalDate(localDate);
Date localDate = new Date(DBDate.getTime() + 24 * 60 * 60 * 1000);
logger.info("DB 时间 加一天后的 时间: " + localDate.toString());
field.set(obj, localDate);
}
} catch (IllegalArgumentException | IllegalAccessException e) {
logger.error(e.getMessage());
}
}
}
}
}