SpringMVC(四):@RequestMapping结合org.springframework.web.filter.HiddenHttpMethodFilter实现REST请求

1)REST具体表现:

--- /account/1  HTTP GET       获取id=1的account

--- /account/1  HTTP DELETE 删除id=1的account

--- /aacount/1  HTTP PUT        更新id=1的account

--- /account      HTTP POST     新增account

2)SpringMVC中如何实现REST?

众所周知,浏览器form表单只支持GET与POST请求,而DELETE、PUT等method并不支持。Spring3.0增加了一个过滤器,可以将这些请求转化为标准的http方法,使得支持GET、POST、PUT及DELETE请求。

这个过滤器就是:org.springframework.web.filter.HiddenHttpMethodFilter

 1 package org.springframework.web.filter;
 2 
 3 import java.io.IOException;
 4 import java.util.Locale;
 5 import javax.servlet.FilterChain;
 6 import javax.servlet.ServletException;
 7 import javax.servlet.http.HttpServletRequest;
 8 import javax.servlet.http.HttpServletRequestWrapper;
 9 import javax.servlet.http.HttpServletResponse;
10 
11 import org.springframework.util.Assert;
12 import org.springframework.util.StringUtils;
13 import org.springframework.web.util.WebUtils;
14 
15 /**
16  * {@link javax.servlet.Filter} that converts posted method parameters into HTTP methods,
17  * retrievable via {@link HttpServletRequest#getMethod()}. Since browsers currently only
18  * support GET and POST, a common technique - used by the Prototype library, for instance -
19  * is to use a normal POST with an additional hidden form field ({@code _method})
20  * to pass the "real" HTTP method along. This filter reads that parameter and changes
21  * the {@link HttpServletRequestWrapper#getMethod()} return value accordingly.
22  *
23  * <p>The name of the request parameter defaults to {@code _method}, but can be
24  * adapted via the {@link #setMethodParam(String) methodParam} property.
25  *
26  * <p><b>NOTE: This filter needs to run after multipart processing in case of a multipart
27  * POST request, due to its inherent need for checking a POST body parameter.</b>
28  * So typically, put a Spring {@link org.springframework.web.multipart.support.MultipartFilter}
29  * <i>before</i> this HiddenHttpMethodFilter in your {@code web.xml} filter chain.
30  *
31  * @author Arjen Poutsma
32  * @author Juergen Hoeller
33  * @since 3.0
34  */
35 public class HiddenHttpMethodFilter extends OncePerRequestFilter {
36 
37     /** Default method parameter: {@code _method} */
38     public static final String DEFAULT_METHOD_PARAM = "_method";
39 
40     private String methodParam = DEFAULT_METHOD_PARAM;
41 
42 
43     /**
44      * Set the parameter name to look for HTTP methods.
45      * @see #DEFAULT_METHOD_PARAM
46      */
47     public void setMethodParam(String methodParam) {
48         Assert.hasText(methodParam, "'methodParam' must not be empty");
49         this.methodParam = methodParam;
50     }
51 
52     @Override
53     protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
54             throws ServletException, IOException {
55 
56         HttpServletRequest requestToUse = request;
57 
58         if ("POST".equals(request.getMethod()) && request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) == null) {
59             String paramValue = request.getParameter(this.methodParam);
60             if (StringUtils.hasLength(paramValue)) {
61                 requestToUse = new HttpMethodRequestWrapper(request, paramValue);
62             }
63         }
64 
65         filterChain.doFilter(requestToUse, response);
66     }
67 
68 
69     /**
70      * Simple {@link HttpServletRequest} wrapper that returns the supplied method for
71      * {@link HttpServletRequest#getMethod()}.
72      */
73     private static class HttpMethodRequestWrapper extends HttpServletRequestWrapper {
74 
75         private final String method;
76 
77         public HttpMethodRequestWrapper(HttpServletRequest request, String method) {
78             super(request);
79             this.method = method.toUpperCase(Locale.ENGLISH);
80         }
81 
82         @Override
83         public String getMethod() {
84             return this.method;
85         }
86     }
87 
88 }

从这个filter代码中可以得知,该filter是通过POST方式提交表单,该表单中包含一个名称为_method的隐藏域,该隐藏域的值用来判定将要转化的请求方式。所谓的转化请求方式,就是在该filter中重新生成了一个新的、标准化的请求。

3)如何使用到springmvc项目中?

步骤一:在web.xml中添加filter配置:

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

步骤二:在HelloWord.java中添加get/post/put/delete方法:

 1 package com.dx.springlearn.handlers;
 2 
 3 import org.springframework.stereotype.Controller;
 4 import org.springframework.web.bind.annotation.PathVariable;
 5 import org.springframework.web.bind.annotation.RequestMapping;
 6 import org.springframework.web.bind.annotation.RequestMethod;
 7 
 8 @Controller
 9 @RequestMapping("class_requestmapping")
10 public class HelloWord {
11     private static String SUCCESS = "success";
12 
13     @RequestMapping(value = "/accountDelete/{id}", method = RequestMethod.DELETE)
14     public String accountDelete(@PathVariable("id") Integer id) {
15         System.out.println("test rest DELETE,account id:" + id);
16         return SUCCESS;
17     }
18 
19     @RequestMapping(value = "/accountPut/{id}", method = RequestMethod.PUT)
20     public String accountPut(@PathVariable("id") Integer id) {
21         System.out.println("test rest PUT,account id:" + id);
22         return SUCCESS;
23     }
24 
25     @RequestMapping(value = "/account", method = RequestMethod.POST)
26     public String account() {
27         System.out.println("test rest POST");
28         return SUCCESS;
29     }
30 
31     @RequestMapping(value = "/account/{id}", method = RequestMethod.GET)
32     public String account(@PathVariable("id") Integer id) {
33         System.out.println("test rest GET,account id:" + id);
34         return SUCCESS;
35     }
36 }

步骤三:在index.jsp中添加get/post/put/delete方法请求的html脚本:

    <!-- delete提交 -->    
    <form id="form_testRestMethod_DELETE" name="form_testRestMethod_DELETE" method="POST"
        action="class_requestmapping/accountDelete/2">
        <input type="hidden" name="_method" value="DELETE" />
        <button name="submit" id="submit">test rest DELETE</button>
    </form>
    <br>
    <!-- put提交 -->    
    <form id="form_testRestMethod_PUT" name="form_testRestMethod_PUT" method="POST"
        action="class_requestmapping/accountPut/2">
        <input type="hidden" name="_method" value="PUT" />
        <button name="submit" id="submit">test rest PUT</button>
    </form>
    <br>
    <!-- post提交 -->    
    <form id="form_testRestMethod_POST" name="form_testRestMethod_POST"
        method="POST" action="class_requestmapping/account">
        <button name="submit" id="submit">test rest POST</button>
    </form>
    <br>
    <!-- get提交 -->    
    <a href="class_requestmapping/account/1">test rest GET</a>
    <br>

步骤四:测试打印结果为:

test rest GET,account id:1
test rest POST
test rest PUT,account id:2
test rest DELETE,account id:2

 

posted @ 2018-01-04 17:07  cctext  阅读(856)  评论(0编辑  收藏  举报