自定义序列化器处理用户名返回

540 阅读2分钟

前言

数据库里只保存了用户id,但需要返回对应的用户名给前端显示。实现方式很多,本文内容使用自定义序列化器与自定义注解实现。例如数据库有用户表、评论表数据

# 用户表
INSERT INTO `user`(`id`, `name`) VALUES ('1111', 'CodeHunter');
INSERT INTO `user`(`id`, `name`) VALUES ('2222', '测试用户2');

# 评论表
INSERT INTO `comment`(`id`, `content`, `user_id`) VALUES ('aaaaa', '评论1', '1111');
INSERT INTO `comment`(`id`, `content`, `user_id`) VALUES ('bbbbb', '评论2', '2222');

返回给前端结构

@Data
public class Comment implements Serializable {

    private String id;

    private String content;
    // 用户id
    private String userId;
    // 如这条评论id为aaaa,userName返回 CodeHunter
    private String userName;
}

思路

  • 自定义序列化器

    序列化userName字段时,通过反射与自定义注解拿到userId值,然后获取对应的用户名

  • 自定义注解

    作用在userName字段上,指向userId字段

实现

  • 定义@Username注解
 @Retention(RetentionPolicy.RUNTIME)
 @Target(ElementType.FIELD)
 public @interface Username {
     // 指向用户id的字段
     String value();
 }
  • 返回结构定义
 @Data
 public class Comment implements Serializable {
 
     private String id;
 
     private String content;
 
     private String userId;
 
     // 使用自定义序列化器处理,值为 null 时也使用自定义序列化器处理
     @JsonSerialize(using = UsernameSerializer.class, nullsUsing = UsernameSerializer.class)
     @Username("userId")
     private String username;
 }
  • 定义UsernameSerializer序列化器
@Component
@Slf4j
public class UsernameSerializer extends JsonSerializer<String> {
    @Override
    public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        // 需引入 hutool 工具类依赖
        // 如果有值则直接序列化
        if (StrUtil.isNotBlank(value)) {
            gen.writeString(value);
            return;
        }

        JsonStreamContext outputContext = gen.getOutputContext();
        // 获取当前序列化的字段名
        String currentName = outputContext.getCurrentName();
        // 获取当前序列化字段的所属对象
        Object currentValue = outputContext.getCurrentValue();

        try {
            /*
             *
             * 通过反射获取到当前序列化字段,再判断字段是否有@Username注解
             * 有则获取指向的用户id字段,通过反射获取到用户id的值,
             * 再通过用户id值获取对应的用户名
             *
             * */
            Field usernameField = ReflectUtil.getField(currentValue.getClass(), currentName);
            Username annotation = usernameField.getAnnotation(Username.class);
            if (Objects.nonNull(annotation)) {
                String userIdFieldName = annotation.value();
                if (StrUtil.isNotBlank(userIdFieldName)) {
                    Object idValue = ReflectUtil.getFieldValue(currentValue, userIdFieldName);
                    if (Objects.nonNull(idValue)) {
                        // TODO: 此处处理 userId -> userName; 可采用 Redis Hash处理
                        value = idValue.toString();
                    }
                }
            }

        } catch (Exception exception) {
            log.info("序列化用户名异常 {}", exception.getMessage());
        }

        gen.writeString(value);
    }
}

测试

  • 此处测试userName值直接取userId

  • 处理前

序列化前.png

  • 处理后(value值与userId一致)

序列化后.png

结尾

如果文章对你有帮助,请点赞 👍🏻 支持一下。若有错误之处或有更好的建议,欢迎指正,谢谢。