在開發過程中,我們對外提供的服務可以抽成兩大塊,一塊是不變的,即我們抽象出來的請求頭,一塊是根據不同的接口而不同的請求體。
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下載。