栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java > SpringBoot

Springboot系列之RestApi中获取枚举类属性的几种方式

SpringBoot 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Springboot系列之RestApi中获取枚举类属性的几种方式

前言

我们在日常开发中经常会遇到,实体类中的枚举属性,在通过@ResponseBody注解返回到前端后,默认被解析成了枚举对象的name值,当我们需要获取枚举类的详细属性时就会变得非常麻烦,今天给大家分享几种常用的获取枚举类属性的方式。

例子

我们先通过一个小例子讲解这个问题,首先我们要准备一个简单的接口,用于查询用户信息,用户实体中包含性别、用户类型和用户状态三种枚举属性,我们下面的例子中, 将会分别拿这三个枚举类进行测试。
代码如下:
用户实体User.java

@Data
public class User {
    private String username;
    private String site;
    private String[] git;
    private GenderEnum gender;
    private TypeEnum type;
    private StatusEnum status;
}

枚举类内容如下:
GenderEnum.java

public enum GenderEnum {
    MALE("男"),
    FAMALE("女");
    private String desc;

    GenderEnum(String desc) {
 this.desc = desc;
    }

    public String getDesc() {
 return desc;
    }
}

TypeEnum.java

public enum TypeEnum {
    ADMIN("管理员"),
    USER("普通用户");
    private String desc;

    TypeEnum(String desc) {
 this.desc = desc;
    }

    public String getDesc() {
 return desc;
    }
}

StatusEnum.java

public enum StatusEnum {
    INUSE("使用中"),
    UNUSED("未使用"),
    DISABLED("已禁用");

    private String desc;

    StatusEnum(String desc) {
 this.desc = desc;
    }

    public String getDesc() {
 return desc;
    }
}

Controller类RestApiController.java

@RestController
public class RestApiController {

    @RequestMapping("/users")
    public Object users() {
 List userList = new ArrayList<>();
 User user = null;
 for (int i = 0; i < 2; i++) {
     user = new User();
     user.setGender(i % 2 == 0 ? GenderEnum.MALE : GenderEnum.FAMALE);
     user.setType(i % 2 == 0 ? TypeEnum.ADMIN : TypeEnum.USER);
     user.setStatus(i % 2 == 0 ? StatusEnum.INUSE : StatusEnum.DISABLED);
     user.setUsername("user_" + i);
     user.setSite("https://www.zhyd.me");
     user.setGit(new String[]{"https://gitee.com/yadong.zhang", "https://github.com/zhangyd-c"});
     userList.add(user);
 }
 return userList;
    }
}

接口返回数据的原始内容如下:

[
  {
    "username": "user_0",
    "site": "https://www.zhyd.me",
    "git": [
      "https://gitee.com/yadong.zhang",
      "https://github.com/zhangyd-c"
    ],
    "gender": "MALE",
    "type": "ADMIN",
    "status": "INUSE",
  },
  {
    "username": "user_1",
    "site": "https://www.zhyd.me",
    "git": [
      "https://gitee.com/yadong.zhang",
      "https://github.com/zhangyd-c"
    ],
    "gender": "FAMALE",
    "type": "USER",
    "status": "DISABLED"
  }
]

从接口数据中可以清楚的看到,枚举类属性被解析成了字符串。接下来我们将分别通过几种方式,完成对枚举类属性的获取。

第一种:新增Get方法

这种方式,需要我们在User.java实体类中,为用户类型枚举属性添加对应的get方法:

@Data
public class User {
    private String username;
    private String site;
    private String[] git;
    private GenderEnum gender;
    private TypeEnum type;
    private StatusEnum status;

    public String getTypeEnumDesc() {
 return null == type ? null : type.getDesc();
    }
}

接口响应内容:

[
  {
    "username": "user_0",
    "site": "https://www.zhyd.me",
    "git": [
      "https://gitee.com/yadong.zhang",
      "https://github.com/zhangyd-c"
    ],
    "gender": "MALE",
    "type": "ADMIN",
    "status": "INUSE",
    "typeEnumDesc": "管理员"
  },
  {
    "username": "user_1",
    "site": "https://www.zhyd.me",
    "git": [
      "https://gitee.com/yadong.zhang",
      "https://github.com/zhangyd-c"
    ],
    "gender": "FAMALE",
    "type": "USER",
    "status": "DISABLED",
    "typeEnumDesc": "普通用户"
  }
]

这种方式的优缺点:

  • 优点
    • 简单,不需要集成其他代码
  • 缺点
    • 扩展性差,如果一个枚举类存在多个属性,那我们就要在业务bean中为每个枚举属性单独增加get方法,想想都觉得头疼。

一般用来应急

第二种:通过自定义FastJsonHttpMessageConverter完成对Enum的转换

注:本人开发环境的fastjson版本为1.2.37, 另外测试了1.2.34和1.2.52,其他版本可能有所差异

改进枚举类

本小节只以TypeEnum.java枚举类为例,重写枚举类的toString方法

TypeEnu.java

public enum TypeEnum {
    ADMIN("管理员"),
    USER("普通用户");
    private String desc;

    TypeEnum(String desc) {
 this.desc = desc;
    }

    public String getDesc() {
 return desc;
    }

    @Override
    public String toString() {
 return "{\"name\": \"" + this.name() + "\", \"desc\": \"" + this.getDesc() + "\"}";
    }
}
新增配置类
@Configuration
public class WebMvcConf implements WebMvcConfigurer {

    @Override
    public void extendMessageConverters(List> converters) {
 converters.forEach(System.out::println);
    }

    
    @Configuration
    @ConditionalOnClass({FastJsonHttpMessageConverter.class})
    @ConditionalOnProperty(
     name = {"spring.http.converters.preferred-json-mapper"},
     havingValue = "fastjson",
     matchIfMissing = true
    )
    public class FastJsonHttpMessageConvertersConfiguration {

 @Bean
 @ConditionalOnMissingBean({FastJsonHttpMessageConverter.class})
 public FastJsonHttpMessageConverter fastJsonHttpMessageConverter() {
     FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();

     FastJsonConfig fastJsonConfig = new FastJsonConfig();
     fastJsonConfig.setSerializerFeatures(
      SerializerFeature.PrettyFormat,
      SerializerFeature.WriteEnumUsingToString
     );

     converter.setFastJsonConfig(fastJsonConfig);
     return converter;
 }
    }
}

注:

  • @ConditionalOnClass表示当存在FastJsonHttpMessageConverter类时,才会加载该配置
  • @@ConditionalOnProperty表示当spring.http.converters.preferred-json-mapper配置项的值为fastjson时,才会加载该配置,并且即使没有(matchIfMissing)该property也会正常加载
  • @ConditionalOnMissingBean表示当没有注入FastJsonHttpMessageConverter类时,才会执行当前的注入操作

需要注意的是,一定要在SerializerFeature中添加SerializerFeature.WriteEnumUsingToString,表示在对枚举类序列化的时候,返回枚举类的toString()方法的值。关于SerializerFeature其他参数的说明,请参考https://blog.csdn.net/u010246789/article/details/52539576

重新访问接口,返回内容如下:

[
	{
		"gender":"MALE",
 "status": "INUSE",
		"git":["https://gitee.com/yadong.zhang","https://github.com/zhangyd-c"],
		"site":"https://www.zhyd.me",
		"type":"{"name": "ADMIN", "desc": "绠$悊鍛�"}",
		"typeEnumDesc":"绠$悊鍛�",
		"username":"user_0"
	},
	{
		"gender":"FAMALE",
 "status": "DISABLED",
		"git":["https://gitee.com/yadong.zhang","https://github.com/zhangyd-c"],
		"site":"https://www.zhyd.me",
		"type":"{"name": "USER", "desc": "鏅€氱敤鎴�"}",
		"typeEnumDesc":"鏅€氱敤鎴�",
		"username":"user_1"
	}
]

汉字全部乱码了,通过Debug发现,FastJsonHttpMessageConverter的supportedMediaTypes属性默认为* @Configuration @ConditionalOnClass({FastJsonHttpMessageConverter.class}) @ConditionalOnProperty( name = {"spring.http.converters.preferred-json-mapper"}, havingValue = "fastjson", matchIfMissing = true ) public class FastJsonHttpMessageConvertersConfiguration { @Bean @ConditionalOnMissingBean({FastJsonHttpMessageConverter.class}) public FastJsonHttpMessageConverter fastJsonHttpMessageConverter() { FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter(); FastJsonConfig fastJsonConfig = new FastJsonConfig(); fastJsonConfig.setSerializerFeatures( SerializerFeature.PrettyFormat, SerializerFeature.WriteEnumUsingToString ); List mediaTypes = new ArrayList<>(); mediaTypes.add(MediaType.APPLICATION_JSON_UTF8); converter.setSupportedMediaTypes(mediaTypes); ValueFilter valueFilter = (o, s, o1) -> { if (o1 instanceof Enum) { String str = String.valueOf(o1); if (isJson(str)) { o1 = JSONObject.parseObject(String.valueOf(o1), Map.class); } } return o1; }; fastJsonConfig.setSerializeFilters(valueFilter); converter.setFastJsonConfig(fastJsonConfig); return converter; } } }

响应数据如下:

[
  {
    "gender": "MALE",
    "status": "INUSE",
    "git": [
      "https://gitee.com/yadong.zhang",
      "https://github.com/zhangyd-c"
    ],
    "site": "https://www.zhyd.me",
    "type": {
      "name": "ADMIN",
      "desc": "管理员"
    },
    "typeEnumDesc": "管理员",
    "username": "user_0"
  },
  {
    "gender": "FAMALE",
    "status": "DISABLED",
    "git": [
      "https://gitee.com/yadong.zhang",
      "https://github.com/zhangyd-c"
    ],
    "site": "https://www.zhyd.me",
    "type": {
      "name": "USER",
      "desc": "普通用户"
    },
    "typeEnumDesc": "普通用户",
    "username": "user_1"
  }
]

这种方式的优缺点:

  • 优点
    • 不需要对业务bean进行定制化,减少不必要的代码冗余和耦合
    • 扩展性好,枚举类中可以自定义多个属性
  • 缺点
    • 代码量大,新增了一个配置类
    • 每个枚举类中都需要OverridetoString方法,对代码的维护造成一定的影响
第三种:使用fastjson的@JSONType注解

因为Springboot默认使用的jackson的Converter,而@JSONType是fastjson的注解,所以这种方式也是基于FastJsonHttpMessageConverter的。

我们以StatusEnum.java为例,演示该注解的用法

首先修改StatusEnum.java为以下内容:

@JSonType(serializeEnumAsJavaBean = true)
public enum StatusEnum {
    INUSE("使用中"),
    UNUSED("未使用"),
    DISABLED("已禁用");

    private String desc;

    StatusEnum(String desc) {
 this.desc = desc;
    }

    public String getDesc() {
 return desc;
    }

    public String getName() {
 return this.name();
    }
}

注:如果此处存在反序列化异常,请参考:https://github.com/alibaba/fastjson/issues/1452

响应结果:

[
  {
    "gender": "MALE",
    "git": [
      "https://gitee.com/yadong.zhang",
      "https://github.com/zhangyd-c"
    ],
    "site": "https://www.zhyd.me",
    "status": {
      "desc": "使用中",
      "name": "INUSE"
    },
    "type": {
      "name": "ADMIN",
      "desc": "管理员"
    },
    "typeEnumDesc": "管理员",
    "username": "user_0"
  },
  {
    "gender": "FAMALE",
    "git": [
      "https://gitee.com/yadong.zhang",
      "https://github.com/zhangyd-c"
    ],
    "site": "https://www.zhyd.me",
    "status": {
      "desc": "已禁用",
      "name": "DISABLED"
    },
    "type": {
      "name": "USER",
      "desc": "普通用户"
    },
    "typeEnumDesc": "普通用户",
    "username": "user_1"
  }
]

效果和第二步的一致。

这种方式的优缺点:

  • 优点
    • 不需要对业务bean进行定制化,减少不必要的代码冗余和耦合
    • 扩展性好,枚举类中可以自定义多个属性
    • 不用去定制toString方法
    • 使用注解配置枚举类,方便快捷
  • 缺点
    • 依赖FastJsonHttpMessageConverter,需要单独对HttpMessageConverter进行增强
第四种:使用jackson的@JsonFormat注解

这一步开始,我们先把第二种方案中添加的FastJsonHttpMessageConvertersConfiguration类注掉,这样能更清楚的对比效果。

我们修改GenderEnum类内容如下:

@JsonFormat(shape = JsonFormat.Shape.OBJECT)
public enum GenderEnum {
    MALE("男"),
    FAMALE("女");
    private String desc;

    GenderEnum(String desc) {
 this.desc = desc;
    }

    public String getDesc() {
 return desc;
    }
}

访问接口返回的数据结构如下:

[
  {
    "username": "user_0",
    "site": "https://www.zhyd.me",
    "git": [
      "https://gitee.com/yadong.zhang",
      "https://github.com/zhangyd-c"
    ],
    "gender": {
      "desc": "男"
    },
    "type": "ADMIN",
    "status": "INUSE",
    "typeEnumDesc": "管理员"
  },
  {
    "username": "user_1",
    "site": "https://www.zhyd.me",
    "git": [
      "https://gitee.com/yadong.zhang",
      "https://github.com/zhangyd-c"
    ],
    "gender": {
      "desc": "女"
    },
    "type": "USER",
    "status": "DISABLED",
    "typeEnumDesc": "普通用户"
  }
]

已经成功序列化了枚举,因为我们枚举类中只有一个getDesc方法,所以序列化出来的枚举内容,也只有这一个参数。当实际生产环境中的枚举类存在多个属性时,只需要分别加上getXxx方法即可。

这种方式的优缺点:

  • 优点
    • 不需要对业务bean进行定制化,减少不必要的代码冗余和耦合
    • 扩展性好,枚举类中可以自定义多个属性
    • 不用去定制toString方法
    • 使用注解配置枚举类,方便快捷
    • Jackson自带注解,不依赖自定义的HttpMessageConverter,减少代码量
  • 缺点
    • 暂无
测试中碰到的问题

作者在写测试用例的时候,因不小心,碰到过几个问题,在这儿记录一下,防止后面有朋友继续碰到。

  1. JSONType是fastjson的注解,JsonFormat是jackson的注解,在使用自定义的FastJsonHttpMessageConverter组件时,JsonFormat是不可用的,同理在禁用掉FastJsonHttpMessageConverter组件后,JSONType不可用
  2. 其他问题,多见于参考资料的链接
项目源码

https://github.com/zhangyd-c/springboot-learning/tree/master/springboot-enums

参考资料
  • https://www.jianshu.com/p/68a75c093023
  • https://blog.csdn.net/gottst0113/article/details/80978966
  • https://blog.csdn.net/u010246789/article/details/52539576
  • https://blog.csdn.net/mickjoust/article/details/51671060
  • https://blog.csdn.net/qq_41599820/article/details/86607029
  • https://blog.csdn.net/zhangfengaiCQ/article/details/82657926
  • https://github.com/alibaba/fastjson/issues/1452
其他开源作品
  • blog-hunter,一款简单好用并且支持多个平台的博客爬取工具
  • OneBlog,一个简洁美观、功能强大并且自适应的Java博客
  • JustAuth,史上最全的整合第三方登录的工具,目前已支持Github、Gitee、微博、钉钉、百度、Coding、腾讯云开发者平台、OSChina、支付宝、QQ、微信、淘宝、Google、Facebook、抖音、领英、小米、微软和今日头条等第三方平台的授权登录。Login, so easy!
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/234422.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号