今天使用ajax请求rest风格的put请求报错,最后查看源码才解决问题。
* 如果直接发送ajax=PUT形式的请求
* 封装的数据
* Blog
* [blogId=1, blogTitle=null, blogContentr=null]
问题:
* 请求体中有数据;
* 但是Blog对象封装不上,导致sql语句成为 update tbl_emp where blog_id = 20;
*
原因:
* Tomcat:
* 1、将请求体中的数据,封装一个map。
* 2、request.getParameter("blogTitle")就会从这个map中取值。
* 3、SpringMVC封装POJO对象的时候,会把POJO中每个属性的值,request.getParamter("blogTitle");
事件-AJAX发送PUT请求失败:
* PUT请求,请求体中的数据,request.getParameter("empName")拿不到
* Tomcat一看是PUT不会封装请求体中的数据为map,只有POST形式的请求才封装请求体为map
解决方案
1.直接发送ajax的put请求
* 我们要能支持直接发送PUT之类的请求还要封装请求体中的数据
* 1、配置上HttpPutFormContentFilter;
<filter>
<filter-name>HttpPutFormContentFilter</filter-name>
<filter-class>org.springframework.web.filter.HttpPutFormContentFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HttpPutFormContentFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
* 2、他的作用;将请求体中的数据解析包装成一个map。
* 3、request被重新包装,request.getParameter()被重写,就会从自己封装的map中取数据
---
2.直接在data后面加上——method=put
$.ajax({
data:"&_method=PUT"
})
HiddenHttpMethodFilter 可以将页面的表单提交post请求转换为指定的delete和 put请求
但是直接发送ajax的put请求
关于源码分析
在org.apache.catalina.connector.Request类中的
parseParameters()方法中拿到连接器,调用连接器的ispareseMethod()方法,判断是否为链接器中的method是否包含POST,如果是POST方式才会执行后续的解析内容。所以说直接ajax上写PUT解析不到。
加入 HttpPutFormContentFilter
重新包装请求中的数据,重写getParameter(),从自己封装map中数据
HttpPutFormContentFilter的
protected void doFilterInternal(final HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
//如果是PUT或者PATCH请求,
if (("PUT".equals(request.getMethod()) || "PATCH".equals(request.getMethod())) && isFormContentType(request)) {
//拿到数据,包装成HttpInputMessage
HttpInputMessage inputMessage = new ServletServerHttpRequest(request) {
@Override
public InputStream getBody() throws IOException {
return request.getInputStream();
}
};
//调用read()读取成MultiValueMap(Map)//将请求提中的对象转换成一个map
MultiValueMap<String, String> formParameters = formConverter.read(null, inputMessage);
//
HttpServletRequest wrapper = new HttpPutFormContentRequestWrapper(request, formParameters);
filterChain.doFilter(wrapper, response);
}
else {
filterChain.doFilter(request, response);
}
}
private static class HttpPutFormContentRequestWrapper extends HttpServletRequestWrapper {
private MultiValueMap<String, String> formParameters;
public HttpPutFormContentRequestWrapper(HttpServletRequest request, MultiValueMap<String, String> parameters) {
super(request);
this.formParameters = (parameters != null ? parameters : new LinkedMultiValueMap<String, String>());
}
//此处重写了getParameter()方法,获取参数时还从自己的map当中获取,
@Override
public String getParameter(String name) {
String queryStringValue = super.getParameter(name);
String formValue = this.formParameters.getFirst(name);
return (queryStringValue != null ? queryStringValue : formValue);
}