猿蜕变系列8——一文搞懂Interceptor操纵姿势
看过之前的蜕变系列文章,相信你对springMVC有了一定的认识。对springMVC的文件上传,也有了一定的认识。今天我们来开启新讨论,讲一讲springMVC的Interceptor拦截器怎么去处理web层面通用逻辑。
在web开发中,我们有很多需要统一去处理的事情,我们先回忆下之前解决过的一个问题——请求的中文乱码问题。为了处理中文的乱码问题,我们编写并配置了过滤器(Filter),统一对字符做了UTF-8编码。
其实在程序中,还有很多类似需要全局统一处理的事情要做,比如登录验证、权限验证、请求访问时长统计,web应用层关键日志输出 ……为了解决这些需要去统一处理的问题,Spring MVC提供了拦截器(Interceptor)来处理。Spring MVC的拦截器有框架提供的,也提供了接口让用户自己去定义。用户自定义拦截器要求实现接口org.springframework.web.servlet.HandlerInterceptor。我们看下接口的定义(去掉注释的):
package org.springframework.web.servlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.method.HandlerMethod;
public interface HandlerInterceptor {
boolean preHandle(HttpServletRequest request,HttpServletResponse response, Object handler)
throws Exception;
void postHandle(
HttpServletRequest request,HttpServletResponse response, Object handler, ModelAndView modelAndView)
throws Exception;
void afterCompletion(
HttpServletRequest request,HttpServletResponse response, Object handler, Exception ex)
throws Exception;
}
接口有三个方法需要实现:
boolean preHandle(HttpServletRequest request,HttpServletResponse response, Object handler)
throws Exception;
返回值为 boolean类型,如果返回为 true,就会执行controller方法,并且会将afterCompletion()方法放到一个方法栈中等待执行。大家注意方法入参,request和response都存在,可以做的事情很多了。
void postHandle(
HttpServletRequest request,HttpServletResponse response, Object handler, ModelAndView modelAndView)
throws Exception;
无返回值类型,这个方法会在Controller方法执行完成之后执行。如果Controller的方法没有被执行到,那么这个方法也不会执行。大家注意一下,方法有个入参ModelAndView 类型的,这意味着我们可以修改返回视图。
void afterCompletion(
HttpServletRequest request,HttpServletResponse response, Object handler, Exception ex)
throws Exception;
当preHandle返回为true时,这个方法会被放到一个方法栈等待执行,什么时候执行呢?等待视图渲染完成之后再执行。大家注意方法参数有Exception类型的,在这里可以处理异常。
看看DispatcherServlet的源码的doDispatch方法就知道了,接下来我们自己实现一个拦截器:
package com.pz.web.study.springmvc.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
public class FirstInterceptor implements HandlerInterceptor{
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponseresponse, Object handler) throws Exception{
System.out.println("==preHandle==被执行了");
return true;
}
@Override
publicvoidpostHandle(HttpServletRequest request,
HttpServletResponseresponse, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("==postHandle==被执行了");
}
@Override
publicvoidafterCompletion(HttpServletRequest request,
HttpServletResponseresponse, Object handler, Exception ex)
throws Exception {
System.out.println("==afterCompletion==被执行了");
}
}
为了更好的查看效果我们编写个新的Controller
package com.pz.web.study.springmvc.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class InterceptorControllerDemo {
@RequestMapping("/InterceptorControllerDemo.do")
public String InterceptorControllerDemo() throws Exception {
System.out.println("Interceptor方法==InterceptorControllerDemo===被执行了");
return"../index";
}
}
增加拦截器配置,修改spring-servlet.xml增加内容
<!-- 配置拦截器 -->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.pz.web.study.springmvc.interceptor.FirstInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
启动应用,访问
http://127.0.0.1/InterceptorControllerDemo.do
注意控制台输出:
=FirstInterceptor=preHandle==被执行了
=Controller方法==InterceptorControllerDemo===被执行了
=FirstInterceptor=postHandle==被执行了
=FirstInterceptor=afterCompletion==被执行了
我们观察配置文件,mvc:interceptors发现拦截器有多个,那么有多个拦截器时怎么执行呢?哪个拦截器先执行?
为了搞明白这个我们再定义个拦截器吧:
package com.pz.web.study.springmvc.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
public class SecondInterceptor implements HandlerInterceptor{
@Override
public booleanpreHandle(HttpServletRequest request,
HttpServletResponseresponse, Object handler) throws Exception {
System.out.println("=SecondInterceptor=preHandle==被执行了");
return true;
}
@Override
public void postHandle(HttpServletRequestrequest,
HttpServletResponseresponse, Object handler,
ModelAndView modelAndView)throws Exception {
System.out.println("=SecondInterceptor=postHandle==被执行了");
}
@Override
public voidafterCompletion(HttpServletRequest request,
HttpServletResponseresponse, Object handler, Exception ex)
throws Exception {
System.out.println("=SecondInterceptor=afterCompletion==被执行了");
}
}
修改拦截器配置
<!-- 配置拦截器 -->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.pz.web.study.springmvc.interceptor.FirstInterceptor"/>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.pz.web.study.springmvc.interceptor.SecondInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
启动应用继续访问:
http://127.0.0.1/InterceptorControllerDemo.do
控制台输出
=FirstInterceptor=preHandle==被执行了
=SecondInterceptor=preHandle==被执行了
=Controller方法==InterceptorControllerDemo===被执行了
=SecondInterceptor=postHandle==被执行了
=FirstInterceptor=postHandle==被执行了
=SecondInterceptor=afterCompletion==被执行了
=FirstInterceptor=afterCompletion==被执行了
preHandle方法是按照配置顺序执行的,而postHandle和afterCompletion方法是按照配置逆序执行的!
我们在生活中经常遇到下面的场景,我们访问某些站点,一些功能需要在登录后才能使用。下面我们就来实现这样一个小功能:让url为/user/下访问的 Contoller方法,只能使用用户名为pangzi的用户才能访问。我们看下面这个例子:
先编写用于登录的页面login.jsp:
<%@ page language="java" contentType="text/html;charset=utf-8"
pageEncoding="utf-8"isELIgnored="false"%>
<html>
<head>
<title>spring form表单样例使用对象接收参数</title>
</head>
<body>
<form action="./login.do"method=post>
<lable>用户名:</lable>
<input type="text"name="userName" id="userName"/><br />
<lable>密码:</lable>
<input type="password"name="passWord" id="phone"/><br />
<input type="submit"value="登录"id="submit" /><br />
</form>
</body>
</html>
编写用于登录的Controller:
package com.pz.web.study.springmvc.controller;
import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import com.pz.web.study.springmvc.domain.User;
@Controller
public class LoginControllerDemo {
@RequestMapping("/login.do")
public String userAction(String userName,StringpassWord,HttpServletRequest request) throws Exception {
if(userName.equals("pangzi")&&passWord.equals("123456")){
User user= new User();
user.setUserName(userName);
request.getSession().setAttribute("user", user);
return"../index";
}
return"../login";
}
}
编写权限访问控制拦截器
package com.pz.web.study.springmvc.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import com.pz.web.study.springmvc.domain.User;
public class UserLoginInterceptor implements HandlerInterceptor{
@Override
public booleanpreHandle(HttpServletRequest request,
HttpServletResponseresponse, Object handler) throws Exception {
String uri=request.getRequestURI();
if(uri.contains("/user/")){
User user = (User)request.getSession().getAttribute("user");
if(null==user){
response.sendRedirect("/login.jsp");
}
}
System.out.println("=UserLoginInterceptor=preHandle==被执行了");
return true;
}
@Override
public void postHandle(HttpServletRequestrequest,
HttpServletResponseresponse, Object handler,
ModelAndView modelAndView)throws Exception {
System.out.println("=UserLoginInterceptor=postHandle==被执行了");
}
@Override
public void afterCompletion(HttpServletRequestrequest,
HttpServletResponseresponse, Object handler, Exception ex)
throws Exception {
System.out.println("=UserLoginInterceptor=afterCompletion==被执行了");
}
}
修改spring-servlet.xml增加拦截器配置:
<!-- 配置拦截器 -->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.pz.web.study.springmvc.interceptor.FirstInterceptor"/>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.pz.web.study.springmvc.interceptor.SecondInterceptor"/>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.pz.web.study.springmvc.interceptor.UserLoginInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
编写一个用于验证的Controller:
package com.pz.web.study.springmvc.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/user")
publicclass UserLoginControllerDemo {
@RequestMapping("/userAction.do")
public String userAction() throws Exception {
System.out.println("userAction成功执行了");
return"../index";
}
}
启动应用,访问:
http://127.0.0.1/user/userAction.do
页面跳转到登录页面,输入
用户名 pangzi
密码 123456
登录后
然后再访问
http://127.0.0.1/user/userAction.do
看看效果
- nwui —— 又一个go语言图形界面解决方案
- Golang 通用连接池
- 解决JS操作Cookies出现的乱码问题,修复WordPress评论乱码
- 分享一个WordPress外链跳转教程,兼容知更鸟暗箱下载和文章索引
- 让WordPress RSS/Feed订阅数据延迟发布,附RSS技巧集锦
- Linux系统防CC攻击自动拉黑IP增强版Shell脚本
- 利用artDialog给网站添加一个能显示搜索来路和关键词的欢迎框
- 解决启用wp super cache缓存后,页面追加多个斜杠仍然可以访问的隐患
- WordPress集成底部滚动推荐条,让好文章不再被埋没
- go语言base64加密解密的方法
- WordPress酷炫CSS3读者墙,排名按年度、本月、本周划分的小方法
- WordPress给文章添加百度是否已收录查询和显示功能(自定义栏目优化版)
- PHP制作百度站内搜索绿色通道的网页列表数据文件
- 分享几个可用的二维码API,以及给博客添加文章二维码图片的方法
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法