java项目时区实现

注意 :GMT与Etc/GMT不是一个意思

传统ssm项目增加时区功能

实现思路:

1. 项目中的时间和数据库存储的时间一致,可以为任一指定时区;

2. mybatis实现对返回实体类中的属性拦截和修改;

 

方式选型:

1. aop拦截,常用于拦截到方法,对于不会注入spring容器的返回entity(返回实体一般不会注入到spring容器里面)无法拦截;

2. 自定义注解拦截,自定义注解用的是aop的机制拦截的注解,所以没办法修改;

3. mybatis拦截器可以拦截所有关于数据库的操作,然后利用反射机制获取返回数据,并对对应字段值修改;

 

实现步骤:

1. 写一个mybatis拦截器

package xxxx;

import com.dfocus.gateway.server.common.utils.TimeZoneUtils;
import com.dfocus.gateway.server.enums.TimeTransType;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.executor.Executor;
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.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

@Intercepts(
@Signature(method = "query",
        type = Executor.class,
        args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}
)
)
@Slf4j
public class TimeZoneInterceptor implements Interceptor {


    @Autowired
    RedisTemplate redisTemplate;

    /**
     * 拦截器拦截操作
     * @param invocation
     * @return
     */
    @Override
    public Object intercept(Invocation invocation)  {

        Object proceed = null;
        try {
            //获取操作对象
            proceed = invocation.proceed();
            MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];


            /**
             * 下面这些值(返回值类型、返回实力类...)可以在上一行打个断点看一下具体代表什么,
             * 然后根据自己的需要获取到方法名或者返回实体类进行拦截和修改
             */          

            //获取返回值类型
            String returnType = invocation.getMethod().getReturnType().getName();

            //获取返回实体类
            String resultMap = mappedStatement.getResultMaps().get(0).getType().getName();

            //方法路径和名称
            String methodPathName = mappedStatement.getId();

            //注解中method的值
            String methodName = invocation.getMethod().getName();

            //sql类型
            SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();


            TimeTransType timeTransType = TimeTransType.find(returnType,resultMap,methodPathName);

            if (timeTransType != null){
                if ("query".equals(methodName)) {
                    //对有要求的字段填值
                    if (SqlCommandType.SELECT.equals(sqlCommandType)) {

                        switch (timeTransType){
                            case TYPE1:
                                List<Object> list = (List<Object>) proceed;
                                for (Object obj : list) {
                                    //获取gatewaysn
                                    String gatewaySn;
                                    try {
                                        gatewaySn = (String) getFieldValue(obj,"gatewaySN");
                                    }catch (Exception e){
                                        log.info("[时区时间转换获取gatewaySn数据出错]");
                                        break;
                                    }
                                    if (StringUtils.isEmpty(gatewaySn)){
                                        throw new NullPointerException();
                                    }
                                    String timeZoneId = getGatewayTimeZoneId(gatewaySn);

                                    Map<String,Object> l = new HashMap<>();
                                    l.put("createTime",String.class);
                                    l.put("updateTime",String.class);
                                    transTime(obj,timeZoneId,l);
                                }
                                break;
                           
                        }
                        log.info("[时区时间转换成功]timezone transform success!");
                    }
                }
            }
        } catch (Exception e) {
            log.error("[时区实践转换失败]timezone transform error",e);
            e.printStackTrace();
        }
        return proceed;
    }

    /**
     * @param target 表示被拦截的对象,此处为 Executor 的实例对象
     *               作用:如果被拦截对象所在的类有实现接口,就为当前拦截对象生成一个代理对象
     *               如果被拦截对象所在的类没有指定接口,这个对象之后的行为就不会被代理操作
     * @return
     */
    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {

    }

    /**
     * 查询所属时区
     * @param gatewaySn
     * @return
     */
    public String getGatewayTimeZoneId(String gatewaySn) {
        String tzId = "UTC";
        try {
            //此处实现获取timeZoneId
            }
        } catch (Exception ex) {
            log.error("获取时区timeZoneId错误,默认返回UTC时间,ex:{}", ex);
        }
        return tzId;
    }

    /**
     * 反射取值
     * @param obj
     * @param field
     * @return
     * @throws Exception
     */
    public Object getFieldValue(Object obj,String field) throws Exception{
        Field fieldName = obj.getClass().getDeclaredField(field);
        fieldName.setAccessible(true);
        return fieldName.get(obj);
    }

    /**
     * 反射设值
     * @param obj
     * @param field
     * @param value
     * @throws Exception
     */
    public void setFieldValue(Object obj,String field,Object value) throws Exception{
        Field[] fields = obj.getClass().getDeclaredFields();
        for (Field fld : fields) {
            if (field.equals(fld.getName())) {
                fld.setAccessible(true);
                fld.set(obj, value);
            }
        }
    }

    public void transTime(Object obj,String timeZoneId,Map<String,Object> map) throws Exception{
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            if (entry.getValue().equals(String.class) ){
                String originTime = (String) getFieldValue(obj,entry.getKey());
                if (StringUtils.isEmpty(originTime)){
                    setFieldValue(obj,entry.getKey(),"");
                    continue;
                }
                String transTime = TimeZoneUtils.string2TimezoneDefault(originTime,timeZoneId);
                setFieldValue(obj,entry.getKey(),transTime);
            }
        }
    }
}

2.写一个enum,来自定义拦截的方法或者对象

package com.dfocus.gateway.server.enums;

public enum TimeTransType {
    /**
     * 返回时间拦截
     */
    TYPE1("java.util.List","com.dfocus.gateway.server.module.server.base.pojo","*");

    private String returnType;

    private String resultMap;

    private String methodPathName;

    TimeTransType(String returnType, String resultMap, String methodPathName){
        this.returnType = returnType;
        this.resultMap = resultMap;
        this.methodPathName = methodPathName;
    }

    public String getReturnType() {
        return returnType;
    }

    public void setReturnType(String returnType) {
        this.returnType = returnType;
    }

    public String getResultMap() {
        return resultMap;
    }

    public void setResultMap(String resultMap) {
        this.resultMap = resultMap;
    }

    public String getMethodPathName() {
        return methodPathName;
    }

    public void setMethodPathName(String methodPathName) {
        this.methodPathName = methodPathName;
    }

    public static TimeTransType find(String returnType,String resultMap,String methodPathName) {
        for (TimeTransType timeTransType : TimeTransType.values()) {
            if (timeTransType.returnType.equals(returnType)
                    && timeTransType.resultMap.equals(resultMap)){
                if ("*".equals(timeTransType.methodPathName)
                        || timeTransType.methodPathName.equals(methodPathName)){
                    return timeTransType;
                }
            }
        }
        return null;
    }
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值