文档章节

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
码字总数 35812
作品 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

没有更多内容

加载失败,请刷新页面

加载更多

Swagger中配置了@ApiModelProperty的allowableValues属性但不显示的问题

现在用Swagger来生成API文档的例子已经非常多了,今天碰到开发同事问了一个问题,帮着看了一下,主要还是配置方法的问题,所以记录一下。如果您也碰到了同样的问题,希望本文对您有用。 问题...

程序猿DD
7分钟前
0
0
sql 命令

show variables like '%general%'; show variables like '%log_output%'; show variables like '%quer%'; show global status like '%slow%';...

JavaSon712
14分钟前
0
0
Django修改默认数据库引擎

Django默认数据库引擎为sqlite3,除了sqlite3,还支持postgresql、mysql、oracle 配置如下:其中postgresql_psycopg2为postgresql的适配器。 'django.db.backends.postgresql' 'django.db.bac......

MichaelShu
19分钟前
0
0
动画源码解析

目录介绍 1.Animation和Animator区别 2.Animation运行原理和源码分析 2.1 基本属性介绍 2.2 如何计算动画数据 2.3 什么是动画更新函数 2.4 动画数据如何存储 2.5 Animation的调用 3.Animator...

潇湘剑雨
26分钟前
1
0
Mac OS 最强鼠标改键软件:BetterAndBetter

官网: http://www.better365.cn 话不多说,先上你们最喜欢的软件界面截图。 通用: 触摸板: 鼠标: 键盘: 情景模式: 文本跳窗(自动跳窗): 四角触发: 工具箱: 脚本: 关于: 说下我目...

故国有明
49分钟前
18
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部