在Spring 3.2中使用AJAX的PUT方法不起作用
我正在尝试使用以下jQuery 1.6通过AJAX在Spring( 3.2.0 )中调用一个方法。
function updateRoleEnabled(id) { $.ajax({ datatype:"json", type: "PUT", url: "/wagafashion/ajax/UpdateUserRole.htm", data: "id="+id+"&t="+new Date().getTime(), success: function(response) { }, error: function(e) { alert('Error: ' + e); } }); }
它试图在Spring中调用以下方法。
@RequestMapping(value=("ajax/UpdateUserRole"), method=RequestMethod.PUT) public @ResponseBody void updateUserRole(@RequestParam(value=("id")) String id) { System.out.println("id = "+id); }
FireFox响应以下错误。
HTTP状态405 – 不支持请求方法“GET”
类型状态报告
消息请求方法’GET’不受支持
description对于请求的资源,不允许使用指定的HTTP方法(不支持请求方法’GET’)。
Apache Tomcat / 6.0.26
它适用于GET
和POST
方法,JSON( 使用Jackson-2.1.1 )在应用程序的其他部分也可以正常工作。
如果需要查看dispatcher-servlet.xml
文件,则完整内容如下所示。
atom=application/atom+xml html=text/html json=application/json *=*/* fileUploadingFailure indexController
如何在Spring 3.2中使GET
和POST
以外的HTTP方法工作?
编辑:
根据以下注释,以下是我的整个web.xml
文件。
contextConfigLocation /WEB-INF/applicationContext.xml /WEB-INF/spring-security.xml springSecurityFilterChain org.springframework.web.filter.DelegatingFilterProxy springSecurityFilterChain /* NoCacheFilter filter.NoCacheFilter NoCacheFilter /admin_side/* FileUploadFilter com.ckfinder.connector.FileUploadFilter sessionCookieName JSESSIONID sessionParameterName jsessionid FileUploadFilter /ckfinder/core/connector/java/connector.java multipartFilter org.springframework.web.multipart.support.MultipartFilter multipartFilter /* httpMethodFilter org.springframework.web.filter.HiddenHttpMethodFilter httpMethodFilter /* openSessionInViewFilter org.springframework.orm.hibernate3.support.OpenSessionInViewFilter singleSession false openSessionInViewFilter /* org.springframework.web.context.ContextLoaderListener ServletContextListener listener.UnregisterDatabaseDrivers ConnectorServlet com.ckfinder.connector.ConnectorServlet XMLConfig /WEB-INF/config.xml debug false 1 ConnectorServlet /ckfinder/core/connector/java/connector.java org.springframework.security.web.session.HttpSessionEventPublisher Missing login 401 /WEB-INF/jsp/admin_side/ErrorPage.jsp Forbidden directory listing 403 /WEB-INF/jsp/admin_side/ErrorPage.jsp Missing page 404 /WEB-INF/jsp/admin_side/ErrorPage.jsp Uncaught exception 500 /WEB-INF/jsp/admin_side/ErrorPage.jsp Unsupported servlet method 503 /WEB-INF/jsp/admin_side/ErrorPage.jsp dispatcher org.springframework.web.servlet.DispatcherServlet 2 dispatcher *.htm 30 redirect.jsp
除非只使用路径参数,否则处理常规HTTP PUT需要更多工作。
从 Spring 3.1开始, HttpPutFormContentFilter
可用于使@RequestParam
适用于application/x-www-form-urlencoded
数据:
在HTTP PUT请求期间通过
ServletRequest.getParameter*()
系列方法使表单编码数据可用的filter。Servlet规范要求表单数据可用于HTTP POST,但不能用于HTTP PUT请求。 此filter拦截HTTP PUT请求,其中内容类型为“
application/x-www-form-urlencoded
”,从请求正文中读取表单编码内容,并包装ServletRequest以使表单数据可用作请求参数,就像它适用于HTTP POST请求。
但是:此filter使用请求的输入流,使其不能用于FormHttpMessageConverter
类的转换器,例如用于@RequestBody MultiValueMap
或HttpEntity
。 因此,一旦在应用程序中配置了上述filter,在调用使用其他转换器的方法时,您将获得“IOException:stream closed”,这些转换器也需要原始application/x-www-form-urlencoded
PUT数据。
或者,可以使用@RequestBody
或HttpEntity>
手动完成所有操作:
@RequestMapping(value="ajax/UpdateUserRole", method=RequestMethod.PUT, produces = MediaType.TEXT_PLAIN_VALUE) public @ResponseBody String updateUserRole( @RequestBody final MultiValueMap data, final HttpServletResponse response) { Map params = data.toSingleValueMap(); String id = params.get("id"); String a = params.get("a"); String b = params.get("b"); if(id == null || a == null || b == null) { response.setStatus(HttpServletResponse.SC_BAD_REQUEST); return null; } return "id = " + id; }
另请参阅使用WebDataBinder
的示例 ,或使用:
public ResponseEntity updateUserRole( final HttpEntity> entity) { Map params = entity.getBody().toSingleValueMap(); String id = params.get("id"); ...
请注意,对于测试,使用MockMvc的 mockMvc.perform(put(url).param(name, value))
实际上也可以使用代码forms的问题,即使它在servlet容器中会失败。 但是MockMvc并没有在这样的servlet容器中运行,因此有点愚弄你。
MockMvc的.param .param(name, value)
也适用于HttpPutFormContentFilter
。 但是当使用MockMvc测试@RequestBody
或HttpEntity>
,还需要手动创建任何application/x-www-form-urlencoded
PUT内容。 喜欢:
mockMvc.perform(put(url).content("id=" + URLEncoder.encode(id, "UTF-8") + "&a=" + URLEncoder.encode(a, "UTF-8") + "&b=" + ...)
为了能够简单地使用.param(name, value)
,就像GET和POST一样,可以定义:
public static RequestPostProcessor convertParameters() { return new RequestPostProcessor() { @Override public MockHttpServletRequest postProcessRequest( final MockHttpServletRequest request) { if ("PUT".equalsIgnoreCase(request.getMethod()) { Map params = request.getParameterMap(); if (params != null) { StringBuilder content = new StringBuilder(); for (Entry es : params.entrySet()) { for (String value : es.getValue()) { try { content.append(URLEncoder.encode(es.getKey(), "UTF-8")) .append("=") .append(URLEncoder.encode(value, "UTF-8")) .append("&"); } catch (UnsupportedEncodingException e) { throw new IllegalArgumentException("UTF-8 not supported"); } } } request.setParameters(new HashMap()); request.setContent(content.toString().getBytes()); request.setContentType(MediaType.APPLICATION_FORM_URLENCODED_VALUE); } } return request; } }; }
…然后在.with(convertParameters())
.param(name, value)
旁边使用.with(convertParameters())
.param(name, value)
:
mockMvc.perform(put(url) .with(convertParameters()) .param("id", id).param("a", a).param("b", b) ...)
鉴于以上所有,只需将HttpPutFormContentFilter
用于application/x-www-form-urlencoded
数据,就可以让生活更轻松。
当浏览器没有发送application/x-www-form-urlencoded
数据,但是诸如JSON之类的东西,那么尝试映射到MultiValueMap
将产生415 Unsupported Media Type。 相反,使用类似@RequestBody MyDTO data
或HttpEntity
如使用Jackson JSON在Spring MVC中解析JSON中所述 。