在Spring 3.2中使用AJAX的PUT方法不起作用

Tin*_*iny 5 jquery spring json put jackson

我正在尝试使用以下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);
            }
    });
}
Run Code Online (Sandbox Code Playgroud)

它试图在Spring中调用以下方法.

@RequestMapping(value=("ajax/UpdateUserRole"), method=RequestMethod.PUT)
public @ResponseBody void updateUserRole(@RequestParam(value=("id")) String id)
{
    System.out.println("id = "+id);
}
Run Code Online (Sandbox Code Playgroud)

FireFox响应以下错误.

HTTP状态405 - 不支持请求方法"GET"

类型状态报告

消息请求方法'GET'不受支持

description对于请求的资源,不允许使用指定的HTTP方法(不支持请求方法'GET').

Apache Tomcat/6.0.26

它适用于GETPOST方法和JSON(与Jackson-2.1.1)也适用于应用程序的其他部分.


如果需要查看dispatcher-servlet.xml文件,完整内容如下.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"

       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"

       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
       http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd">

    <context:component-scan base-package="controller" />
    <context:component-scan base-package="validatorbeans" />

    <mvc:annotation-driven content-negotiation-manager="contentNegotiationManager" >
        <mvc:message-converters register-defaults="false">
        <bean id="jacksonMessageConverter" p:supportedMediaTypes="application/json" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
    </mvc:message-converters>
    </mvc:annotation-driven>

    <bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
        <property name="favorPathExtension" value="false" />
        <property name="favorParameter" value="false" />
        <property name="ignoreAcceptHeader" value="false" />
        <property name="mediaTypes" >
            <value>
                atom=application/atom+xml
                html=text/html
                json=application/json
                *=*/*
            </value>
        </property>
    </bean>

    <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />
    <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/>
    <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
        <property name="exceptionMappings">
            <props>
                <prop key="org.springframework.web.multipart.MaxUploadSizeExceededException">
                    fileUploadingFailure
                </prop>
            </props>
        </property>
    </bean>
    <bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
            <props>
                <prop key="index.htm">indexController</prop>
            </props>
        </property>
    </bean>

    <bean id="viewResolver"
          class="org.springframework.web.servlet.view.InternalResourceViewResolver"
          p:prefix="/WEB-INF/jsp/"
          p:suffix=".jsp" />

    <bean name="indexController"
          class="org.springframework.web.servlet.mvc.ParameterizableViewController"
          p:viewName="index" />
</beans>
Run Code Online (Sandbox Code Playgroud)

如何在Spring 3.2 之外制作HTTP方法GETPOST在其中工作?


编辑:

根据以下评论,以下是我的整个web.xml文件.

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            /WEB-INF/applicationContext.xml
            /WEB-INF/spring-security.xml
        </param-value>
    </context-param>
    <filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>



    <filter>
        <filter-name>NoCacheFilter</filter-name>
        <filter-class>filter.NoCacheFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>NoCacheFilter</filter-name>
        <url-pattern>/admin_side/*</url-pattern>
    </filter-mapping>


    <filter>
        <filter-name>FileUploadFilter</filter-name>
        <filter-class>com.ckfinder.connector.FileUploadFilter</filter-class>
        <init-param>
            <param-name>sessionCookieName</param-name>
            <param-value>JSESSIONID</param-value>
        </init-param>
        <init-param>
            <param-name>sessionParameterName</param-name>
            <param-value>jsessionid</param-value>
        </init-param>
    </filter>


    <filter-mapping>
        <filter-name>FileUploadFilter</filter-name>
        <url-pattern>
                    /ckfinder/core/connector/java/connector.java
     </url-pattern>
    </filter-mapping>

    <filter>
        <filter-name>multipartFilter</filter-name>
        <filter-class>org.springframework.web.multipart.support.MultipartFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>multipartFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>


    <filter>
        <filter-name>httpMethodFilter</filter-name>
        <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>httpMethodFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>


    <filter>
        <filter-name>openSessionInViewFilter</filter-name>
        <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
        <init-param>
            <param-name>singleSession</param-name>
            <param-value>false</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>openSessionInViewFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>





    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <listener>
        <description>ServletContextListener</description>
        <listener-class>listener.UnregisterDatabaseDrivers</listener-class>
    </listener>
    <servlet>
        <servlet-name>ConnectorServlet</servlet-name>
        <servlet-class>com.ckfinder.connector.ConnectorServlet</servlet-class>
        <init-param>
            <param-name>XMLConfig</param-name>
            <param-value>/WEB-INF/config.xml</param-value>
        </init-param>
        <init-param>
            <param-name>debug</param-name>
            <param-value>false</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>ConnectorServlet</servlet-name>
        <url-pattern>
                    /ckfinder/core/connector/java/connector.java
            </url-pattern>
    </servlet-mapping>


     <listener>
        <listener-class>
          org.springframework.security.web.session.HttpSessionEventPublisher
        </listener-class>
      </listener>




    <error-page>
        <description>Missing login</description>
        <error-code>401</error-code>
        <location>/WEB-INF/jsp/admin_side/ErrorPage.jsp</location>
    </error-page>

    <error-page>
        <description>Forbidden directory listing</description>
        <error-code>403</error-code>
        <location>/WEB-INF/jsp/admin_side/ErrorPage.jsp</location>
    </error-page>

    <error-page>
        <description>Missing page</description>
        <error-code>404</error-code>
        <location>/WEB-INF/jsp/admin_side/ErrorPage.jsp</location>
    </error-page>

    <error-page>
        <description>Uncaught exception</description>
        <error-code>500</error-code>
        <location>/WEB-INF/jsp/admin_side/ErrorPage.jsp</location>
    </error-page>

    <error-page>
        <description>Unsupported servlet method</description>
        <error-code>503</error-code>
        <location>/WEB-INF/jsp/admin_side/ErrorPage.jsp</location>
    </error-page>



    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>2</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>*.htm</url-pattern>
    </servlet-mapping>
    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
    <welcome-file-list>
        <welcome-file>redirect.jsp</welcome-file>
    </welcome-file-list>
</web-app>
Run Code Online (Sandbox Code Playgroud)

Arj*_*jan 2

除非仅使用路径参数,否则处理常规 HTTP PUT 需要更多工作。

Spring 3.1 开始,HttpPutFormContentFilter可用于@RequestParamapplication/x-www-form-urlencoded数据工作:

过滤器,使表单编码数据ServletRequest.getParameter*()在 HTTP PUT 请求期间通过一系列方法可用。

Servlet 规范要求表单数据可用于 HTTP POST,但不可用于 HTTP PUT 请求。此过滤器拦截内容类型为“ application/x-www-form-urlencoded”的 HTTP PUT 请求,从请求正文中读取表单编码内容,并包装 ServletRequest 以使表单数据可用作请求参数,就像 HTTP POST 请求一样。

但是:此过滤器消耗请求的输入流,使其无法用于转换器FormHttpMessageConverter,例如 ,如用于@RequestBody MultiValueMap<String, String>HttpEntity<MultiValueMap<String, String>>。因此,在应用程序中配置application/x-www-form-urlencoded上述过滤器后,在调用使用也需要原始PUT 数据的其他转换器的方法时,您将收到“IOException:流已关闭”。


或者,可以使用或手动完成所有操作:@RequestBodyHttpEntity<?>

@RequestMapping(value="ajax/UpdateUserRole", method=RequestMethod.PUT,
    produces = MediaType.TEXT_PLAIN_VALUE)
public @ResponseBody String updateUserRole(
    @RequestBody final MultiValueMap<String, String> data,
    final HttpServletResponse response) {
  Map<String, String> 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;
}
Run Code Online (Sandbox Code Playgroud)

另请参阅使用 的示例WebDataBinder,或使用:

public ResponseEntity<String> updateUserRole(
    final HttpEntity<MultiValueMap<String, String>> entity) {
  Map<String, String> params = entity.getBody().toSingleValueMap();
  String id = params.get("id");
  ...
Run Code Online (Sandbox Code Playgroud)

请注意,对于测试,使用MockMvc mockMvc.perform(put(url).param(name, value))实际上也可以处理问题中的代码,即使它在 servlet 容器中会失败。但是 MockMvc 没有在这样的 servlet 容器中运行,因此有点欺骗你。

MockMvc.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=" + ...)
Run Code Online (Sandbox Code Playgroud)

为了能够简单地使用.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<String, String[]> params = request.getParameterMap();
        if (params != null) {
          StringBuilder content = new StringBuilder();
          for (Entry<String, String[]> 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<String, String[]>());
          request.setContent(content.toString().getBytes());
          request.setContentType(MediaType.APPLICATION_FORM_URLENCODED_VALUE);
        }
      }
      return request;
    }
  };
}
Run Code Online (Sandbox Code Playgroud)

...然后使用.with(convertParameters())旁边.param(name, value)

mockMvc.perform(put(url)
    .with(convertParameters())
    .param("id", id).param("a", a).param("b", b) ...)
Run Code Online (Sandbox Code Playgroud)

鉴于上述所有内容,简单地使用HttpPutFormContentFilter数据application/x-www-form-urlencoded确实让生活变得更轻松。

当浏览器不发送application/x-www-form-urlencoded数据,而是发送 JSON 等内容时,尝试映射到MultiValueMap将产生 415 不支持的媒体类型。相反,请使用类似@RequestBody MyDTO dataHttpEntity<MyDTO> entity使用 Jackson JSON 在 Spring MVC 中解析 JSON中所解释的内容。