前言
数据库里只保存了用户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值 -
处理前
- 处理后(value值与
userId一致)
结尾
如果文章对你有帮助,请点赞 👍🏻 支持一下。若有错误之处或有更好的建议,欢迎指正,谢谢。