使用Mybatis的 Interceptor 实现对所有入库出库的Date字段进行转换

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());
                }
            }
        }
    }
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值