SpringMVC(五):HiddenHttpMethodFilter实现REST请求

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>

 

112654_2RJL_2296021.png

112749_3VyK_2296021.png

 

我们看下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

转载于:https://my.oschina.net/LevelCoder/blog/914487

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值