HiddenHttpMethodFilter 主要针对HTTP的GET,PUT,POST,DELETE请求进行状态转化所实现REST风格
理解REST风格架构转化可参考博客:http://kb.cnblogs.com/page/186516/
配置文件:配置HiddenHttpMethodFilter过滤器
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id="WebApp_ID" version="3.0">
<!-- 配置 HiddenHttpMethodFilter过滤器 -->
<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>
<!-- 配置 springDispatcherServlet拦截器 -->
<servlet>
<servlet-name>springDispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 配置springDispatcherServlet 初始化参数,配置springmvc文件的位置和名称 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:springmvc.xml</param-value>
</init-param>
<!-- 配置 springDispatcherServlet在项目启动时就被创建 -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springDispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
控制器
package com.levelcoder.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
/**
*
* 描述:HiddenHttpMethodFilter过滤器
*
* 作者:LevelCoder
*
* 邮箱:LevelCoder@126.com
*
* 日期:2017年5月31日 上午10:32:05
*
* 版本:V1.0.0
*/
@Controller
public class HiddenHttpMethodFilterController {
/**
* REST GET请求模式
* @return
*/
@RequestMapping(value="/hiddenHttpMethodFilter/{id}",method=RequestMethod.GET)
public String get(@PathVariable("id") Integer id){
System.out.println("REST GET请求成功,请求参数="+id);
return "success";
}
/**
* REST POST请求模式
* @return
*/
@RequestMapping(value="/hiddenHttpMethodFilter",method=RequestMethod.POST)
public String post(){
System.out.println("REST POST请求成功");
return "success";
}
/**
* REST PUT请求模式
* @return
*/
@RequestMapping(value="/hiddenHttpMethodFilter/{id}",method=RequestMethod.PUT)
public String put(@PathVariable("id") Integer id){
System.out.println("REST PUT请求成功,请求参数="+id);
return "success";
}
/**
* REST DELETE请求模式
* @return
*/
@RequestMapping(value="/hiddenHttpMethodFilter/{id}",method=RequestMethod.DELETE)
public String delete(@PathVariable("id") Integer id){
System.out.println("REST DELETE请求成功,请求参数="+id);
return "success";
}
}
测试index页面
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<p>REST 请求模式</p>
<form action="hiddenHttpMethodFilter/1" method="get">
<input type="submit" value="GET请求"/>
</form>
<form action="hiddenHttpMethodFilter" method="post">
<input type="submit" value="POST请求"/>
</form>
<form action="hiddenHttpMethodFilter/1" method="post">
<input type="hidden" name="_method" value="PUT"/>
<input type="submit" value="PUT请求"/>
</form>
<form action="hiddenHttpMethodFilter/1" method="post">
<input type="hidden" name="_method" value="DELETE"/>
<input type="submit" value="DELETE请求"/>
</form>
</body>
</html>
我们看下HiddenHttpMethodFilter的运行原理
拿PUT请求作为解说案例
当点击PUT请求时执行OncePerRequestFilter下的doFilter方法
@Override
public final void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
if (!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)) {
throw new ServletException("OncePerRequestFilter just supports HTTP requests");
}
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
String alreadyFilteredAttributeName = getAlreadyFilteredAttributeName();
boolean hasAlreadyFilteredAttribute = request.getAttribute(alreadyFilteredAttributeName) != null;
if (hasAlreadyFilteredAttribute || skipDispatch(httpRequest) || shouldNotFilter(httpRequest)) {
// Proceed without invoking this filter...
filterChain.doFilter(request, response);
}
else {
// Do invoke this filter...
request.setAttribute(alreadyFilteredAttributeName, Boolean.TRUE);
try {
doFilterInternal(httpRequest, httpResponse, filterChain);
}
finally {
// Remove the "already filtered" request attribute for this request.
request.removeAttribute(alreadyFilteredAttributeName);
}
}
}
在doFilter方法中获取过滤器信息,并引用此Filter,然后执行doFilterInternal方法,
/**
* Same contract as for {@code doFilter}, but guaranteed to be
* just invoked once per request within a single request thread.
* See {@link #shouldNotFilterAsyncDispatch()} for details.
* <p>Provides HttpServletRequest and HttpServletResponse arguments instead of the
* default ServletRequest and ServletResponse ones.
*/
protected abstract void doFilterInternal(
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException;
因为HiddenHttpMethodFilter 继承 OncePerRequestFilter 所以在 HiddenHttpMethodFilter 中重写doFilterInternal方法
/** Default method parameter: {@code _method} */
public static final String DEFAULT_METHOD_PARAM = "_method";
private String methodParam = DEFAULT_METHOD_PARAM;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
String paramValue = request.getParameter(this.methodParam);
if ("POST".equals(request.getMethod()) && StringUtils.hasLength(paramValue)) {
String method = paramValue.toUpperCase(Locale.ENGLISH);
HttpServletRequest wrapper = new HttpMethodRequestWrapper(request, method);
filterChain.doFilter(wrapper, response);
}
else {
filterChain.doFilter(request, response);
}
}
由上可看到 this.methodParam为默认DEFAULT_METHOD_PARAM,而DEFAULT_METHOD_PARAM又赋值_method,也就是说当为POST请求,获取已_method为参数的时候进行判断,当请求方法为POST,且请求参数不为空,长度大于0的时候 执行 下面过滤方法
1.针对方法请求参数进行大写转换
2.针对请求方法进行HTTP请求封装 其中 HttpMethodRequestWrapper源码如下
/**
* Simple {@link HttpServletRequest} wrapper that returns the supplied method for
* {@link HttpServletRequest#getMethod()}.
*/
private static class HttpMethodRequestWrapper extends HttpServletRequestWrapper {
private final String method;
public HttpMethodRequestWrapper(HttpServletRequest request, String method) {
super(request);
this.method = method;
}
@Override
public String getMethod() {
return this.method;
}
}
3.执行过滤请求
执行完后进行过滤器引用移除
简单的@RequestMapping REST 请求模式就这样
demo地址: http://git.oschina.net/LevelCoder/demos