一般情况下数据库表中存储的字段是其所对应的字典值,但当我们更据id查询详情或者查询列表时,每次都需要关联字典表查询,这样比较繁琐。
所需依赖:hutool 及 AOP
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!--hutool-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.5</version>
</dependency>
1.新建字典表
2.自定义注解
/**
* @author ntxz
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface BindDict {
//绑定的字段映射
String filedMapping();
//字典类型
String type();
}
3.编写注解aop实现
import cn.hutool.core.util.ReflectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ntxz.functional.entity.Result;
import com.ntxz.functional.entity.SysDict;
import com.ntxz.functional.service.SysDictService;
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 java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
/**
* @author ntxz
* @create 2023-02-20-14:36
*/
@Aspect
@Component
@Slf4j
public class DictAop {
@Autowired
private SysDictService sysDictService;
//切入点 com.ntxz.functional包下所有 类名是 *Controller 的类,方法参数任意个。
@Pointcut("execution(* com.ntxz.functional..*.*Controller.*(..))")
public void around()
{
}
/*
* 环绕通知
* */
@Around("around()")
public Object process(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
//1.执行原方法
Object proceed = proceedingJoinPoint.proceed();
//2.拿到原方法的原返回值 调用parseDict进行字典转换
this.parseDict(proceed);
return proceed;
}
private void parseDict(Object result) throws IllegalAccessException {
// 1.检测是否为统一返回(更据自身情况修改,Result是我自己编写的一个统一返回)
if(result instanceof Result){
//2.获取Result中的数据体
Object metaObj = ((Result) result).getData();
//返回是否是列表
if (metaObj instanceof ArrayList){
ArrayList list = (ArrayList) metaObj;
for (Object a:list){
doParseDict(a);
}
}
//返回单个对象
if (metaObj != null && !(metaObj instanceof ArrayList) ){
doParseDict(metaObj);
}
}
}
//绑定字典
public void doParseDict(Object obj) throws IllegalAccessException {
Field[] fields = ReflectUtil.getFields(obj.getClass());
if (fields != null && fields.length != 0){
Iterator<Field> iterator = Arrays.stream(fields).iterator();
while (iterator.hasNext()){
Field field = iterator.next();
BindDict dict = field.getAnnotation(BindDict.class);
//获取绑定了注解的字段
if (dict !=null){
//设置取消字段保护
field.setAccessible(true);
String mapping = dict.filedMapping();//字典值所在字段名
Field mappingField = ReflectUtil.getField(obj.getClass(), mapping);//获取字典值所在字段
mappingField.setAccessible(true);
//查询字典表
QueryWrapper<SysDict> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("type",dict.type()).eq("item_value",mappingField.get(obj));
SysDict dict1 = sysDictService.getOne(queryWrapper);
field.set(obj,dict1.getItemName());//设置字典
}
}
}
}
}
4.字典实体类
@TableName(value ="sys_dict")
@Data
public class SysDict implements Serializable {
/**
*
*/
@TableId(type = IdType.AUTO)
private Integer id;
/**
* 字典类型
*/
private String type;
/**
* 字典值
*/
private String itemValue;
/**
* 字典名称
*/
private String itemName;
@TableLogic
private String isDeleted;
private Date createTime;
private Date updateTime;
@TableField(exist = false)
private static final long serialVersionUID = 1L;
}
5.统一返回Result
/**
* @author ntxz
* @create 2021-10-19-22:27
*/
@Data
public class Result<T> {
//响应状态码
private Integer code;
//响应信息
private String msg;
//总记录数
private Long count;
//代表返回的数据
private T data;
}
6.测试类及vo用于绑定注解(也可以直接在实体类中使用)
测试类
@Data
public class TestDict {
@TableId(type = IdType.AUTO)
private Integer id;
private String name;
private String address;
private String sex;
}
vo
@Data
@ToString(callSuper = true)
public class TestDictVo extends TestDict {
@BindDict(filedMapping = "sex",type = "sex") //filedMapping 对应实体类的哪个字段,type字典类型
private String sexName;
@BindDict(filedMapping = "address",type = "address")
private String addressName;
@BindDict(filedMapping = "auditCode" ,type = "audit")
private String auditName;
}
7.编写测试Crontroller
@RestController
@Slf4j
@RequestMapping("/API")
public class APIController {
@GetMapping("/detail")
public Result getDict(){
TestDictVo testDictVo=new TestDictVo();
TestDict testDict = new TestDict();
testDict.setId(0);
testDict.setAddress("0");
testDict.setSex("0");
testDict.setName("sfgs");
BeanUtils.copyProperties(testDict, testDictVo);
return ResultUtils.buildSuccess(testDictVo);
}
@GetMapping("/list")
public Result getDict1(){
TestDictVo testDictVo=new TestDictVo();
TestDictVo testDictVo2=new TestDictVo();
TestDict testDict = new TestDict();
testDict.setId(0);
testDict.setAddress("0");
testDict.setSex("0");
testDict.setName("sfgs");
TestDict testDict2 = new TestDict();
testDict2.setId(1);
testDict2.setAddress("2");
testDict2.setSex("1");
testDict2.setName("sdfffg");
BeanUtils.copyProperties(testDict, testDictVo);
BeanUtils.copyProperties(testDict2, testDictVo2);
ArrayList<TestDictVo> list = new ArrayList<>();
list.add(testDictVo2);
list.add(testDictVo);
return ResultUtils.buildSuccess(list);
}
}