我正在编写一个REST端点,它需要同时支持application / x-www-form-urlencoded和application / json作为请求体。我已经做了以下配置,
@RequestMapping(method = RequestMethod.POST, produces = { MediaType.APPLICATION_JSON_VALUE }, consumes = {
MediaType.APPLICATION_FORM_URLENCODED_VALUE, MediaType.APPLICATION_JSON_VALUE }, path = Constants.ACCESS_TOKEN_V1_ENDPOINT)
public OAuth2Authorization createAccessTokenPost(
@RequestBody(required = false) MultiValueMap<String, String> paramMap) { ..
虽然它单独支持application / x-www-form-urlencoded或application / json(当我从consumes = {}注释掉一个内容类型时),但它不同时支持两者。有什么想法吗?
答案 0 :(得分:1)
根据我的调查结果,spring不支持内容类型“application/x-www-form-urlencoded
”,“application/json
”和“application/xml
”。
我认为原因:Spring通过解析并将它们注入标有@RequestBody
spring注释的java pojo来处理JSON和XML类型。但是,x-www-form-urlencoded
必须注入标有MultiValueMap<>
的{{1}}对象。标记为@RequestBody
的两种不同的Java类型将不会同时支持,因为spring可能不知道注入有效负载的位置。
工作解决方案:
“@RequestBody
”可以支持,因为它在API中。也就是说,可以使用@RequestBody注释将其注入spring application/x-www-form-urlencoded
。
为了在同一方法上支持JSON和XML,我们可以利用servlet规范和构建在它们之上的spring类来提取有效负载作为流。
示例代码:
MultiValueMap<>
注意事项使用此方法可以支持任何自定义数据类型/标记/格式。 Spring的import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.util.MultiValueMap;
// usual REST service class
@Autowired
private MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter;
@Autowired
private Jaxb2RootElementHttpMessageConverter jaxb2RootElementHttpMessageConverter;
public ResponseEntity<Object> authorizationRequestPost(HttpServletResponse response, HttpServletRequest request,@RequestBody(required = false) MultiValueMap<String, String> parameters) {
// this MultiValueMap<String,String> will contain key value pairs of "application/x-www-form-urlencoded" parameters.
// payload object to be populated
Authorization authorization = null;
HttpInputMessage inputMessage = new ServletServerHttpRequest(request) {
@Override
public InputStream getBody() throws IOException {
return request.getInputStream();
}
};
if (request.getContentType().equals(MediaType.APPLICATION_JSON_VALUE)) {
authorization = (Authorization) mappingJackson2HttpMessageConverter.read(Authorization.class, inputMessage);
}
else if (request.getContentType().equals(MediaType.APPLICATION_XML_VALUE)) {
authorization = (Authorization)jaxb2RootElementHttpMessageConverter.read(Authorization.class, inputMessage);
}
else{
// extract values from MultiValueMap<String,String> and populate Authorization
}
// remaining method instructions
}
可以扩展为编写解析逻辑。
另一种可能的方法可以是一个执行相同逻辑的AOP样式解决方案:通过从org.springframework.http.converter.HttpMessageConverter<>
输入流中提取有效负载来解析有效负载并注入到有效负载对象中。
第三种方法将编写一个用于执行逻辑的过滤器。
答案 1 :(得分:0)
使用单个Spring控制器方法无法同时处理application/json
和application/x-www-form-urlencoded
请求。
Spring通过ServletRequest.getParameter(java.lang.String)获得了application/x-www-form-urlencoded
数据,文件说:
对于HTTP servlet,参数包含在查询字符串或发布的表单数据中。
如果参数数据是在请求正文中发送的(例如HTTP POST请求中发生的情况),则直接通过getInputStream()或getReader()读取正文会干扰此方法的执行。
因此,如果您的方法参数用@RequestBody
注释,Spring将读取请求正文并将其解析为方法参数对象。但是application/x-www-form-urlencoded
导致Spring通过调用ServletRequest.getParameter(java.lang.String)来填充参数对象。
答案 2 :(得分:0)
要做到这一点,即使您不使用ProductTags
注释MultiValueMap
,上面的answer也不起作用,它将始终检查@RequestBody
其余情况解决为contentType==MediaType.APPLICATION_FORM_URLENCODED_VALUE
。