springboot 实现REST接口返回自动拼接字典映射数据

在设计Restful接口时,一些字典数据为了更符合用户使用习惯,需要转换成对应的字典值。比如创建用户,数据库存的都是用户id,而页面需要展示用户的真实姓名。再比如一些状态,数据库存的可能是一些数字,需要页面上展示对应的状态描述。原则上应该由前端来调用字典接口进行转换,但有时为了降低前端的开发工作量,需要后端转换完成后返回给前端(仅针对前端开发资源不足的情况下,不推荐)

故基于springboot的返参解析机制,在处理返回结果时,检查返回对象中是否有@Dict注解,如有则基于返回对象类创建一个新的的类,添加被@Dict注解的字段,字段名为在原字段名后面拼了一个Label,然后创建对象并赋值。下面是具体代码实现。

新建一个@Dict注解,用来配置字典相关信息

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Dict {
    String dictName() default "";

    Class<? extends BaseMapping> mappingClass() default StaticDictMapping.class;
}
public interface BaseMapping {

    Object mapping(Object o, String dictName, String propertyName);
}

这里给一个静态字典的实现

@Component
public class StaticDictMapping implements BaseMapping {
    @Autowired
    private IDictDataService dictDataService;

    @Override
    public Object mapping(Object o, String dictName, String propertyName) {
        if (Objects.isNull(o) || StringUtils.isEmpty(dictName)) {
            return o;
        }
        return dictDataService.getDictDataPojo(dictName, o.toString()).getDictLabel();
    }
}

这里再给一个动态字典的实现

@Service
public class UserServiceImpl implements IUserService, BaseMapping {

    @Autowired
    private UserDao userDao;


    @Override
    public UserPojo queryUserByUserId(Long userId) {
        return userDao.queryUserByUserId(userId);
    }

  
    @Override
    public Object mapping(Object o, String dictName, String propertyName) {
        if (Objects.equals(dictName, "batchQuery")) {
            List<Long> userIds = Arrays.stream(((String) o).split(",")).filter(StringUtil::isNotEmpty).map(Long::valueOf).collect(Collectors.toList());
            return listUsersByIds(userIds);
        } else {
            UserPojo userPojo = this.queryUserByUserId(o instanceof Long ? (Long) o : Long.valueOf(o.toString()));
            return userPojo.getNickName();
        }
    }
}

新建一个Convert继承MappingJackson2HttpMessageConvert

@Configuration
public class DictMessageConvert extends MappingJackson2HttpMessageConverter {
    public DictMessageConvert(ObjectMapper objectMapper) {
        super(objectMapper);
    }

    @Override
    protected void writeInternal(Object o, Type type, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
        if (o instanceof TablePojo && !CollectionUtils.isEmpty(((TablePojo) o).getRows())) {
            ((TablePojo) o).setRows(parseObjToMap(((TablePojo) o).getRows()));
        }
        if (o instanceof AjaxResult && Objects.nonNull(((AjaxResult) o).get("data"))) {
            Object data = ((AjaxResult) o).get("data");
            Object parsed = parseObjToMap(data instanceof List ? (List<?>) data : Collections.singletonList(data));
            if (Objects.isNull(parsed)) {
                ((AjaxResult) o).put("data", null);
            }
            ((AjaxResult) o).put("data", data instanceof List ? parsed : ((List<?>) parsed).get(0));
        }
        super.writeInternal(o, type, outputMessage);
    }

    @Override
    protected boolean canWrite(MediaType mediaType) {
        return Objects.nonNull(mediaType) && Objects.equals(mediaType.toString(), "application/json");
    }

    public List<?> parseObjToMap(List<?> rows) {
        return rows.stream().map(o -> {
            Map<String, Object> labelMap = getLabelStr(o);
            if (!CollectionUtils.isEmpty(labelMap)) {
                return createDynamicBean(o, labelMap);
            }
            return o;
        }).collect(Collectors.toList());
    }

    private Object createDynamicBean(Object source, Map<String, Object> labelMap) {
        BeanGenerator generator = new BeanGenerator();
        generator.setSuperclass(source.getClass());
        labelMap.forEach((k, v) -> generator.addProperty(k + "Label", Object.class));
        Object rsltObj = generator.create();
        BeanUtils.copyProperties(source, rsltObj);
        final Class<?> dynamicObjClass = rsltObj.getClass();
        labelMap.forEach((k, v) -> {
            try {
                Field field = dynamicObjClass.getDeclaredField("$cglib_prop_" + k + "Label");
                field.setAccessible(true);
                field.set(rsltObj, v);
            } catch (Exception e) {
                logger.error(e);
            }
        });
        return rsltObj;
    }

    private Map<String, Object> getLabelStr(Object o) {
        return Arrays.stream(o.getClass().getDeclaredFields()).filter(field -> !Modifier.isFinal(field.getModifiers()))
                .filter(field -> field.isAnnotationPresent(Dict.class)).collect(Collectors.toMap(Field::getName, field -> {
                    try {
                        field.setAccessible(true);
                        Object val = field.get(o);
                        if (Objects.nonNull(val)) {
                            Dict dict = field.getAnnotation(Dict.class);
                            BaseMapping mapping = SpringUtil.getBeanWithNoThrow(dict.mappingClass());
                            if (Objects.isNull(mapping)) {
                                mapping = dict.mappingClass().newInstance();
                            }
                            return Objects.requireNonNull(mapping).mapping(val, dict.dictName(), field.getName());
                        }
                    } catch (Exception e) {
                        logger.error(e.getMessage(), e);
                    }
                    return Collections.emptyMap();
                }));
    }
}

返回对象用法

@Data
public class PermApplyPojo {
    /**
     * 申请id
     */
    private String applyId;


    /**
     * 申请人id
     */
    @Dict(mappingClass = UserServiceImpl.class)
    private Long applyUsrId;
    /**
     * 未审批-1,同意-3,拒绝-4,审批中-2
     */
    @Dict(dictName = "approval_status")
    private String auditStatus;

    /**
     * 被授权人
     */
    @NotEmpty(message = "被授权人不能为空")
    @Dict(mappingClass = UserServiceImpl.class, dictName = "batchQuery")
    private String authenticUsrIds;


    /**
     * 申请时间
     */
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date createTime;

 }

返回结果:
springboot 实现REST接口返回自动拼接字典映射数据_第1张图片

你可能感兴趣的:(Java基础,spring,boot,java,spring)