Spring MVC中枚举序列化-如何处理VO中的枚举字段?
anyway,枚举是Java中表达有限状态的利器。使用枚举不仅可以增强类型安全,同时也会极大提升代码的可读性和可维护性。
在 Spring MVC 项目中,当使用 Jackson 序列化枚举类型时,默认行为是序列化枚举的 name() 值(即枚举常量的名称)。但在实际开发中,我们通常需要更灵活的控制。以下是详细分析和解决方案:
1. Jackson 默认枚举序列化行为
public enum EnterpriseAuthStatusEnum {
PENDING, // 序列化为 "PENDING"
APPROVED, // 序列化为 "APPROVED"
REJECTED // 序列化为 "REJECTED"
}
当 EnterpriseAuthVO { Long enterpriseId; EnterpriseAuthStatusEnum authStatus; } 对象被序列化为 JSON 时:
{
"enterpriseId": 12345,
"authStatus": "PENDING" // 默认输出枚举的 name() 值
}
2. 常见需求与解决方案
需求 1:返回枚举的说明文字(而非常量名)
@JsonFormat(shape = JsonFormat.Shape.OBJECT) // 关键注解
public enum EnterpriseAuthStatusEnum {
PENDING(0, "待审核"),
APPROVED(1, "已通过"),
REJECTED(2, "已拒绝");
private final int code;
private final String description;
// 构造方法、getter(必须添加 getter 方法)
}
序列化结果:
{
"enterpriseId": 12345,
"authStatus": {
"code": 0,
"description": "待审核"
}
}
需求 2:返回自定义值(如 code)
public enum EnterpriseAuthStatusEnum {
PENDING(0),
APPROVED(1),
REJECTED(2);
private final int code;
EnterpriseAuthStatusEnum(int code) {
this.code = code;
}
@JsonValue // 关键注解:标记作为序列化的值
public int getCode() {
return code;
}
}
序列化结果:
{
"enterpriseId": 12345,
"authStatus": 0 // 直接输出 code 值
}
需求 3:根据不同场景返回不同值
public enum EnterpriseAuthStatusEnum {
PENDING(0, "pending"),
APPROVED(1, "approved"),
REJECTED(2, "rejected");
private final int code;
private final String text;
EnterpriseAuthStatusEnum(int code, String text) {
this.code = code;
this.text = text;
}
// 自定义序列化器
@JsonComponent
public static class Serializer extends StdSerializer<EnterpriseAuthStatusEnum> {
public Serializer() {
super(EnterpriseAuthStatusEnum.class);
}
@Override
public void serialize(
EnterpriseAuthStatusEnum value,
JsonGenerator gen,
SerializerProvider provider
) throws IOException {
// 根据业务需求选择输出字段
gen.writeString(value.text);
// 或 gen.writeNumber(value.code);
}
}
}
3. 全局配置方案(改变所有枚举行为)
在 application.yml 中配置:
spring:
jackson:
serialization:
WRITE_ENUMS_USING_TO_STRING: true # 使用 toString() 而非 name()
或通过 Java 配置:
@Configuration
public class JacksonConfig {
@Bean
public Jackson2ObjectMapperBuilderCustomizer enumCustomizer() {
return builder -> {
// 方案1: 使用 toString()
builder.featuresToEnable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);
// 方案2: 使用索引值
// builder.featuresToEnable(SerializationFeature.WRITE_ENUMS_USING_INDEX);
};
}
}
4. 最佳实践建议:返回带说明的完整对象(推荐)
@Data
public class EnumDTO {
private String name;
private int code;
private String description;
}
// 在VO中转换
public class EnterpriseAuthVO {
private Long enterpriseId;
@JsonIgnore // 隐藏原始枚举
private EnterpriseAuthStatusEnum authStatus;
@ApiModelProperty("客户开户状态")
public EnumDTO getauthStatusInfo() {
if (authStatus == null) return null;
return new EnumDTO(
authStatus.name(),
authStatus.getCode(),
authStatus.getDescription()
);
}
}
序列化结果:
{
"enterpriseId": 12345,
"authStatusInfo": {
"name": "PENDING",
"code": 0,
"description": "待审核"
}
}
5. 完整示例代码
// 枚举定义
@JsonFormat(shape = JsonFormat.Shape.OBJECT)
public enum EnterpriseAuthStatusEnum {
PENDING(0, "待审核"),
APPROVED(1, "已通过"),
REJECTED(2, "已拒绝");
private final int code;
private final String description;
// 构造方法、getter
}
// VO对象
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class EnterpriseAuthVO implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty("企业id")
private Long enterpriseId;
@ApiModelProperty("客户开户状态")
private EnterpriseAuthStatusEnum authStatus;
}
// 控制器
@RestController
public class EnterpriseController {
@GetMapping("/auth/status")
public EnterpriseAuthVO getAuthStatus() {
return new EnterpriseAuthVO()
.setEnterpriseId(10001L)
.setAuthStatus(EnterpriseAuthStatusEnum.PENDING);
}
}
请求响应:
{
"enterpriseId": 10001,
"authStatus": {
"code": 0,
"description": "待审核"
}
}
关键总结
| 需求场景 | 实现方案 | 序列化结果示例 |
|---|---|---|
| 默认行为 | 无配置 | "PENDING" |
| 返回数字编码 | @JsonValue + getCode() |
0 |
| 返回完整对象 | @JsonFormat(shape = OBJECT) |
{"code":0, "desc":"待审核"} |
| 全局使用 toString() | WRITE_ENUMS_USING_TO_STRING |
"待审核" |
| 自定义序列化逻辑 | 实现 JsonSerializer |
任意自定义格式 |
生产环境推荐:使用 @JsonFormat(shape = OBJECT) 返回完整枚举信息,前端可直接展示 description 字段,同时保留 code 用于逻辑判断。
当看到一些不好的代码时,会发现我还算优秀;当看到优秀的代码时,也才意识到持续学习的重要!--buguge
本文来自博客园,转载请注明原文链接:https://www.cnblogs.com/buguge/p/18931089
浙公网安备 33010602011771号