Mybatis拦截器,修改Date类型数据。设置毫秒为0
1:背景
Mysql自动将datetime类型的毫秒数四舍五入,比如代码中传入的Date类型的数据值为 2021.03.31 23:59:59.700 到数据库 2021.04.01 00:00:00.0。
对数据准确性造成影响。
2:解决方案
存入数据库之前去除毫秒数,终极方案使用mybatis拦截器,对insert和update类型的操作修改Date类型的参数值,去除毫秒数。
3:源代码
package com.hyx.study.commom.aop.interceptor; import com.hyx.study.commom.util.JacksonUtils; import com.xkzhangsan.time.calculator.DateTimeCalculatorUtil; import org.apache.ibatis.executor.Executor; import org.apache.ibatis.executor.statement.StatementHandler; 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.slf4j.Logger; import org.slf4j.LoggerFactory; import org.apache.commons.beanutils.BeanUtils; import org.springframework.stereotype.Component; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.sql.Connection; import java.sql.Statement; import java.util.*; /** * @author huangyaxiong * @version 1.0 * @description: 利用mybatis拦截器,修改所有得Date类型得参数省略毫秒数 * @date 2022-09-06 9:59 */ @Intercepts({ @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}) }) @Component 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 { String processSql = getSqlByInvocation(invocation); logger.info("原始sql==>{}",processSql); Object[] args = invocation.getArgs(); for(Object arg:args){ if(arg instanceof MappedStatement){ MappedStatement mappedStatement = (MappedStatement) arg; SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType(); logger.info("操作类型==>{}",sqlCommandType); if(sqlCommandType == SqlCommandType.INSERT || sqlCommandType == SqlCommandType.UPDATE){ continue; }else{ break; } }else if(arg instanceof Map){ //如果是map,有两种情况:(1)使用@Param多参数传入,由Mybatis包装成map。(2)原始传入Map logger.info("这是一个包装过的类型!"); Map map=(Map)arg; for (Object obj : map.values()){ tranDateProperty(obj); } }else { tranDateProperty(arg); } } return invocation.proceed (); } /** * @description: 修改对象中对的Date类型并且舍弃毫秒数 * @param arg * @author 'huangyaxiong' * @date: 2022-09-06 11:16 */ private static 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:{}", JacksonUtils.object2Json(arg),e); } } @Override public Object plugin(Object target) { // 当目标类是StatementHandler类型时,才包装目标类,否者直接返回目标本身,减少目标被代理的次数 return Plugin.wrap(target, this); // return null; } @Override public void setProperties(Properties properties) { } }