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
基础才是编程人员应该深入研究的问题,比如:
1)List/Set/Map内部组成原理|区别
2)mysql索引存储结构&如何调优/b-tree特点、计算复杂度及影响复杂度的因素。。。
3)JVM运行组成与原理及调优
4)Java类加载器运行原理
5)Java中GC过程原理|使用的回收算法原理
6)Redis中hash一致性实现及与hash其他区别
7)Java多线程、线程池开发、管理Lock与Synchroined区别
8)Spring IOC/AOP 原理;加载过程的。。。
【+加关注】。