数据字典回显功能设计与实现
文章目录
1. 业务场景
我们日常开发中经常会遇到:数据字典类型的字段存储至数据库的是id或者code,然而页面显示的时候却是名称
2. 实现设计
关于解决上述问题有以下几种方案:
2.1 注解+AOP切面
注解主要起标记作用,然后采用切面处理标记字段,把id或code转化成字典名称。这种方式可以灵活的标记是否需要回显转化处理,后面我采用这种方式举例说明
2.2 注解+mybatis拦截器
注解主要起标记作用,mybatis拦截器拦截之后,判断注解标记字段,把id或code转化成字典名称
2.3 注解+序列化
注解主要起标记作用,需增加专门的序列化处理器,序列化的过程中判断注解标记字段,把id或code转化成字典名称
2.4 涉及字段直接申明成字典引用类型+mybatis拦截器+反序列化处理
这种方式最为灵活,意思就是把涉及数据字典的字段,申明成字典类型(比如说DictData),前端就直接可以拿到字典的所有内容(包括id、code、名称)。
该种方式的实现需要三步操作:
1.涉及字段直接申明成字典引用类型
2.mybatis拦截之后通过id或code补全字典数据
3.前端传递的id或code在反序列化的过程中补全字典数据
3. 具体实现
- 定义方法标记注解,主要用来判断该接口是否需要字典转化
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface NeedEchoDict {
}
- 定义字段标记注解,主要用来判断字典类型字段
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DictData {
/**
* 字典类型
*
* @return
*/
String type() default "";
}
- AOP切面处理
@Slf4j
@Aspect
@Component
public class DictEchoAspect {
@Around("@annotation(com.jiayuan.common.annotation.NeedEchoDict)")
public Object translation(final ProceedingJoinPoint pjp) throws Throwable {
//目标方法执行
Object resultR = pjp.proceed();
if (ObjectUtil.isNull(resultR)) {
return resultR;
}
//获取返回data值
Object result = ((Result) resultR).getData();
if (result instanceof PageData) {
// 分页的情况
PageData page = (PageData) result;
result = ((PageData) result).getList();
result = translate(result);
page.setList((List) result);
((Result) resultR).setData(page);
return resultR;
}
result = translate(result);
((Result) resultR).setData(result);
return resultR;
}
/**
* 返回值转换,增加字典回显
*
* @param result
* @return
*/
private Object translate(Object result) {
if (result instanceof List || result instanceof ArrayList) {
for (Object entity : (List) result) {
to(entity);
}
} else {
to(result);
}
return result;
}
/**
* 根据类上注解,设置目标属性值
*
* @param entity 返回对象
*/
public void to(Object entity) {
Class c = entity.getClass();
for (; c != Object.class; c = c.getSuperclass()) {
try {
Field[] fields = c.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
Object preValue = field.get(entity);
Class<?> type = field.getType();
if (ObjectUtil.isNotNull(preValue)) {
//如果对象中包含list,判断list中是否包含注解
if (type.equals(List.class) || type.equals(ArrayList.class)) {
// 当前集合的泛型类型
Type genericType = field.getGenericType();
if (null == genericType) {
continue;
}
if (genericType instanceof ParameterizedType) {
for (Object o : (List) preValue) {
to(o);
}
}
}
//todo 自定义对象方式
if (field.isAnnotationPresent(DictData.class)) {
final String dictName = DictCache.getDictName(preValue.toString());
//设置字典内容
field.set(entity, dictName);
}
}
}
//父类存在子类不存在情况
} catch (Exception e) {
log.error("字典回显失败:{}", JSONUtil.toJsonStr(entity));
e.printStackTrace();
}
}
}
}
- 使用案例
@NeedEchoDict
@GetMapping("pageForApproval")
@ApiOperation("审批分页")
public Result<PageData<ApprovalAcademicActivityResponse>> pageForApproval(@Validated ApprovalAcademicActivityRequest request,
@Validated PageDTO pageDTO) {
PageData<ApprovalAcademicActivityResponse> page = academicActivityService.pageForApproval(request, pageDTO);
return Result.ok(page);
}
@Data
@ApiModel(value = "审批分页学术活动结果")
public class ApprovalAcademicActivityResponse Serializable {
private static final long serialVersionUID = -4402178057699015363L;
@DictData
@ApiModelProperty(value = "活动性质")
private String activityNature;
@DictData
@ApiModelProperty(value = "活动范围")
private String activityScope;
。。。
}