在开发过程中,我们对外提供的服务可以抽成两大块,一块是不变的,即我们抽象出来的请求头,一块是根据不同的接口而不同的请求体。
package com.bijian.study.dto; public class BaseRequest<T> { private CommonReqHeaderDTO commonReqHeaderDTO; private T data; public CommonReqHeaderDTO getCommonReqHeaderDTO() { return commonReqHeaderDTO; } public void setCommonReqHeaderDTO(CommonReqHeaderDTO commonReqHeaderDTO) { this.commonReqHeaderDTO = commonReqHeaderDTO; } public T getData() { return data; } public void setData(T data) { this.data = data; } }
而我们在测试过程发现一个小小的问题,如果对方传的json串都是字符串类型的,则会原封不动地映射到我们的java对象上。但如果对方有传非字符串的值,如25.60,则到映射到对象的值则为25.6,由于我们是面向公网的服务,会对请求过来的数据进行验签,如请求方验签的是25.60,而我们验签的值为成了25.6,则会验签不通过。所以,我特意分析了一下。记录如下:
1.不管是数值还是非数值的的,让请求方统一按字符串传。
2.在我们的系统,每一个请求体都定义一个对象,如这里的BatchOper.java
@ResponseBody @RequestMapping(value="/addUser", method=RequestMethod.POST) public BaseResponse addUser(HttpServletRequest request, HttpServletResponse response, @RequestBody BaseRequest<BatchOper> baseRequest) { logger.info("第三方请求,请求参数:{}", JsonUtil.toFullJson(baseRequest)); return null; }
package com.bijian.study.dto; import java.math.BigDecimal; import com.bijian.study.mapper.CustomBigDecimalSerialize; import com.bijian.study.mapper.CustomDoubleSerialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; public class BatchOper { //批次交易订单号 private String batchOrderId; //汇总笔数 private int totalCount; //汇总金额 private BigDecimal totalAmount; private Double totalAmount2; private BigDecimal totalAmount3; //文件名称 private String fileName; public String getBatchOrderId() { return batchOrderId; } public void setBatchOrderId(String batchOrderId) { this.batchOrderId = batchOrderId; } public int getTotalCount() { return totalCount; } public void setTotalCount(int totalCount) { this.totalCount = totalCount; } public BigDecimal getTotalAmount() { return totalAmount; } public void setTotalAmount(BigDecimal totalAmount) { this.totalAmount = totalAmount; } public Double getTotalAmount2() { return totalAmount2; } public void setTotalAmount2(Double totalAmount2) { this.totalAmount2 = totalAmount2; } public BigDecimal getTotalAmount3() { return totalAmount3; } public void setTotalAmount3(BigDecimal totalAmount3) { this.totalAmount3 = totalAmount3; } public String getFileName() { return fileName; } public void setFileName(String fileName) { this.fileName = fileName; } }
请求的JSON串如下:
{"commonReqHeaderDTO":{"headReqDate":"20180208","headReqTime":"01241401978"},"data":{"batchOrderId":"0417775230004","totalCount":5,"totalAmount":"252.60","totalAmount2":25.80,"totalAmount3":125.50,"fileName":"/20180417/cs-gdgthzz041702.txt"}}
输出日志如下:
21:13:14.044 INFO com.bijian.study.controller.UserController 67 addUser - 第三方请求,请求参数:{"commonReqHeaderDTO":{"headReqDate":"20180208","headReqTime":"01241401978"},"data":{"batchOrderId":"0417775230004","totalCount":5,"totalAmount":252.60,"totalAmount2":25.8,"totalAmount3":125.50,"fileName":"/20180417/cs-gdgthzz041702.txt"}}
我们不难发现,BigDecimal和String类型的末尾的0还是保留,即正常映射了,但Double类型的则丢掉了最后的0。
因此,方法二就是每一个请求体都定义一个映射对象,数字类型的可以为String,也可以是BigDecimal。
但,对于Double,我们是否还有其它方法呢?这时,我们不难想到SpringMVC的自定义转换器。
package com.bijian.study.mapper; import java.io.IOException; import java.text.DecimalFormat; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; public class CustomDoubleSerialize extends JsonSerializer<Double> { private DecimalFormat df = new DecimalFormat("##.0000"); @Override public void serialize(Double value, JsonGenerator gen, SerializerProvider serializers) throws IOException, JsonProcessingException { if(value != null) { //gen.writeString(df.format(value));//转换成字符串 gen.writeNumber(df.format(value)); } } }
package com.bijian.study.mapper; import java.io.IOException; import java.math.BigDecimal; import java.text.DecimalFormat; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; public class CustomBigDecimalSerialize extends JsonSerializer<BigDecimal> { private DecimalFormat df = new DecimalFormat("##.000"); @Override public void serialize(BigDecimal value, JsonGenerator gen, SerializerProvider serializers) throws IOException, JsonProcessingException { if(value != null) { //gen.writeString(df.format(value)); gen.writeNumber(df.format(value)); } } }
然后需要给需要转换的属性上面加上注解,如下在totalAmount、totalAmount2分别加上自定义转换器。
package com.bijian.study.dto; import java.math.BigDecimal; import com.bijian.study.mapper.CustomBigDecimalSerialize; import com.bijian.study.mapper.CustomDoubleSerialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; public class BatchOper { //批次交易订单号 private String batchOrderId; //汇总笔数 private int totalCount; //汇总金额 @JsonSerialize(using=CustomBigDecimalSerialize.class) private BigDecimal totalAmount; @JsonSerialize(using=CustomDoubleSerialize.class) private Double totalAmount2; private BigDecimal totalAmount3; //文件名称 private String fileName; public String getBatchOrderId() { return batchOrderId; } public void setBatchOrderId(String batchOrderId) { this.batchOrderId = batchOrderId; } public int getTotalCount() { return totalCount; } public void setTotalCount(int totalCount) { this.totalCount = totalCount; } public BigDecimal getTotalAmount() { return totalAmount; } public void setTotalAmount(BigDecimal totalAmount) { this.totalAmount = totalAmount; } public Double getTotalAmount2() { return totalAmount2; } public void setTotalAmount2(Double totalAmount2) { this.totalAmount2 = totalAmount2; } public BigDecimal getTotalAmount3() { return totalAmount3; } public void setTotalAmount3(BigDecimal totalAmount3) { this.totalAmount3 = totalAmount3; } public String getFileName() { return fileName; } public void setFileName(String fileName) { this.fileName = fileName; } }
这时,我们同样用上面的json串请求,输出日志如下:
21:20:28.512 INFO com.bijian.study.controller.UserController 67 addUser - 第三方请求,请求参数:{"commonReqHeaderDTO":{"headReqDate":"20180208","headReqTime":"01241401978"},"data":{"batchOrderId":"0417775230004","totalCount":5,"totalAmount":252.600,"totalAmount2":25.8000,"totalAmount3":125.50,"fileName":"/20180417/cs-gdgthzz041702.txt"}}
但,这种方式在我们的项目中还是不可取,因为不可能把所有请求体都定义出来,这样就达不到我们原来特意做成抽象类的目的了。最后我的方法是在验签前,对JSON串中的有小数点的数字类型的小数做补0处理。方法如下所示:
jsonStr = jsonStr.replaceAll("\\.0,", ".00,"); jsonStr = jsonStr.replaceAll("\\.0}", ".00}"); jsonStr = jsonStr.replaceAll("\\.1,", ".10,"); jsonStr = jsonStr.replaceAll("\\.1}", ".10}"); jsonStr = jsonStr.replaceAll("\\.2,", ".20,"); jsonStr = jsonStr.replaceAll("\\.2}", ".20}"); jsonStr = jsonStr.replaceAll("\\.3,", ".30,"); jsonStr = jsonStr.replaceAll("\\.3}", ".30}"); jsonStr = jsonStr.replaceAll("\\.4,", ".40,"); jsonStr = jsonStr.replaceAll("\\.4}", ".40}"); jsonStr = jsonStr.replaceAll("\\.5,", ".50,"); jsonStr = jsonStr.replaceAll("\\.5}", ".50}"); jsonStr = jsonStr.replaceAll("\\.6,", ".60,"); jsonStr = jsonStr.replaceAll("\\.6}", ".60}"); jsonStr = jsonStr.replaceAll("\\.7,", ".70,"); jsonStr = jsonStr.replaceAll("\\.7}", ".70}"); jsonStr = jsonStr.replaceAll("\\.8,", ".80,"); jsonStr = jsonStr.replaceAll("\\.8}", ".80}"); jsonStr = jsonStr.replaceAll("\\.9,", ".90,"); jsonStr = jsonStr.replaceAll("\\.9}", ".90}");
参考文章:https://blog.csdn.net/u013220534/article/details/79697554
测试的完整代码可到http://bijian1013.iteye.com/blog/2419741下载。