自定义注解结合Aop数据字典应用

梦想与她 提交于 2020-01-25 18:56:01

本篇博客主要聊聊自定义注解在项目中的应用,自定义注解用来做系统监控日志,这个用法已经烂大街了,无法让面试官眼前一亮的感觉。

项目开发中数据字典使用场景非常多,使用数据字典有一点非常的不方便,那就是数据库中存放的是数字,而实际页面上展示的却是汉字;那么这也就造成了,每次做页面展示的时候都需要给数字进行转义,将其转义成汉字内容展示到页面,而转换的过程过于繁琐;

咱们的自定义注解可以完美的解决这一问题;

浏览器输入:http://localhost:8080/student/listPager 测试

最后浏览器访问的效果图

小李飞刀_解决方案

小李飞刀_解决方案

当然,也可以不走默认规则,xxx就是在类属性上的自定义注解的属性值

小李飞刀_解决方案

相关的pom依赖

com.alibaba fastjson 1.2.4

逆向工程生成实体类、mapper.xml、mapper.java

实体类

package com.javaxl.model;

public class DataDict {
private Integer id;

private String datasource;

private String description;

public DataDict(Integer id, String datasource, String description) {
    this.id = id;
    this.datasource = datasource;
    this.description = description;
}

public DataDict() {
    super();
}

public Integer getId() {
    return id;
}

public void setId(Integer id) {
    this.id = id;
}

public String getDatasource() {
    return datasource;
}

public void setDatasource(String datasource) {
    this.datasource = datasource;
}

public String getDescription() {
    return description;
}

public void setDescription(String description) {
    this.description = description;
}

}

package com.javaxl.model;

public class DataItem {
private Integer id;

private String datasource;

private String code;

private String val;

public DataItem(Integer id, String datasource, String code, String val) {
    this.id = id;
    this.datasource = datasource;
    this.code = code;
    this.val = val;
}

public DataItem() {
    super();
}

public Integer getId() {
    return id;
}

public void setId(Integer id) {
    this.id = id;
}

public String getDatasource() {
    return datasource;
}

public void setDatasource(String datasource) {
    this.datasource = datasource;
}

public String getCode() {
    return code;
}

public void setCode(String code) {
    this.code = code;
}

public String getVal() {
    return val;
}

public void setVal(String val) {
    this.val = val;
}

}

package com.javaxl.model;

import com.javaxl.annotation.Dict;

public class Student {
private Integer id;

private String name;

@Dict(dicDataSource = "stu_Level")
private Integer stulevel;

@Dict(dicDataSource = "stu_English",dicText = "xxx")
private Integer englishlevel;

@Dict(dicDataSource = "stu_hobby")
private String stuhobby;

public Student(Integer id, String name, Integer stulevel, Integer englishlevel, String stuhobby) {
    this.id = id;
    this.name = name;
    this.stulevel = stulevel;
    this.englishlevel = englishlevel;
    this.stuhobby = stuhobby;
}

public Student() {
    super();
}

public Integer getId() {
    return id;
}

public void setId(Integer id) {
    this.id = id;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public Integer getStulevel() {
    return stulevel;
}

public void setStulevel(Integer stulevel) {
    this.stulevel = stulevel;
}

public Integer getEnglishlevel() {
    return englishlevel;
}

public void setEnglishlevel(Integer englishlevel) {
    this.englishlevel = englishlevel;
}

public String getStuhobby() {
    return stuhobby;
}

public void setStuhobby(String stuhobby) {
    this.stuhobby = stuhobby;
}

}

Mapper.java

package com.javaxl.mapper;

import com.javaxl.model.DataDict;

public interface DataDictMapper {
int deleteByPrimaryKey(Integer id);

int insert(DataDict record);

int insertSelective(DataDict record);

DataDict selectByPrimaryKey(Integer id);

int updateByPrimaryKeySelective(DataDict record);

int updateByPrimaryKey(DataDict record);

}

package com.javaxl.mapper;

import com.javaxl.model.DataItem;
import org.springframework.stereotype.Repository;
import org.springframework.web.bind.annotation.ResponseBody;

@Repository
public interface DataItemMapper {
int deleteByPrimaryKey(Integer id);

int insert(DataItem record);

int insertSelective(DataItem record);

DataItem selectByPrimaryKey(Integer id);

int updateByPrimaryKeySelective(DataItem record);

int updateByPrimaryKey(DataItem record);

DataItem selectByDatasourceCode(DataItem dataItem);

}

小李飞刀_解决方案

package com.javaxl.mapper;

import com.javaxl.model.Student;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public interface StudentMapper {
int deleteByPrimaryKey(Integer id);

int insert(Student record);

int insertSelective(Student record);

Student selectByPrimaryKey(Integer id);

int updateByPrimaryKeySelective(Student record);

int updateByPrimaryKey(Student record);

List<Student> listPager(Student student);

}

小李飞刀_解决方案

Service层

package com.javaxl.service;

import com.javaxl.model.DataItem;

/**

  • @author 小李飞刀

  • @site www.javaxl.com

  • @company

  • @create 2019-11-24 20:56
    */
    public interface DataItemService {
    DataItem selectByDatasourceKey(DataItem dataItem);

    String selectByDatasourceKey(String dataSource, String key);
    }

package com.javaxl.service;

import com.javaxl.model.Student;
import com.javaxl.util.PageBean;

import java.util.List;

/**

  • @author 小李飞刀
  • @site www.javaxl.com
  • @company
  • @create 2019-11-24 20:51
    */
    public interface StudentService {
    List listPager(Student student, PageBean pageBean);
    }

package com.javaxl.service.impl;

import com.javaxl.mapper.DataItemMapper;
import com.javaxl.model.DataItem;
import com.javaxl.service.DataItemService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**

  • @author 小李飞刀

  • @site www.javaxl.com

  • @company

  • @create 2019-11-24 21:01
    */
    @Service
    public class DataItemServiceImpl implements DataItemService {
    @Autowired
    private DataItemMapper dataItemMapper;
    @Override
    public DataItem selectByDatasourceKey(DataItem dataItem) {
    return dataItemMapper.selectByDatasourceCode(dataItem);
    }

    @Override
    public String selectByDatasourceKey(String dataSource, String key) {
    DataItem dataItem = new DataItem();
    dataItem.setDatasource(dataSource);
    dataItem.setCode(key);
    return dataItemMapper.selectByDatasourceCode(dataItem).getVal();
    }
    }

package com.javaxl.service.impl;

import com.javaxl.mapper.StudentMapper;
import com.javaxl.model.Student;
import com.javaxl.service.StudentService;
import com.javaxl.util.PageBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

/**

  • @author 小李飞刀
  • @site www.javaxl.com
  • @company
  • @create 2019-11-24 20:54
    */
    @Service
    public class StudentServiceImpl implements StudentService {
    @Autowired
    private StudentMapper studentMapper;
    @Override
    public List listPager(Student student, PageBean pageBean) {
    return studentMapper.listPager(student);
    }
    }

重点代码来了

package com.javaxl.controller;

import com.javaxl.model.Student;
import com.javaxl.service.StudentService;
import com.javaxl.util.PageBean;
import com.javaxl.util.PageUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import java.util.List;

/**

  • @author 小李飞刀

  • @site www.javaxl.com

  • @company

  • @create 2019-11-24 21:06
    */
    @Controller
    @RequestMapping("/student")
    public class StudentController {
    @Autowired
    private StudentService studentService;

    @ResponseBody
    @RequestMapping("/listPager")
    public PageUtils listPager(Student student, HttpServletRequest req){
    PageBean pageBean = new PageBean();
    pageBean.setRequest(req);
    List list = this.studentService.listPager(student,pageBean);
    PageUtils pageUtils = new PageUtils(list,pageBean.getTotal());
    return pageUtils;
    }
    }

DictAspect.java

package com.javaxl.aspect;

import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.javaxl.annotation.Dict;
import com.javaxl.service.DataItemService;
import com.javaxl.util.ObjConvertUtils;
import com.javaxl.util.PageUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**

  • @author 小李飞刀

  • @site www.javaxl.com

  • @company

  • @create 2019-11-24 20:39
    */
    @Aspect
    @Component
    @Slf4j
    public class DictAspect {
    private static String DICT_TEXT_SUFFIX = “_dictText”;

    @Autowired
    private DataItemService dataItemService;

    // 定义切点Pointcut 拦截所有对服务器的请求
    @Pointcut(“execution( * com.javaxl.controller..(…))”)
    public void excudeService() {
    }

    /**

    • 这是触发 excudeService 的时候会执行的,在环绕通知中目标对象方法被调用后的结果进行再处理
    • @param pjp
    • @return
    • @throws Throwable
      */
      @Around(“excudeService()”)
      public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
      //这是定义开始事件
      long time1 = System.currentTimeMillis();
      //这是方法并获取返回结果
      Object result = pjp.proceed();
      //这是获取到 结束时间
      long time2 = System.currentTimeMillis();
      log.debug(“获取JSON数据 耗时:” + (time2 - time1) + “ms”);
      //解析开始时间
      long start = System.currentTimeMillis();
      //开始解析(翻译字段内部的值凡是打了 @Dict 这玩意的都会被翻译)
      this.parseDictText(result);
      //解析结束时间
      long end = System.currentTimeMillis();
      log.debug(“解析注入JSON数据 耗时” + (end - start) + “ms”);
      return result;
      }

    /**

    • 本方法针对返回对象为Result 的PageUtils的分页列表数据进行动态字典注入

    • 字典注入实现 通过对实体类添加注解@dict 来标识需要的字典内容,字典分为单字典dataSource即可

    • 示例为Student

    • 字段为stu_sex 添加了注解@Dict(dicDataSource = “stu_sex”) 会在字典服务立马查出来对应的text 然后在请求list的时候将这个字典text,已字段名称加_dictText形式返回到前端

    • 例输入当前返回值的就会多出一个stu_sex_dictText字段

    • {

    • stu_sex:1,

    • stu_sex_dictText:“男”

    • }

    • 前端直接取值sext_dictText在table里面无需再进行前端的字典转换了

    • customRender:function (text) {

    • if(text==1){

    • return “男”;

    • }else if(text==2){

    • return “女”;

    • }else{

    • return text;

    • }

    • }

    • 目前vue是这么进行字典渲染到table上的多了就很麻烦了 这个直接在服务端渲染完成前端可以直接用

    • @param result
      */
      private void parseDictText(Object result) {
      if (result instanceof PageUtils) {
      List items = new ArrayList<>();
      PageUtils pageUtils = (PageUtils) result;
      //循环查找出来的数据
      for (Object record : pageUtils.getData()) {
      ObjectMapper mapper = new ObjectMapper();
      String json = “{}”;
      try {
      //解决@JsonFormat注解解析不了的问题详见SysAnnouncement类的@JsonFormat
      json = mapper.writeValueAsString(record);
      } catch (JsonProcessingException e) {
      log.error(“json解析失败” + e.getMessage(), e);
      }
      JSONObject item = JSONObject.parseObject(json);

           //update-begin--Author:scott -- Date:20190603 ----for:解决继承实体字段无法翻译问题------
           //for (Field field : record.getClass().getDeclaredFields()) {
           for (Field field : ObjConvertUtils.getAllFields(record)) {
               //update-end--Author:scott  -- Date:20190603 ----for:解决继承实体字段无法翻译问题------
               if (field.getAnnotation(Dict.class) != null) {
                   String datasource = field.getAnnotation(Dict.class).dicDataSource();
                   String text = field.getAnnotation(Dict.class).dicText();
                   //获取当前带翻译的值
                   String key = String.valueOf(item.get(field.getName()));
                   //翻译字典值对应的txt
                   String textValue = translateDictValue(datasource, key);
                   //  DICT_TEXT_SUFFIX的值为,是默认值:
                   // public static final String DICT_TEXT_SUFFIX = "_dictText";
                   log.debug(" 字典Val : " + textValue);
                   log.debug(" __翻译字典字段__ " + field.getName() + DICT_TEXT_SUFFIX + ": " + textValue);
                   //如果给了文本名
                   if (!StringUtils.isEmpty(text)) {
                       item.put(text, textValue);
                   } else {
                       //走默认策略
                       item.put(field.getName() + DICT_TEXT_SUFFIX, textValue);
                   }
      
               }
               //date类型默认转换string格式化日期
               if (field.getType().getName().equals("java.util.Date") && field.getAnnotation(JsonFormat.class) == null && item.get(field.getName()) != null) {
                   SimpleDateFormat aDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                   item.put(field.getName(), aDate.format(new Date((Long) item.get(field.getName()))));
               }
           }
           items.add(item);
       }
       pageUtils.setData(items);
      

      }
      }

    /**

    • 翻译字典文本

    • @param datasource

    • @param key

    • @return
      */
      private String translateDictValue(String datasource, String key) {
      //如果key为空直接返回就好了
      if (ObjConvertUtils.isEmpty(key)) {
      return null;
      }
      StringBuffer textValue = new StringBuffer();
      //分割 key 值
      String[] keys = key.split(",");
      //循环 keys 中的所有值
      for (String k : keys) {
      String tmpValue = null;
      log.debug(" 字典 key : " + k);
      if (k.trim().length() == 0) {
      continue; //跳过循环
      }
      tmpValue = dataItemService.selectByDatasourceKey(datasource, k.trim());

       if (tmpValue != null) {
           if (!"".equals(textValue.toString())) {
               textValue.append(",");
           }
           textValue.append(tmpValue);
       }
      

      }
      //返回翻译的值
      return textValue.toString();
      }
      }

Dict.java

package com.javaxl.annotation;

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

/**

  • @author 小李飞刀

  • @site www.javaxl.com

  • @company

  • @create 2019-11-24 20:37

  • 专门用于数据字典中的数字转汉字的自定义注解
    */
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Dict {

    /**

    • 方法描述: 数据dataSource
    • @return 返回类型: String
      */
      String dicDataSource();

    /**

    • 方法描述: 这是返回后Put到josn中的文本 key 值
    • @return 返回类型: String
      */
      String dicText() default “”;
      }

PageUtils.java

package com.javaxl.util;

import java.io.Serializable;
import java.util.List;

/**

  • @author 小李飞刀

  • @site www.javaxl.com

  • @company

  • @create 2019-11-24 20:36
    */
    public class PageUtils implements Serializable {
    private static final long serialVersionUID = 1L;
    //这是总行数
    private long total;
    //这是保持查询出来的数据
    private List<?> data;

    /**
    *

    • @param list 保存数据
    • @param total 查到多行数据
      */
      public PageUtils(List<?> list, long total) {
      this.data = list;
      this.total = total;
      }

    public long getTotal() {
    return total;
    }

    public void setTotal(int total) {
    this.total = total;
    }

    public List<?> getData() {
    return data;
    }

    public void setData(List<?> data) {
    this.data = data;
    }

    public static long getSerialVersionUID() {
    return serialVersionUID;
    }
    }

ObjConvertUtils.java

package com.javaxl.util;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**

  • @author 小李飞刀

  • @site www.javaxl.com

  • @company

  • @create 2019-11-24 20:37
    /
    public class ObjConvertUtils {
    /
    *

    • 获取类的所有属性,包括父类
    • @param object
    • @return
      */
      public static Field[] getAllFields(Object object) {
      Class<?> clazz = object.getClass();
      List fieldList = new ArrayList<>();
      while (clazz != null) {
      fieldList.addAll(new ArrayList<>(Arrays.asList(clazz.getDeclaredFields())));
      clazz = clazz.getSuperclass();
      }
      Field[] fields = new Field[fieldList.size()];
      fieldList.toArray(fields);
      return fields;
      }

    public static boolean isEmpty(Object object) {
    if (object == null) {
    return (true);
    }
    if ("".equals(object)) {
    return (true);
    }
    if (“null”.equals(object)) {
    return (true);
    }
    return (false);
    }

}

友情提示:

真正的自定义注解去做数据字典的转义,应该在切面类引用缓存技术,比如redis;不然的话每次转义一个数字为汉字,还需要查询一次数据库,性能十分低下;

over…

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!