数据字典回显功能设计与实现
文章目录
- 数据字典回显功能设计与实现
- 1. 业务场景
- 2. 实现设计
- 2.1 注解+AOP切面
- 2.2 注解+mybatis拦截器
- 2.3 注解+序列化
- 2.4 涉及字段直接申明成字典引用类型+mybatis拦截器+反序列化处理
- 3. 具体实现
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;。。。
}