request參數獲取,參數校驗,參數處理


需求:

1.post接口,需要在過濾器中進行參數校驗,校驗通過之后再執行方法

2.原有代碼中使用x-www-form-urlencoded傳參,新需求要使用json格式

3.原有代碼校驗過濾器使用ServletRequest.getParameter來獲取參數,並將其放入ThreadLocal<OpenapiRequest>常量中進行校驗

 

問題:

1.改用json傳參之后,再過濾器中無法通過ServletRequest.getParameter來獲取參數,所有參數為null,因此無法通過參數加密校驗

'使用流讀取參數,可以獲取參數'
            BufferedReader streamReader = new BufferedReader(new InputStreamReader(request.getInputStream(), "UTF-8"));
            StringBuilder responseStrBuilder = new StringBuilder();
            String inputStr;
            while ((inputStr = streamReader.readLine()) != null) {
                responseStrBuilder.append(inputStr);
            }
            String paramString = responseStrBuilder.toString();

2.參數校驗通過,但是方法接收參數出錯

Caused by: org.glassfish.hk2.api.MultiException: A MultiException has 7 exceptions.  They are:
1. java.lang.IllegalStateException: The @FormParam is utilized when the content type of the request entity is not application/x-www-form-urlencoded
2. java.lang.IllegalStateException: The @FormParam is utilized when the content type of the request entity is not application/x-www-form-urlencoded
3. java.lang.IllegalStateException: The @FormParam is utilized when the content type of the request entity is not application/x-www-form-urlencoded
4. java.lang.IllegalStateException: The @FormParam is utilized when the content type of the request entity is not application/x-www-form-urlencoded
5. java.lang.IllegalStateException: The @FormParam is utilized when the content type of the request entity is not application/x-www-form-urlencoded
6. java.lang.IllegalArgumentException: While attempting to resolve the dependencies of com.seari.ztxplatform.openapi.model.OpenapiRequest errors were found
7. java.lang.IllegalStateException: Unable to perform operation: resolve on com.seari.ztxplatform.openapi.model.OpenapiRequest

  解決方法:替換原方法的入參注解@BeanParam為@RequestBody

 3.入參中普通String字段接收成功,其中一個參數data在類中定義為String,但是傳參需要一個json對象,導致報錯

本次響應數據:"Can not deserialize instance of java.lang.String out of START_OBJECT token
at [Source: org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$UnCloseableInputStream@c507164; 
line: 5, column: 13] (through reference chain: com.seari.ztxplatform.openapi.model.OpenapiRequest[\"data\"])"

  此時可以在傳參時,將data參數按照字符串格式傳,而不是json格式,可以正常調用接口。樣式如

 

4.前端需要統一入參格式,不能單獨將data以String類型傳參,要求的傳參格式為

 

    解決方法增加一個反序列化工具

 

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import groovy.util.logging.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import java.io.IOException;

/**
 * 用來自定義openapiRequest中的data在反序列化時的類型
 *
 * @author liming
 * @since 2021/12/30 17:07
 */
@Component
@Slf4j
public class DataJsonDeserializer extends JsonDeserializer {
    private final Logger log = LoggerFactory.getLogger(ApiParameterFilter.class);

    @Override
    public String deserialize(JsonParser data, DeserializationContext ctxt)
            throws IOException, JsonProcessingException {


        if (ObjectUtils.isEmpty(data)) {
            return null;
        }
        String openapiData = data.toString();

        log.info((" ====> "
                + data.getText() + ",轉換后的結果 ====> " + openapiData));


        return openapiData;
    }
}

 

  然后再接收參數類的data字段的set方法上加上注解

    @JsonDeserialize(using = DataJsonDeserializer.class)
    public void setData(String data) {
        this.data = data;
    }

 

從stackoverflow看到一個類型的問題,當時答題人提到關於這個問題可以去看看jsonDeserializer相關內容,最后試了下確實可以。真的是一句話拯救了我一天的時間,感謝!

For deserializing a node that can be either a String or an Object, you could give a look to @JsonSerialize giving a custom JsonDeserializer

 

詳見  

https://stackoverflow.com/questions/54062469/cannot-deserialize-instance-of-java-lang-string-out-of-start-object-token

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

2022年1月4日更新

元旦過后再次測試,發現原來data里面的參數確實從json對象轉成String類型了,但是問題是接口獲得的參數中,data字段是一個json對象的內存地址,形如“com.fasterxml.jackson.core.json.UTF8StreamJsonParser@f71b6f6”,這個參數對接口來說根本無法使用。

此時的思路
1.反序列化注解的配置類中沒有正確獲取data參數,可能是沒有使用合適的api方法

  嘗試在   public class DataJsonDeserializer extends JsonDeserializer   類中使用其他獲取參數的方法,結果沒有找到api可以正常返回data里面原json數據。

  此時,嘗試在其他字段上加上    @JsonDeserialize(using = DataJsonDeserializer.class)    注解,觀察可能的幾個api方法的輸出,發現個別方法可以正常輸出所選參數字段中的數值。

  觀察data字段相應api輸出結果,發現getText()方法只輸出了data的json數據的一個  {  ,說明反序列化注解沒有正確獲取參數數據。判斷使用String類型接收json格式的數據,這種情況不能使用反序列化注解進行參數修改。

2.判斷接口獲取參數的方式可能跟攔截器中的方法類似    request.getParameter("data")    ,而攔截器通過參數流的方式讀取並保存了入參內容,但是參數在到達接口時沒有正常獲取。

  a.手動在獲取到參數之后,重新賦值給request的parameter,但是發現沒有setParameter方法。

  b.在繼承的  HttpServletRequestWrapper  子類中,增加一個Map用來存儲參數,重寫getParameter()方法,使參數獲取改為從當前類中的Map獲取

3.測試,成功。發現反序列化配置中的字段轉換正常,嘗試刪除反序列化注解,接口功能正常。


免責聲明!

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



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