我有两个Spring MVC控制器方法。两者都在请求正文中接收相同的数据(格式为HTLM POST
形式:version=3&name=product1&id=2
),但是一个方法处理PUT
个请求,另一个处理DELETE
:
@RequestMapping(value = "ajax/products/{id}", method = RequestMethod.PUT)
@ResponseBody
public MyResponse updateProduct(Product product, @PathVariable("id") int productId) {
//...
}
@RequestMapping(value = "ajax/products/{id}", method = RequestMethod.DELETE)
@ResponseBody
public MyResponse updateProduct(Product product, @PathVariable("id") int productId) {
//...
}
在第一种方法中,product
参数的所有字段都已正确初始化。在第二个中,仅初始化id
字段。其他字段为null
或0.(id
可能由于id
路径变量而初始化。)
我可以看到HttpServletRequest
对象包含请求正文中所有字段的值(version=3&name=product1&id=2
)。它们只是没有映射到product
参数的字段。
如何使第二种方法有效?
我还尝试使用@RequestParam
带注释的参数。在处理PUT
请求的方法中,它可以工作。在DELETE
方法中,我得到一个例外:org.springframework.web.bind.MissingServletRequestParameterException: Required String parameter 'version' is not present
。
我需要在DELETE
个请求的主体中传递数据,因为数据包含用于乐观锁定的行版本。
答案 0 :(得分:31)
问题不是Spring
问题,而是Tomcat
问题。
默认情况下,当HTTP方法为POST
时,Tomcat将仅解析表单样式中的参数(至少对于我检查的版本7.0.54,但它可能对所有人都相同) Tomcat 7版本。)
为了能够处理DELETE方法,您需要设置Tomcat连接器的parseBodyMethods
属性。连接器配置在server.xml
。
您更新的连接器很可能如下所示:
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"
parseBodyMethods="POST,PUT,DELETE"
URIEncoding="UTF-8" />
Here是用于配置Tomcat连接器的文档页面。
一旦你设置了Tomcat来解析参数,Spring就可以正常工作了(尽管在你的情况下你可能需要从控制器方法中删除@RequestBody
)
答案 1 :(得分:3)
您可以尝试将注释@RequestBody添加到Product参数中。
但是如果你只需要传递版本信息,那么使用请求参数更合适。
所以在你的删除方法@RequestParam(&#34; version&#34;)int版本中添加一个新参数,并在调用delete方法时传递一个查询参数,如..ajax/products/123?version=1
正如您所说,请求param在删除时不适合您,您可以发布您使用的确切网址和方法签名吗?
答案 2 :(得分:1)
Spring boot 1.5。*
@Bean
public TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory() {
return new TomcatEmbeddedServletContainerFactory(){
@Override
protected void customizeConnector(Connector connector) {
super.customizeConnector(connector);
connector.setParseBodyMethods("POST,PUT,DELETE");
}
};
}
答案 3 :(得分:1)
对于Spring Boot 2.0 +:
@Bean
public TomcatServletWebServerFactory containerFactory() {
return new TomcatServletWebServerFactory() {
@Override
protected void customizeConnector(Connector connector) {
super.customizeConnector(connector);
connector.setParseBodyMethods("POST,PUT,DELETE");
}
};
}
答案 4 :(得分:0)
在DELETE请求的正文中传递数据
@Component 公共类CustomiseTomcat实现WebServerFactoryCustomizer {
@Override
public void customize(TomcatServletWebServerFactory factory) {
factory.addConnectorCustomizers( new TomcatConnectorCustomizer() {
@Override
public void customize(Connector connector) {
connector.setParseBodyMethods("POST,PUT,DELETE");
}
});
}
}