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.测试,成功。发现反序列化配置中的字段转换正常,尝试删除反序列化注解,接口功能正常。