项目场景:
今天写接口的时候,本想着用 swagger 去测试,然后看到控制台打印了很多错误日志,大概就是关于 AbstractSerializableParameter
这个类转换时出现了错误,虽然不影响功能,但是看着还是很糟心,在网上相关博客之后,自己总结了一下,避免下次再犯
问题描述
@PostMapping(value = "/save-bill-info")
@ApiOperation(value = "保存财务账单信息")
public ResponseBean saveBillInfo(
@ApiParam(required = true, value = "商品名称") @RequestParam(required = true) String productTitle,
@ApiParam(required = true, value = "商品价格") @RequestParam(required = true) BigDecimal price,
@ApiParam(required = false, value = "商品数量") @RequestParam(required = false) Integer number,
@ApiParam(required = false, value = "平均人数") @RequestParam(required = false) Integer average,
@ApiParam(required = true, value = "支付金额") @RequestParam(required = true) BigDecimal payMoney,
@ApiParam(required = true, value = "支付类型") @RequestParam(required = true) PayTypeEnum payType,
@ApiParam(required = true, value = "账单类型") @RequestParam(required = true) BillTypeEnum type,
@ApiParam(required = true, value = "消费日期") @RequestParam(required = true) String day,
@ApiParam(required = false, value = "财务标签") @RequestParam(required = false) List<Integer> labels,
@ApiParam(required = false, value = "发送方主键") @RequestParam(required = false) Integer senderId,
@ApiParam(required = false, value = "接收方主键") @RequestParam(required = false) Integer receiverId
) {
financeService.saveBillInfo(productTitle,price,number,average,payMoney,payType,type,day,labels,senderId,receiverId);
return ResponseBean.success();
}
以上就是我今天定义的接口,启动项目之后打开 swagger 文档
后面还有很多错误日志,我就只截取了一部分。
原因分析:
点到 AbstractSerializableParameter
源码里面去看,源码如下:
...
protected String example;
protected String type;
...
@JsonProperty("x-example")
public Object getExample() {
if (this.example == null) {
return null;
} else {
try {
if ("integer".equals(this.type)) {
return Long.valueOf(this.example);
}
if ("number".equals(this.type)) {
return Double.valueOf(this.example);
}
if ("boolean".equals(this.type) && ("true".equalsIgnoreCase(this.example) || "false".equalsIgnoreCase(this.defaultValue))) {
return Boolean.valueOf(this.example);
}
} catch (NumberFormatException var2) {
LOGGER.warn(String.format("Illegal DefaultValue %s for parameter type %s", this.defaultValue, this.type), var2);
}
return this.example;
}
}
从源码上来看就是拿 type
去解析对应的 example
,如果没有解析成功的话就会报 Illegal DefaultValue %s for parameter type %s
这种错误,而且只会校验这三种类型的数据
、那么这个 type
和 example
是怎么来的呢?
其实在我们通过 swagger 定义接口的时候就已经给出了这些信息,比如之前接口定义的 price
参数:
@ApiParam(required = true, value = "商品价格") @RequestParam(required = true) BigDecimal price,
这个参数其实已经确定了该参数的 type
是 number
类型,example
没有定义,取默认的就是 ""
,可以点击 @ApiParam
注解看到
@Target({ElementType.PARAMETER, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ApiParam {
...
String example() default "";
...
}
也就是说如果我们没有给 integer
、number
、boolean
这三种类型的参数设置 example
的话,程序走到 AbstractSerializableParameter
这个类,就会拿 ""
进行后续的 Long.valueOf(this.example)
、Double.valueOf(this.example)
、Boolean.valueOf(this.example)
操作,导致解析出现异常,从而报错。
同理使用 @ApiModelProperty
定义请求体,只要为 integer
、number
、boolean
这三种类型,不设置 example
也一样会报错,比如以下 enableFlag
字段:
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@ApiModel(value = "查询菜单列表")
public class QueryMenuListReq extends PageInfo {
@ApiModelProperty("关键字")
private String keyWord;
@ApiModelProperty("是否禁用")
private Boolean enableFlag;
}
@ApiModelProperty
源码:
@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ApiModelProperty {
...
String example() default "";
...
}
解决方案:
如果知道它为什么会报错了之后,那就很容易解决了,比如之前定义的接口,我给 Integer
、BigDecimal
、Boolean
所定义的参数设置个 example
不就行了嘛
/save-bill-info
接口中的 Integer
、BigDecimal
类型字段设置 example
值
@PostMapping(value = "/save-bill-info")
@ApiOperation(value = "保存财务账单信息")
public ResponseBean saveBillInfo(
@ApiParam(required = true, value = "商品名称") @RequestParam(required = true) String productTitle,
@ApiParam(required = true, value = "商品价格",example = "0") @RequestParam(required = true) BigDecimal price,
@ApiParam(required = false, value = "商品数量",example = "0") @RequestParam(required = false) Integer number,
@ApiParam(required = false, value = "平均人数",example = "0") @RequestParam(required = false) Integer average,
@ApiParam(required = true, value = "支付金额",example = "0") @RequestParam(required = true) BigDecimal payMoney,
@ApiParam(required = true, value = "支付类型") @RequestParam(required = true) PayTypeEnum payType,
@ApiParam(required = true, value = "账单类型") @RequestParam(required = true) BillTypeEnum type,
@ApiParam(required = true, value = "消费日期") @RequestParam(required = true) String day,
@ApiParam(required = false, value = "财务标签") @RequestParam(required = false) List<Integer> labels,
@ApiParam(required = false, value = "发送方主键",example = "0") @RequestParam(required = false) Integer senderId,
@ApiParam(required = false, value = "接收方主键",example = "0") @RequestParam(required = false) Integer receiverId) {
financeService.saveBillInfo(productTitle,price,number,average,payMoney,payType,type,day,labels,senderId,receiverId);
return ResponseBean.success();
}
QueryMenuListReq
请求体 enableFlag
字段设置 example
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@ApiModel(value = "查询菜单列表")
public class QueryMenuListReq extends PageInfo {
@ApiModelProperty("关键字")
private String keyWord;
@ApiModelProperty(value = "是否禁用",example = "false")
private Boolean enableFlag;
}
启动项目,开启 swagger 就不会报错了
现在虽然错是不会报了,但是这个其实是 swagger-models:1.5.20
的 bug
,在 1.5.21版本已经修改了这个问题
,所以为了永久解决这个问题就只能直接去修改 pom
文件中的依赖了, 通过替换依赖解决
之前的依赖:
<!-- swagger -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-spring-web</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
修改后的依赖:
<!-- swagger -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-spring-web</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
<exclusions>
<exclusion>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
<version>1.6.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
现在不用去设置什么 example
也不会报错了。
参考博客:
关于Swagger会报AbstractSerializableParameter类的异常问题
解决swagger的类型转换报错问题