介绍
项目中会有字典表,而业务表中存储的是字典表的id,每次查询的时候都需要left join
,感觉不是太舒服,所以,这种情况可以使用自定义注解配合AOP环绕通知解决;
类似的返回json如格式:
{
"id":100,
"name":"张三",
"age":1,
"ageDictName":"男" // 此字段为通过环绕通知获取生成
}
下面贴代码:
注解代码
实体类
@Data
@ToString
@ApiModel
public class PrjProject extends BaseEntity{
/** 主键id */
@ApiModelProperty("项目主键id")
private Long id;
/** 项目阶段状态 */
@Excel(name = "项目阶段状态")
@ApiModelProperty("项目阶段状态")
@Dict(dictType="project_stage")// 字典注解,dictType为字段类型
private Integer state;
}
@Dict
/**
* @author 岳晓鵬
* @version 1.0
* @date 2022/4/28 13:40
* @description 字典注解
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Dict {
/**
* 字典类型 对应表sys_dict_data dict_type字段
*
* @return
*/
String dictType() default "";
}
@QueryDict
/**
* @author 岳晓鵬
* @version 1.0
* @date 2022/4/28 14:41
* @description 作用在Controller方法上 标注拦截使用
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface QueryDict {
}
环绕通知
/**
* @author 岳晓鵬
* @version 1.0
* @date 2022/4/28 14:41
* @description 字典aop类
*/
@Aspect
@Component
@Slf4j
public class DictAspect {
/**
* 项目启动的时候会把字典表加载到redis,所以这里在redis中取数据
*/
@Autowired
private RedisTemplate redisTemplate;
/**
* 只拦截被QueryDict标注的Controller
*
* @param
* @return
* @throws Throwable
*/
@Around(value = "@annotation(com.xxxx.modules.common.annotation.QueryDict)")
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();
this.parseDictText(result);
long end = System.currentTimeMillis();
log.debug("解析注入JSON数据 耗时" + (end - start) + "ms");
return result;
}
/**
* 解析
*
* @param result
*/
private void parseDictText(Object result) {
List<JSONObject> items = new ArrayList<>();
// 判断返回类型,根据不同类型,走不同逻辑
if (result instanceof TableDataInfo) {
TableDataInfo rr = (TableDataInfo) result;
List<?> list = (List<?>) rr.getRows();
getData(items, list);
rr.setRows(items);
} else if (result instanceof AjaxResult) {
AjaxResult ar = (AjaxResult) result;
if (ar.get("data") instanceof java.lang.String) {
ar.put("data", ar.get("data"));
} else {
ar.put("data", getDataModel(ar.get("data")));
}
}
}
private Object getDataModel(Object data) {
ObjectMapper mapper = new ObjectMapper();
String json = "{}";
try {
json = mapper.writeValueAsString(data);
} catch (JsonProcessingException e) {
log.error("Json解析失败:" + e);
}
JSONObject item = JSONObject.parseObject(json);
for (Field field : ReflectUtil.getFields(data.getClass())) {
if (field.getAnnotation(Dict.class) != null) {
String dictType = field.getAnnotation(Dict.class).dictType();
String key = String.valueOf(item.get(field.getName()));
Optional<String> textValue = translateDictValue(dictType, key);
item.put(field.getName() + Constants.DICT_KEY, textValue.orElse("未知"));
}
}
return item;
}
private void getData(List<JSONObject> items, List<?> list) {
for (Object record : list) {
ObjectMapper mapper = new ObjectMapper();
String json = "{}";
try {
json = mapper.writeValueAsString(record);
} catch (JsonProcessingException e) {
log.error("Json解析失败:" + e);
}
JSONObject item = JSONObject.parseObject(json);
for (Field field : ReflectUtil.getFields(record.getClass())) {
if (field.getAnnotation(Dict.class) != null) {
String dictType = field.getAnnotation(Dict.class).dictType();
String key = String.valueOf(item.get(field.getName()));
//翻译字典值对应的text值
Optional<String> textValue = translateDictValue(dictType, key);
item.put(field.getName() + Constants.DICT_KEY, textValue.orElse("未知"));
}
}
items.add(item);
}
}
/**
* 通过redis获取字典数据
*
* @param dictType
* @param key
* @return
*/
private Optional<String> translateDictValue(String dictType, String key) {
log.info("dictType:{},key:{}", dictType, key);
List<SysDictData> sysDictDataList = (List<SysDictData>) redisTemplate.opsForValue().get(Constants.SYS_DICT_KEY + dictType);
return sysDictDataList.stream()
.filter(sysDictData -> sysDictData.getDictValue().equals(key))
.map(sysDictData -> sysDictData.getDictLabel())
.findFirst();
}
}