在开发过程中,我们对外提供的服务可以抽成两大块,一块是不变的,即我们抽象出来的请求头,一块是根据不同的接口而不同的请求体。
packagecom.bijian.study.dto;public class BaseRequest{privateCommonReqHeaderDTO commonReqHeaderDTO;privateT data;publicCommonReqHeaderDTO getCommonReqHeaderDTO() {returncommonReqHeaderDTO;
}public voidsetCommonReqHeaderDTO(CommonReqHeaderDTO commonReqHeaderDTO) {this.commonReqHeaderDTO =commonReqHeaderDTO;
}publicT getData() {returndata;
}public voidsetData(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 BaseRequestbaseRequest) {
logger.info("第三方请求,请求参数:{}", JsonUtil.toFullJson(baseRequest));return null;
}
packagecom.bijian.study.dto;importjava.math.BigDecimal;importcom.bijian.study.mapper.CustomBigDecimalSerialize;importcom.bijian.study.mapper.CustomDoubleSerialize;importcom.fasterxml.jackson.databind.annotation.JsonSerialize;public classBatchOper {//批次交易订单号
privateString batchOrderId;//汇总笔数
private inttotalCount;//汇总金额
privateBigDecimal totalAmount;
privateDouble totalAmount2;privateBigDecimal totalAmount3;//文件名称
privateString fileName;publicString getBatchOrderId() {returnbatchOrderId;
}public voidsetBatchOrderId(String batchOrderId) {this.batchOrderId =batchOrderId;
}public intgetTotalCount() {returntotalCount;
}public void setTotalCount(inttotalCount) {this.totalCount =totalCount;
}publicBigDecimal getTotalAmount() {returntotalAmount;
}public voidsetTotalAmount(BigDecimal totalAmount) {this.totalAmount =totalAmount;
}publicDouble getTotalAmount2() {returntotalAmount2;
}public voidsetTotalAmount2(Double totalAmount2) {this.totalAmount2 =totalAmount2;
}publicBigDecimal getTotalAmount3() {returntotalAmount3;
}public voidsetTotalAmount3(BigDecimal totalAmount3) {this.totalAmount3 =totalAmount3;
}publicString getFileName() {returnfileName;
}public voidsetFileName(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的自定义转换器。
packagecom.bijian.study.mapper;importjava.io.IOException;importjava.text.DecimalFormat;importcom.fasterxml.jackson.core.JsonGenerator;importcom.fasterxml.jackson.core.JsonProcessingException;importcom.fasterxml.jackson.databind.JsonSerializer;importcom.fasterxml.jackson.databind.SerializerProvider;public class CustomDoubleSerialize extends JsonSerializer{private DecimalFormat df = new DecimalFormat("##.0000");
@Overridepublic voidserialize(Double value, JsonGenerator gen, SerializerProvider serializers)throwsIOException, JsonProcessingException {if(value != null) {//gen.writeString(df.format(value));//转换成字符串
gen.writeNumber(df.format(value));
}
}
}
packagecom.bijian.study.mapper;importjava.io.IOException;importjava.math.BigDecimal;importjava.text.DecimalFormat;importcom.fasterxml.jackson.core.JsonGenerator;importcom.fasterxml.jackson.core.JsonProcessingException;importcom.fasterxml.jackson.databind.JsonSerializer;importcom.fasterxml.jackson.databind.SerializerProvider;public class CustomBigDecimalSerialize extends JsonSerializer{private DecimalFormat df = new DecimalFormat("##.000");
@Overridepublic voidserialize(BigDecimal value, JsonGenerator gen, SerializerProvider serializers)throwsIOException, JsonProcessingException {if(value != null) {//gen.writeString(df.format(value));
gen.writeNumber(df.format(value));
}
}
}
然后需要给需要转换的属性上面加上注解,如下在totalAmount、totalAmount2分别加上自定义转换器。
packagecom.bijian.study.dto;importjava.math.BigDecimal;importcom.bijian.study.mapper.CustomBigDecimalSerialize;importcom.bijian.study.mapper.CustomDoubleSerialize;importcom.fasterxml.jackson.databind.annotation.JsonSerialize;public classBatchOper {//批次交易订单号
privateString batchOrderId;//汇总笔数
private inttotalCount;//汇总金额
@JsonSerialize(using=CustomBigDecimalSerialize.class)privateBigDecimal totalAmount;
@JsonSerialize(using=CustomDoubleSerialize.class)privateDouble totalAmount2;privateBigDecimal totalAmount3;//文件名称
privateString fileName;publicString getBatchOrderId() {returnbatchOrderId;
}public voidsetBatchOrderId(String batchOrderId) {this.batchOrderId =batchOrderId;
}public intgetTotalCount() {returntotalCount;
}public void setTotalCount(inttotalCount) {this.totalCount =totalCount;
}publicBigDecimal getTotalAmount() {returntotalAmount;
}public voidsetTotalAmount(BigDecimal totalAmount) {this.totalAmount =totalAmount;
}publicDouble getTotalAmount2() {returntotalAmount2;
}public voidsetTotalAmount2(Double totalAmount2) {this.totalAmount2 =totalAmount2;
}publicBigDecimal getTotalAmount3() {returntotalAmount3;
}public voidsetTotalAmount3(BigDecimal totalAmount3) {this.totalAmount3 =totalAmount3;
}publicString getFileName() {returnfileName;
}public voidsetFileName(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}");