文档章节

SpringMVC(五):HiddenHttpMethodFilter实现REST请求

LevelCoder
 LevelCoder
发布于 2017/06/05 10:16
字数 939
阅读 4
收藏 0

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

© 著作权归作者所有

共有 人打赏支持
LevelCoder
粉丝 8
博文 92
码字总数 35498
作品 0
房山
高级程序员
springMVC笔记系列(7)——HiddenHttpMethodFilter过滤器

什么是REST?首先来段介绍吧。 REST: 即 Representational State Transfer。 (资源)表现层状态转化。 是目前最流行的一种互联网软件架构。它结构清晰、符合标准、易于理解、 扩展方便,所...

HappyBKs
2015/05/19
0
7
Spring MVC 入门指南(二):@RequestMapping用法详解

一、@RequestMapping 简介 在Spring MVC 中使用 @RequestMapping 来映射请求,也就是通过它来指定控制器可以处理哪些URL请求,相当于Servlet中在web.xml中配置 的映射作用一致。让我们先看一...

kolbe
2015/09/22
41.9K
6
SpringMVC ------HiddenHttpMethodFilter 过滤器

Spring3.0以后添加了HiddenHttpMethodFilter过滤器,来支持支持Rest 风格的URL请求。 REST url: — /order/1 HTTP GET :得到 id = 1 的order — /order/1 HTTP DELETE :删除 id = 1 的order......

Rickxue
2015/12/17
39
0
SpringMVC控制器接收不了PUT提交的参数的解决方案

这次改造了下框架,把控制器的API全部REST化,不做不知道,SpringMVC的REST有各种坑让你去跳,顺利绕过它们花了我不少时间,这次来提下SpringMVC的PUT提交参数为null的情况。 照常先贴出我的...

Big_BoBo
2014/01/10
0
1
学习SpringMVC——如何获取请求参数

  @RequestParam,你一定见过;@PathVariable,你肯定也知道;@QueryParam,你怎么会不晓得?!还有你熟悉的他(@CookieValue)!她(@ModelAndView)!它(@ModelAttribute)!没错,仅注解...

Java团长
01/13
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

HTTPS is easy

HTTPS is easy https://www.troyhunt.com/https-is-easy/ HTTPS is easy! In fact, it's so easy I decided to create 4 short videos around 5 minutes each to show people how to enable ......

openthings
26分钟前
0
0
bugList 2

用户端: 1. 上传文件时,当选择:彩色-A3-双面时,第二个图片有bug 应改为 和第一个图片的类型相同 2. 确认打印时,三个下拉选目前有bug 应改为:根据后台配置的商家,group by计算出不同城...

勇恒
29分钟前
2
0
keras cnn 网咯 mnist 分类

搭建貌似比tf是简单很多。。。。。 from keras.datasets import mnistfrom keras.utils import np_utilsfrom keras.models import Sequentialfrom keras.layers import Dense, Activat......

阿豪boy
31分钟前
0
0
解决 /var/run/nginx.pid failed

nginx: [error] open() "/var/run/nginx.pid" failed (2: No such file or directory) sudo nginx -c /etc/nginx/nginx.conf nginx -s reload...

驛路梨花醉美
33分钟前
0
0
nginx负载均衡-ssl原理-生成ssl密钥对-nginx配置ssl

nginx负载均衡: 1.创建配置文件 vim /usr/local/nginx/conf/vhost/load.conf #添加以下内容: upstream qq_com #名字自定义,借助此模块定义多个IP,后面...

ZHENG-JY
33分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部