在java web我的项目中返回一个费用,费用的类型应用了BigDecimal,而后就间接依照公司框架封装了返回值,后果就报错了。
我的项目应用的框架是SpringBoot + swagger + lombok,代码如下:
申请接口:
@ApiOperation(value = "查问费用测试2")@PostMapping(path = "/getFee2/{fee}")public ResultVo<BigDecimal> getFee2(@PathVariable String fee) { BigDecimal f = StringUtils.isEmpty(fee) ? null : new BigDecimal(fee); return ResultVo.ok(f);}
返回后果的封装类
@ApiModel("返回信息包装类")@Datapublic class ResultVo<T> { public static final int OK_CODE = 0; public static final int ERROR_CODE = 1; private static final String DEFAULT_MESSAGE = "OK"; private static final ResultVo<Void> OK_VO; private String code; private String errorMsg; private T content; static { OK_VO = new ResultVo<>(OK_CODE, DEFAULT_MESSAGE); } public ResultVo(String code, String errorMsg, T content) { this.code = code; this.errorMsg = errorMsg; this.content = content; } public static <T> ResultVo<T> ok(T content) { return new ResultVo<>(OK_CODE, null, content); } public static <T> ResultVo<T> error(T content) { return new ResultVo<>(ERROR_CODE, null, content); } public static ResultVo<Void> ok() { return OK_VO; } public ResultVo() { }}
接口申请链接:
curl -X POST "http://localhost:8080/shop/getFee2/10" -H "accept: */*"
申请的返回后果是:
谬误的大略意思就是BigDecimal类型的数据在序列化时出了问题。
解决方案一:
在yml中增加如下配置
spring: jackson: serialization: FAIL_ON_EMPTY_BEANS: false
或者在代码中增加
@Bean public ObjectMapper objectMapper(){ return new ObjectMapper().disable(SerializationFeature.FAIL_ON_EMPTY_BEANS) }
后果就是申请接口不再报错,然而返回的数据的值变成了null。这个后果不合乎我的预期。
解决方案二:
把BigDecimal类型的数据转换成其余的数据类型返回,比如说String,代码如下:
@ApiOperation(value = "查问费用测试2")@PostMapping(path = "/getFee2/{fee}")public ResultVo<String> getFee2(@PathVariable String fee) { BigDecimal f = StringUtils.isEmpty(fee) ? null : new BigDecimal(fee); return ResultVo.ok(Objects.nonNull(f) ? f.toString() : null);}
返回后果如下:
{ "code": "0", "errorMsg": null, "content": "10.00"}
看起来是解决了问题,然而没有方法自定义数据格式,比如说如果数字是整数的话,我并不想要小数点以及小数点前面的数字。
解决方案三:
增加BigDecimal的序列化办法,增加内容如下:
@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.FIELD)@JacksonAnnotationsInside@JsonSerialize(using = BigDecimalSerializer.class)@JsonDeserialize(using = BigDecimalDeSerializer.class)public @interface BigDecimalFormat { String value() default "#.000";}
@JsonComponentpublic class BigDecimalDeSerializer extends JsonDeserializer<BigDecimal> { @Override public BigDecimal deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException { return new BigDecimal(jsonParser.getText()); }}
@JsonComponentpublic class BigDecimalSerializer extends JsonSerializer<BigDecimal> implements ContextualSerializer { // 默认格式化计划, 我的项目中增加了 BigDecimal 的格式化配置后, private String format = "#.00"; @Override public JsonSerializer<?> createContextual(SerializerProvider serializerProvider, BeanProperty beanProperty) throws JsonMappingException { if(beanProperty !=null ){ if(Objects.equals(beanProperty.getType().getRawClass(),BigDecimal.class)){ BigDecimalFormat bigDecimalFormat = beanProperty.getAnnotation((BigDecimalFormat.class)); if(bigDecimalFormat == null){ bigDecimalFormat = beanProperty.getContextAnnotation(BigDecimalFormat.class); } BigDecimalSerializer bigDecimalSerializer = new BigDecimalSerializer(); if(bigDecimalFormat != null){ bigDecimalSerializer.format = bigDecimalFormat.value(); } return bigDecimalSerializer; } return serializerProvider.findValueSerializer(beanProperty.getType(),beanProperty); } return serializerProvider.findNullValueSerializer(beanProperty); } @Override public void serialize(BigDecimal bigDecimal, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { jsonGenerator.writeString(new DecimalFormat(format).format(bigDecimal)); }}
应用形式如下:
把返回后果费用放到对象中,在费用字段上增加序列化注解,代码如下:
@Datapublic class GetFeeRspVo { @ApiModelProperty(name = "费用") @BigDecimalFormat("#.##") private BigDecimal fee; public GetFeeRspVo() { } public GetFeeRspVo(BigDecimal fee) { this.fee = fee; }}
申请接口返回后果如下:
{ "code": "0", "errorMsg": null, "content": { "fee": "10" }}
看起来是返回后果满足了咱们的须要
解决方案四:
是否不包装类呢?钻研了计划三的序列化形式,找了外围的序列化代码
jsonGenerator.writeString(new DecimalFormat(format).format(bigDecimal));
依据这行代码咱们能够本人对BigDecimal数据手动序列化,残缺代码如下:
@ApiOperation(value = "查问费用测试1")@PostMapping(path = "/getFee1/{fee}")public ResultVo<String> getFee1(@PathVariable String fee) { BigDecimal f = StringUtils.isEmpty(fee) ? null : new BigDecimal(fee); return ResultVo.ok(new DecimalFormat("#.##").format(f));}
返回后果如下:
{ "code": "0", "errorMsg": null, "content": "10"}
看起来也能满足要求。
总结:计划三、计划四都是可能满足要求的。其中计划三更通用一些,计划四代码更简洁一些。
参考文章:
https://blog.csdn.net/read225...
https://blog.csdn.net/qq_4135...