SpringMVC中json數據映射為java對象的坑


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

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下載。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM