Interceptor的使用和使用场景

本文详细介绍SpringMVC中拦截器Interceptor的使用方法及其应用场景,包括登录拦截、日志记录和权限验证等实用案例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、引言

在上一篇文章中,介绍了 Interceptor 和 Filter 的区别和执行顺序。我们可以知道 Filter 依赖于 Servlet,它主要是针对 URL 地址做一个编码的事情、过滤掉没用的参数、简单的安全校验(比如登录不登录之类),而 Interceptor 依赖于 SpringMVC 框架,它是在 service 或者一个方法调用前,调用一个方法,或者在方法调用后,调用一个方法。下面来具体介绍 Interceptor 的用法和使用场景。

二、介绍

1、Interceptor使用:
(1)、实现HandlerInterceptor接口。
(2)、继承实现了HandlerInterceptor接口的类。比如Spring已经提供的实现了HandlerInterceptor接口的
	抽象类HandlerInterceptorAdapter ;
2、关于HandlerInterceptor接口

该接口中定义了三个方法,我们就是通过这三个方法来对用户的请求进行拦截处理的。

(1)、preHandle (HttpServletRequest request, HttpServletResponse response, Object handle) 方法。顾名思义,该方法将在请求处理之前进行调用SpringMVC中的Interceptor是链式的调用的,在一个应用中或者是在一个请求中可以同时存在多个Interceptor。每个Interceptor的调用会依据它的声明顺序依次执行,而且最先执行的都是Interceptor中的preHandle 方法,所以可以在这个方法中进行一些前置初始化操作或者是对当前请求的一个预处理,也可以在这个方法中进行一些判断来决定请求是否要继续进行下去。该方法的返回值是Boolean类型的,当它返回为false时,表示请求结束,后续的Interceptor和Controller都不会再执行当返回值为true 时就会继续调用下一个Interceptor的preHandle方法,如果已经是最后一个Interceptor的时候就会是调用当前请求的Controller 方法。

(2)、postHandle (HttpServletRequest request, HttpServletResponse response, Object handle, ModelAndView modelAndView) 方法。由preHandle方法的解释我们知道这个方法包括后面要说到的afterCompletion方法都只能是在当前所属的Interceptor的preHandle方法的返回值为true时才能被调用。**postHandle方法,顾名思义就是在当前请求进行处理之后,也就是Controller方法调用之后执行,但是它会在DispatcherServlet进行视图返回渲染之前被调用,所以我们可以在这个方法中对Controller处理之后的ModelAndView对象进行操作。**postHandle方法被调用的方向跟preHandle是相反的,也就是说先声明的Interceptor的postHandle方法反而会后执行。

(3)、afterCompletion (HttpServletRequest request, HttpServletResponse response, Object handle, Exception ex) 方法,该方法也是需要当前对应的Interceptor的preHandle方法的返回值为true时才会执行。顾名思义,该方法将在整个请求结束之后,也就是在DispatcherServlet 渲染了对应的视图之后执行。这个方法的主要作用是用于进行资源清理工作的。

三、代码

1、Interceptor的使用场景

上面对Interceptor的三个方法进行了详细的介绍,下面我们就来看看Interceptor的使用场景。

(1)、登陆拦截器
//登陆拦截器
public class LoginInterceptor implements HandlerInterceptor {

	/**
	 * 在控制器执行之前完成业务逻辑操作
	 * 方法的返回值决定逻辑是否继续执行, true,表示继续执行, false, 表示不再继续执行。
	 */
	public boolean preHandle(HttpServletRequest request, 
					HttpServletResponse response, Object handler) throws Exception {
		
		// 判断当前用户是否已经登陆
		HttpSession session = request.getSession();
		User loginUser = (User)session.getAttribute("loginUser");
		
		if ( loginUser == null ) {
			String path = session.getServletContext().getContextPath();
			response.sendRedirect(path + "/login");
			return false;	
		} else {
			return true;
		}
	}

	/**
	 * 在Controller方法调用之后执行,但是它会在DispatcherServlet进行视图返回渲染之前被调用
	 */
	public void postHandle(HttpServletRequest request, 
					HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {
		// TODO Auto-generated method stub
	}

	/**
	 * 在完成视图渲染之后,执行此方法。
	 */
	public void afterCompletion(HttpServletRequest request, 
					HttpServletResponse response, Object handler, Exception ex)
			throws Exception {
	}
}

登陆拦截器在访问每个URL的时候都会进行是否登陆判断,如果没登陆的话,就直接跳转到登陆页,并不会跳转到要访问的路径(数据可能获取不到)。在登陆的控制器中,需要把用户信息放在session中,然后在登陆拦截器中,采用如下方式获取HttpSession session = request.getSession();

//登陆控制器,往session中存用户数据代码
User dbUser = userService.queryForLogin(user);
if ( dbUser != null ) {
	session.setAttribute("loginUser", dbUser);
}
(2)、日志拦截器
	/**
	 * 用于记录日志,在每次请求之前,打印请求的地址和参数,方便调试
	 */

	public class LogInterceptor implements HandlerInterceptor {
	
		/** 记录日志 */
		private static Logger logger = LogManager.getLogger(LogManager.ROOT_LOGGER_NAME);
		
		@Override
		public boolean preHandle(HttpServletRequest request,HttpServletResponse response, 
									Object arg2) throws Exception {
			StringBuilder sb = new StringBuilder();
			String uri = request.getRequestURI();
			sb.append("---------------> demo uri:").append(uri).append(" - ");
	
			Enumeration<String> enums2 = request.getParameterNames();
			while (enums2.hasMoreElements()) {
				String key = enums2.nextElement();
				sb.append("\"").append(key).append("\":").append(
						request.getParameter(key)).append(", ");
			}
			logger.info(sb.toString());
			return true;
		}	

		@Override
		public void postHandle(HttpServletRequest request,HttpServletResponse response, 
									Object arg2, ModelAndView arg3)throws Exception {
		
		}
	
		@Override
		public void afterCompletion(HttpServletRequest request,HttpServletResponse response, 
									Object arg2, Exception arg3) throws Exception {
		
		}
	}
(3)、授权访问Url拦截器

此处需要说明一下,无论在门户网站还是管理平台,如果登陆系统后,你知道一些存在的url,即使你没有访问权限,但你在浏览器中直接输入正确的url,你依然可以访问页面,此拦截器的目的就是解决这个问题。

	//此处采用继承抽象类的方式,不是实现Interceptor方式
	public class AuthInterceptor extends HandlerInterceptorAdapter {

		@Autowired
		private PermissionService permissionService;
		
		@Override
		public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
											Object handler) throws Exception {
			// 获取用户的请求地址
			String uri = request.getRequestURI();
			String path = request.getSession().getServletContext().getContextPath();
			
			// 判断当前路径是否需要进行权限验证。
			// 查询所有需要验证的路径集合
			List<Permission> permissions = permissionService.queryAll();
			Set<String> uriSet = new HashSet<String>();
			for ( Permission permission : permissions ) {
				if ( permission.getUrl() != null && !"".equals(permission.getUrl()) ) {
					uriSet.add(path + permission.getUrl());
				}
			}
			
			if ( uriSet.contains(uri) ) {
				// 权限验证
				// 判断当前用户是否拥有对应的权限
				Set<String> authUriSet = (Set<String>)request.getSession()
															.getAttribute("authUriSet");
				if ( authUriSet.contains(uri) ) {
					return true;
				} else {
					response.sendRedirect(path + "/error");
					return false;
				}
			} else {
				return true;
			}
		}
	}
(4)、在SpringMVC中注册这些拦截器
	<mvc:interceptors>
		//对所有请求进行拦截,包括静态资源
		<mvc:interceptor>  
			<mvc:mapping path="/**"/>  
			<bean class="com.scorpios.atcrowdfunding.web.LogInterceptor"></bean>
		</mvc:interceptor> 
        <mvc:interceptor>
            <mvc:mapping path="/**" />
            <mvc:exclude-mapping path="/login" />
            <mvc:exclude-mapping path="/doAJAXLogin" />
            <mvc:exclude-mapping path="/bootstrap/**" />
            <mvc:exclude-mapping path="/css/**" />
            <mvc:exclude-mapping path="/fonts/**" />
            <mvc:exclude-mapping path="/img/**" />
            <mvc:exclude-mapping path="/jquery/**" />
            <mvc:exclude-mapping path="/layer/**" />
            <mvc:exclude-mapping path="/script/**" />
            <mvc:exclude-mapping path="/ztree/**" />
            //该拦截器不对静态资源进行拦截
            <bean class="com.scorpios.atcrowdfunding.web.LoginInterceptor"></bean>
        </mvc:interceptor>
        <mvc:interceptor>
            <mvc:mapping path="/**" />
            <mvc:exclude-mapping path="/login" />
            <mvc:exclude-mapping path="/doAJAXLogin" />
            <mvc:exclude-mapping path="/bootstrap/**" />
            <mvc:exclude-mapping path="/css/**" />
            <mvc:exclude-mapping path="/fonts/**" />
            <mvc:exclude-mapping path="/img/**" />
            <mvc:exclude-mapping path="/jquery/**" />
            <mvc:exclude-mapping path="/layer/**" />
            <mvc:exclude-mapping path="/script/**" />
            <mvc:exclude-mapping path="/ztree/**" />
            //该拦截器不对静态资源进行拦截
            <bean class="com.scorpios.atcrowdfunding.web.AuthInterceptor"></bean>
        </mvc:interceptor>
    </mvc:interceptors>

以上就是拦截器Interceptor的使用和使用场景。

四、总结

(1)、在SpringMVC中利用mvc:interceptors标签,来声明一系列的拦截器,然后它们就可以形成一个拦截器链,拦截器的执行顺序是按声明的先后顺序执行的,先声明的拦截器中的preHandle方法会先执行,然而它的postHandle方法和afterCompletion方法却会后执行。

(2)、在mvc:interceptors标签下声明interceptor主要有两种方式:

a、直接定义一个Interceptor实现类的bean对象。使用这种方式声明的Interceptor拦截器将会对所有的请求进行拦
截。
b、使用mvc:interceptor标签进行声明。使用这种方式进行声明的Interceptor可以通过mvc:mapping子标签来定义
需要进行拦截的请求路径。

经过上述两步之后,定义的拦截器就会发生作用对特定的请求进行拦截了。

### 如何使用拦截器 (Interceptor) #### 实现 HandlerInterceptor 接口 为了创建一个自定义的拦截器,在 Spring Boot 应用程序中通常需要实现 `HandlerInterceptor` 接口。此接口提供了三个主要的方法来控制请求的不同阶段: - **preHandle**: 请求处理前被调用,返回 true 则继续流程;false 将中断后续操作。 - **postHandle**: 请求处理器完成执行后但在视图渲染之前调用。 - **afterCompletion**: 整个请求结束之后调用。 ```java import org.springframework.web.servlet.HandlerInterceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class MyCustomInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("Before handling the request"); return true; // Continue with next interceptors or target method. } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("After processing but before rendering view"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("Request has been completed."); } } ``` #### 注册拦截器到 WebMvcConfigurer 为了让应用程序知道新创建的拦截器的存在,还需要将其注册至配置类中。这可以通过扩展 `WebMvcConfigurer` 并重写相应的方法来完成。 ```java import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class AppConfig implements WebMvcConfigurer { private final MyCustomInterceptor myCustomInterceptor; public AppConfig(MyCustomInterceptor myCustomInterceptor){ this.myCustomInterceptor = myCustomInterceptor; } @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(myCustomInterceptor).addPathPatterns("/api/**"); // Apply to all API endpoints under /api/ } } ``` #### 配置静态资源路径排除 有时可能不希望某些类型的请求受到拦截影响,比如加载 CSS 文件或其他前端依赖项时。这时可以指定要忽略的具体 URL 模式。 ```java @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/"); } // In addition to adding resource handlers... @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new MyCustomInterceptor()) .excludePathPatterns("/static/**", "/css/**", "/js/**", "/images/**"); } ``` #### 用户会话状态检查 在许多情况下,开发者可能会利用拦截器来进行身份验证或授权检查。下面的例子展示了如何基于用户会话信息做出决策。 ```java @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { HttpSession session = request.getSession(false); if(session != null && session.getAttribute("user") != null){ return true; }else{ response.sendRedirect("/login"); return false; } } ``` #### 条件化取消拦截行为 根据具体的业务需求,也可以有条件地跳过某个特定路径下的拦截动作。例如只针对 POST 方法实施额外的安全措施。 ```java if ("POST".equalsIgnoreCase(request.getMethod()) && !request.getRequestURI().startsWith("/admin/")) { // Perform additional checks here and decide whether to proceed. } else { return super.preHandle(request, response, handler); } ``` 以上就是有关于如何在 Spring Boot 中设置运用拦截器的一个基本介绍[^1]。除了上述提到的功能外,拦截器还能够用于其他多种场景下增强应用的行为,如日志记录、性能监控等[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

止步前行

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值