一.背景简述

  首先,我们都知道枚举实例有两个默认属性,name 和 ordinal,可通过 name()和ordinal()方法分别获得。其中 name 为枚举字面量(如 MALE,FEMALE),ordinal 为枚举实例默认次序(从0开始)

  《阿里巴巴Java开发手册》将接口中枚举的使用分为两类,即 接口参数和接口返回值,并规定: 接口参数可以使用枚举类型,但接口返回值不可以使用枚举类型(包括含枚举类型的POJO对象)。

Java中出现的任何元素,在Gosling的角度都会有背后的思考和逻辑(尽管并非绝对完美,但Java的顶层抽象已经是天才级了),比如:接口、抽象类、注解、和本文提到的枚举。枚举有好处,类型安全,清晰直接,还可以使用等号来判断,也可以用在switch中。它的劣势也是明显的,就是不要扩展。可是为什么在返回值和参数进行了区分呢,如果不兼容,那么两个都有问题,怎么允许参数可以有枚举。当时的考虑,如果参数也不能用,那么枚举几乎无用武之地了。参数输出,毕竟是本地决定的,你本地有的,传送过去,向前兼容是不会有问题的。但如果是接口返回,就比较恶心了,因为解析回来的这个枚举值,可能本地还没有,这时就会抛出序列化异常。

比如:你的本地枚举类,有一个天气Enum:SUNNY, RAINY, CLOUDY,如果根据天气计算心情的方法:guess(WeatcherEnum xx),传入这三个值都是可以的。返回值:Weather guess(参数),那么对方运算后,返回一个SNOWY,本地枚举里没有这个值,傻眼了

  当然,使用自定义字段 code 照样不能处理,对此,开发手册作者的回答如下

主要是从防止这种序列化异常角度来考虑,使用code至少不会出大乱子。而catch序列化异常,有点像catch(NullPointerException e)一样代码过度,因为它是可预检异常。

  接口传值也不建议使用Ordinal,因为枚举示例应该是无序的,ordinal提供的顺序是不可靠的。所以我们应该使用自定义的枚举字段。

  我们定义了一个枚举类,继承了两个接口拥有两个字段,如下:

  

public interface ValueEnum<T> {
T value();
} public interface DescriptionEnum {
String description();
} public enum Gender implements ValueEnum<Integer>,DescriptionEnum {
/**
* 性别男
*/
MALE(1,"男"),
/**
* 性别女
*/
FEMALE(2,"女"); private Integer value; private String description; Gender(Integer value,String description) {
this.value = value;
this.description = description;
} @Override
public String description() {
return description;
} @Override
public Integer value() {
return value;
} }

  有个使用Gender的pojo类User

@Data
public class User { private Long id; private String name; private Gender gender; private String email;
}

二. 使用枚举作为接口参数

  2.1 Spring 默认使用Bean接收枚举参数时支持 字面量,这也是我们常见的做法。

    如下:

@Data
public class UserCommand { private String name; private Gender gender; private String email;
}
@ApiOperation("添加用户")
@PostMapping("/users")
public User users(User command){
User user = new User();
BeanUtils.copyProperties(command,user);
return user;
}

  注意这种方式不支持枚举的ordinal值

  2.2 使用Json接收枚举参数

    Json数据都放在请求体中,后台使用注解@RequestBody+command bean接收(也可以从HttpServletRequest的getInputStream获取)

    

 @ApiOperation("添加用户")
@PostMapping("/users")
public User users(@RequestBody UserCommand userCommand) {
User user = new User();
BeanUtils.copyProperties(userCommand,user);
return user;
}

    这种方式支持字面量,ordinary  

  2.3 自定义@RequestBody 和@ResponseBody处理枚举参数

   2.3.1 单独使用@JsonValue

  

public enum Gender implements ValueEnum<Integer>,DescriptionEnum{
/**
* 性别男
*/
MALE(10,"男"),
/**
* 性别女
*/
FEMALE(20,"女"); private Integer value; private String description; Gender(Integer value,String description) {
this.value = value;
this.description = description;
} @Override
public String description() {
return description;
} @JsonValue
@Override
public Integer value() {
return value;
} }

  @JsonValue决定了序列化的字段,表明该枚举类型只能使用该字段值传值。它可标注在字段和getter方法上,推荐标注在getter方法上。因为标注在字段上,swagger参数列表只显示字面值,但实际不能使用字面值传值,这样会给使用该接口的开发人员造成误解。

  标注value字段上:

  

  标注在value方法上

  

  

  这种方案虽然简单,但是只能单独使用某个字段传值。

  2.3.2 使用@JsonValue+@JsonCreator,代码如下

public enum Gender implements ValueEnum<Integer>,DescriptionEnum{
/**
* 性别男
*/
MALE(10,"男"),
/**
* 性别女
*/
FEMALE(20,"女"); private Integer value; private String description; Gender(Integer value,String description) {
this.value = value;
this.description = description;
} @JsonValue
@Override
public String description() {
return description;
} @Override
public Integer value() {
return value;
} @JsonCreator
public static Gender create(String value){
try{
return Gender.valueOf(value);
}catch (IllegalArgumentException e){
for (Gender gender : Gender.values()) {
try {
if (gender.value.equals(Integer.parseInt(value))) {
return gender;
}
}catch (NumberFormatException n) {
if (gender.description.equals(value)) {
return gender;
}
}
}
throw new IllegalArgumentException("No element matches "+value);
} } }

  @JsonValue是可选的,标注在getter方法上或者字段上,但是标注字段上Swagger显示参数不起作用,它可决定枚举反序列化的字段。如下

  

  

  @JsonCreator 标注在静态方法上,表明使用该方法序列化和反序列化,方法内部是序列化的逻辑

  上面的示例代码可使用三种方式传值。枚举类型的字面值,value属性或description属性,。这种方案就比较灵活可以任意决定一个或多个字段传值

Spring mvc 接口枚举类型数据格式化处理的更多相关文章

  1. MVC中将枚举类型数据应用到下拉列表中的方法

    例如: public enum ItemTypes   {      Movie = 1,      Game = 2,      Book = 3   }    在MVC2.0中如何将以上枚举类型使 ...

  2. Spring的controller接受Date类型数据,接受枚举类型数据

    1. Controller接收Date类型的数据 核心使用@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") 来将传递过来的时间字符串 ...

  3. Mock测试你的Spring MVC接口

    1. 前言 在Java开发中接触的开发者大多数不太注重对接口的测试,结果在联调对接中出现各种问题.也有的使用Postman等工具进行测试,虽然在使用上没有什么问题,如果接口增加了权限测试起来就比较恶心 ...

  4. PAT IO-04 混合类型数据格式化输入(5)

    /* *PAT IO-04 混合类型数据格式化输入(5) *2015-08-01 作者:flx413 */ #include<stdio.h> int main() { int a; fl ...

  5. IO-04. 混合类型数据格式化输入

    /** *A4-IO-04. 混合类型数据格式化输入 *C语言实现 *测试已通过 */ #include "stdio.h" int main() { float m1,m2; i ...

  6. DELPHI中枚举类型数据的介绍和使用方法

    在看delphi程序的时候看到aa=(a,b,c,d);这样的东西,还以为是数组,同事说是函数,呵呵,当然这两个都不屑一击,原来这样式子是在声明并付值一个枚举类型的数据.下边写下来DELPHI中枚举类 ...

  7. 换一种方式编写 Spring MVC 接口

    1. 前言 通常我们编写 Spring MVC 接口的范式是这样的: @RestController @RequestMapping("/v1/userinfo") public ...

  8. Spring MVC基础知识整理➣数据校验与格式化

    概述 将view中Form的数据提交到后台之后,后台如何验证数据的有效性?在这里Spring MVC提供了相应的Hibernate类包(hibernate-validator-4.3.1.Final. ...

  9. spring mvc(4)处理模型数据

    处理模型数据 Spring MVC 提供了以下几种途径输出模型数据: – ModelAndView: 处理方法返回值类型为 ModelAndView时, 方法体即可通过该对象添加 模型数据 – Map ...

随机推荐

  1. 【OpenCV学习】计算两幅图像的重叠区域

    问题描述:已知两幅图像Image1和Image2,计算出两幅图像的重叠区域,并在Image1和Image2标识出重叠区域. 算法思想: 若两幅图像存在重叠区域,则进行图像匹配后,会得到一张完整的全景图 ...

  2. EditText控件设置只读

    android的文本框输入控件(EditText),有时需要设置控件为只读,最简单的方法就是在layout xml文件中设置EditText的android:editable属性值为false即可,但 ...

  3. 单反毁三代,kindle富一生

    盖kindle 面更香 人皆知有用之用,而莫知无用之用   一个存留记忆的地方:http://i-remember.fr/en   文章来源:刘俊涛的博客 欢迎关注,有问题一起学习欢迎留言.评论

  4. TurboCAD Pro for Mac(二维绘图和三维建模工具)破解版安装

    1.软件简介    TurboCAD Pro 是 macOS 系统上一款二维绘图和三维建模工具,具备强大的绘图和设计特性,加上强大的创建复杂的三维模型的工具,三维 OpenGL 的渲染,和超过 11, ...

  5. ajax请求中的6个全局事件

    //事件触发顺序ajaxStart,ajaxSend,ajaxSuccess或ajaxError,ajaxComplete,ajaxStop $(document).ajaxStart(functio ...

  6. js中$

    $符号在php中是表示变量的特征字符, 在js中它也有很多作用, 一般我们用来命名一个函数名称,获取id的1.首先可以用来表示变量, 比如变量 var s='asdsd'或var $s='asdasd ...

  7. ZigBee基础

    Zigbee技术 Zigbee由Zigbee联盟制定的无线网络协议,在IEEE 802.15.4标准的基础上设计,是一种自愈.安全和稳健的网状网协议,可扩展到更大范围内的数百个节点.主要用于距离短.功 ...

  8. Why you should use async tasks in .NET 4.5 and Entity Framework 6

    Improve response times and handle more users with parallel processing Building a web application usi ...

  9. Python内置类型——list

    list(列表)是Python内置的可变序列(Sequence)类型,list的对象的方法也都是就地(in-place)更改调用这些方法的列表对象, List的一些细节 可以直接为list的某个下标赋 ...

  10. Java SpringBoot中使用sqljdbc4注意事项 java.lang.ClassNotFoundException: com.microsoft.sqlserver.jdbc.SQLServerDriver

    因项目需要,需要在Java项目中访问 MSSQLServer 数据库,本地开发的时候,没有问题,可以正常链接数据库,通过Jenkins部署到服务器上时候,报数据库驱动未找到. java.lang.Cl ...