001 AOP切面使用注解翻译字典值

参考文献:https://my.oschina.net/angelbo/blog/2875887

感谢博主提供的解决思路方法

博主缺点:不能对字符串字典进行处理,已优化

需求

  • 在服务端开发,数据库表中有些字段对应的是字典值,在查询的时候要展示字典值,这个时候可能就需要关联字典表查询,或者在前后端开发过程中,由前端页面展示的部分调取字典服务的接口来展示,但这样都有问题,前者是数据库字典变更时要修改SQL,都不合理,那有没有更优雅的方式来完成字典值翻译呢?

思路

  • 现在都使用springboot来开发服务,springboot的注解太好用了,能不能使用切面拦截器的方式来完成字典翻译呢?
@TranslationDict({@DictParam(dictCode = "USER_GENDER_CODE",dictValueFiled = "gender",dictNameFiled = "genderName")})
  • 启用AOP 拦截注解TranslationDict,注解里描述需要翻译的字段,字典CODE,和目标字段(翻译完成后对应的值存储)

一、新建注解类

package com.epf.dict;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 翻译字典值注解
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(value={ElementType.METHOD})
@Documented
public @interface TranslationDict {
   DictParam[] value();
}
package com.epf.dict;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 需要翻译的字典值
 *
 * */
@Target(value={ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DictParam {

    /**
     * 字典CODE
     * @return
     */
    String dictCode() default "";

    /**
     * 需要翻译的字段名
     * @return
     */
    String dictValueFiled() default "";


    /**
     * 被翻译的字段名
     * @return
     */
    String dictNameFiled() default "";

}

二、新建拦截器

package com.epf.dict.aspect;

import static com.alibaba.fastjson.JSON.toJSONString;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.epf.dict.DictParam;
import com.epf.dict.TranslationDict;
import com.tiaim.system.entity.DictionariesEntity;
import com.tiaim.system.service.DictionariesService;

/**
 * 翻译字典值的
 */

@Aspect
@Component
public class TranslationDictAspect {
	
	@Autowired
	DictionariesService dictionariesService ;
	
    /**
     * 非基本类型在 CLASS 中的定义
     */
    private static final String FILED_NAME_TYPE = "TYPE";
    
    private Map dictInfoMap = new ConcurrentHashMap<>();

    
    @Around("@annotation(translationDict)")
    public Object Translation(final ProceedingJoinPoint pjp, TranslationDict translationDict) throws Throwable {
    	Object result = pjp.proceed();
    	// 第一步、获取返回值类型
        Class returnType = ((MethodSignature) pjp.getSignature()).getReturnType();
    	
    	//首先,取出要翻译字段的字典值
        String returnJsonResult = toJSONString(result,SerializerFeature.WriteMapNullValue);
        
    	DictParam[] dictParams = translationDict.value();
    	for (DictParam dictParam : dictParams) {
    		
    		//TODO 后期需优化读取Redis
    		 List dictInfos = dictionariesService.getDictionariesListNoPage();

             //先把字典值转成map
             for (DictionariesEntity dictInfo : dictInfos) {
                 dictInfoMap.put(dictInfo.getDictKey(),dictInfo.getZhCn());
             }
    		 Pattern dictPattern= Pattern.compile("\"" + dictParam.dictValueFiled() +".*?,");
             Matcher dictMatcher=dictPattern.matcher(returnJsonResult);
             
             StringBuffer sb = new StringBuffer();
             while (dictMatcher.find()){

                 //取出要翻译字段对应的值
            	 Pattern dictValuePattern= Pattern.compile(":\"(.*?)\",");
                 Matcher dictValueMatcher = dictValuePattern.matcher(dictMatcher.group().toString());
                 if( dictValueMatcher.find()){
                	 //翻译字典
                	 String dictInfoName = dictInfoMap.get(dictValueMatcher.group(1));
                	 String s = dictMatcher.group() + "\"" +  dictParam.dictNameFiled() + "\":\"" +dictInfoName + "\",";
                	 dictMatcher.appendReplacement(sb, s);
                 }else{
                	 String s = dictMatcher.group() + "\"" +  dictParam.dictNameFiled() + "\":\"\",";
                	 dictMatcher.appendReplacement(sb, s);
                 }
             }
             dictMatcher.appendTail(sb);
             returnJsonResult = sb.toString();
    	}
    	result = getJsonToResultObject(returnJsonResult,returnType);
    	
        return result;
    }
    
    
    private Object getJsonToResultObject(String returnJsonResult, Class returnType) {
        // 对象复原
        if (StringUtils.isNotBlank(returnJsonResult)) {
            // 基本类型则直接返回封装类型则对象转换
            if (returnType.isPrimitive()) {
                return returnJsonResult;
            } else {
                try {
                    if ((returnType.getField(FILED_NAME_TYPE)
                            .getClass()).isPrimitive()) {
                        return returnJsonResult;
                    }
                } catch (Exception e) {
                    return JSON.parseObject(returnJsonResult, returnType);
                }
            }
        }
        return null;
    }

}

拦截器主要逻辑:拦截方法,把返回值转成JSON,然后根据注解翻译JSON, 从JSON中取出DictParam中的 dictValueFiled字段的值,然后根据DictParam中的dictCode翻译对一个的字典,然后将翻译好的值插入dictNameFiled这个字段

三、例:

  • 例1:
  • 返回JSON值为
{userId:1,geneder:1,userName:'zhangsan'}
  • 注解为
@TranslationDict({@DictParam(dictCode = "USER_GENDER_CODE",dictValueFiled = "gender",dictNameFiled = "genderName")})
  • 拦截器处理时取出gender字段对应的值“1”和字典“USER_GENDER_CODE”翻译为“男性”,然后将男性赋值给genderName字段
{userId:1,geneder:1,genderName:'男性',userName:'zhangsan'}
  • 然后将JSON转对象返回即可,当然,要翻译的javabean必须要有genderName字段

  • 例2:
@Override
@TranslationDict({
	@DictParam(dictCode = "landType",dictValueFiled = "landType",dictNameFiled = "landTypeName"),
	@DictParam(dictCode = "firstClassUse",dictValueFiled = "firstClassUse",dictNameFiled = "firstClassUseName")
})
public List getTSellList(Pager pager, Example example) {
	// 分页属性设置
	PageHelper.startPage(pager.getPageNo(), pager.getPageSize());
	List list = tSellDao.selectByExample(example);
	PageInfo page = new PageInfo(list);
	/**
	 * 通过反射设置pager相关值,并在控制层获取。
	 **/
	pager.setTotalPage(page.getPages());
	pager.setTotalRecord((int) page.getTotal());
	return list;
}

优化

  • 拦截器优化,翻译字典从缓存里读取。。。

你可能感兴趣的:(java)