赞
踩
保持热爱、奔赴山河
SpringMVC中的拦截器用于拦截控制器方法的执行
SpringMVC中的拦截器需要实现HandlerInterceptor
SpringMVC的拦截器必须在SpringMVC的配置文件中进行配置
public class FirstIntercetor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("FirstInterceptor--->preHandle:控制器方法执行之前执行"); return true; // 返回值作用:false(拦截)true(放行) } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("FirstInterceptor--->postHandle:控制器方法执行之后执行"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("FirstInterceptor--->afterCompletion:渲染视图之后执行的"); } }
<!--配置拦截器-->
<mvc:interceptors>
<!-- 拦截器引用 -->
<bean class="pers.tianyu.interceptor.FirstInterceptor"></bean>
</mvc:interceptors>
<!-- 自定义拦截器 -->
<bean id="firstInterceptor" class="pers.tianyu.interceptor.FirstInterceptor"></bean>
<!--配置拦截器-->
<mvc:interceptors>
<!-- 拦截器引用 -->
<ref bean="firstInterceptor"></ref>
</mvc:interceptors>
<!-- 更精确的自定义拦截器 -->
<bean id="firstInterceptor" class="pers.tianyu.interceptor.FirstInterceptor"></bean>
<!--配置拦截器-->
<mvc:interceptors>
<!-- 以上两种配置方式都是对DispatcherServlet处理的所有的请求进行拦截 -->
<mvc:interceptor>
<!-- 配置需要拦截的请求路径,/**:拦截所有,/*:拦截一层目录结构请求 -->
<mvc:mapping path="/**"/>
<!-- 配置不需要拦截的请求路径 -->
<mvc:exclude-mapping path="/testRequestEntity"/>
<!-- 拦截器引用 -->
<ref bean="firstInterceptor"></ref>
</mvc:interceptor>
</mvc:interceptors>
preHandle();
控制器方法执行之前执行preHandle(),其boolean类型的返回值表示拦截(false)或放行(true)。
postHandle();
控制器方法执行之后执行postHandle()。
afterCompletion();
在控制器方法执行之后,且渲染视图完毕之后执行afterCompletion()。
类位置:org.springframework.web.servlet.DispatcherServlet
public class DispatcherServlet extends FrameworkServlet { protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request; HandlerExecutionChain mappedHandler = null; boolean multipartRequestParsed = false; WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); try { ModelAndView mv = null; Exception dispatchException = null; try { processedRequest = checkMultipart(request); multipartRequestParsed = (processedRequest != request); // Determine handler for the current request. mappedHandler = getHandler(processedRequest); if (mappedHandler == null) { noHandlerFound(processedRequest, response); return; } // Determine handler adapter for the current request. HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // Process last-modified header, if supported by the handler. String method = request.getMethod(); boolean isGet = HttpMethod.GET.matches(method); if (isGet || HttpMethod.HEAD.matches(method)) { long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) { return; } } // mappedHandler 处理器执行链 // 调用拦截器中 preHandle 方法 if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } // Actually invoke the handler.(调用控制器方法) mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) { return; } applyDefaultViewName(processedRequest, mv); // 调用拦截器中 postHandle 方法 mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { dispatchException = ex; } catch (Throwable err) { // As of 4.3, we're processing Errors thrown from handler methods as well, // making them available for @ExceptionHandler methods and other scenarios. dispatchException = new NestedServletException("Handler dispatch failed", err); } // 处理转发结果 processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } catch (Exception ex) { triggerAfterCompletion(processedRequest, response, mappedHandler, ex); } catch (Throwable err) { triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", err)); } finally { if (asyncManager.isConcurrentHandlingStarted()) { // Instead of postHandle and afterCompletion if (mappedHandler != null) { mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); } } else { // Clean up any resources used by a multipart request. if (multipartRequestParsed) { cleanupMultipart(processedRequest); } } } } private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv, @Nullable Exception exception) throws Exception { boolean errorView = false; if (exception != null) { if (exception instanceof ModelAndViewDefiningException) { logger.debug("ModelAndViewDefiningException encountered", exception); mv = ((ModelAndViewDefiningException) exception).getModelAndView(); } else { Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null); mv = processHandlerException(request, response, handler, exception); errorView = (mv != null); } } // Did the handler return a view to render? if (mv != null && !mv.wasCleared()) { // 渲染视图 render(mv, request, response); if (errorView) { WebUtils.clearErrorRequestAttributes(request); } } else { if (logger.isTraceEnabled()) { logger.trace("No view rendering, null ModelAndView returned."); } } if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) { // Concurrent handling started during a forward return; } if (mappedHandler != null) { // Exception (if any) is already handled.. // mappedHandler 处理器执行链 (渲染视图完毕后,调用拦截器afterCompletion方法) mappedHandler.triggerAfterCompletion(request, response, null); } } }
与SpringMVC配置文件的配置顺序有关。
preHandle方法按照配置顺序执行。
postHandle方法按照配置反序执行。
afterCompletion方法在postHandle方法之后按照配置反序执行。
类路径:org.springframework.web.servlet.HandlerExecutionChain
mappedHandler.applyPreHandle(processedRequest, response);方法
/** * Apply preHandle methods of registered interceptors. * @return {@code true} if the execution chain should proceed with the * next interceptor or the handler itself. Else, DispatcherServlet assumes * that this interceptor has already dealt with the response itself. */ boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception { // 对当前类中成员变量interceptorList进行正序循环 for (int i = 0; i < this.interceptorList.size(); i++) { // 获取集合中每一个拦截器 HandlerInterceptor interceptor = this.interceptorList.get(i); // 调用拦截器 preHandle 方法,返回true不执行,返回false执行 if (!interceptor.preHandle(request, response, this.handler)) { // 执行拦截器 afterCompletion 方法(如果 preHandle 方法返回false,不会执行 postHandle 方法,而会执行 afterCompletion 方法) triggerAfterCompletion(request, response, null); return false; } this.interceptorIndex = i; } return true; }
类路径:org.springframework.web.servlet.HandlerExecutionChain
mappedHandler.applyPostHandle(processedRequest, response, mv);方法
/**
* Apply postHandle methods of registered interceptors.
*/
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
throws Exception {
// 对当前类中成员变量interceptorList进行反序循环
for (int i = this.interceptorList.size() - 1; i >= 0; i--) {
// 获取拦截器集合中的每一个拦截器
HandlerInterceptor interceptor = this.interceptorList.get(i);
// 调用 postHandle 方法
interceptor.postHandle(request, response, this.handler, mv);
}
}
类路径:org.springframework.web.servlet.HandlerExecutionChain
mappedHandler.triggerAfterCompletion(request, response, null);方法
/** * Trigger afterCompletion callbacks on the mapped HandlerInterceptors. * Will just invoke afterCompletion for all interceptors whose preHandle invocation * has successfully completed and returned true. */ void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) { // 对当前类中成员变量interceptorIndex进行反序循环 // interceptorIndex:preHandle 返回false之前拦截器的索引 for (int i = this.interceptorIndex; i >= 0; i--) { // 获取拦截器集合中的每一个拦截器 HandlerInterceptor interceptor = this.interceptorList.get(i); try { // 调用 afterCompletion 方法 interceptor.afterCompletion(request, response, this.handler, ex); } catch (Throwable ex2) { logger.error("HandlerInterceptor.afterCompletion threw exception", ex2); } } }
若拦截器中,有某个拦截器的 preHandle() 方法返回false,拦截器的 preHandle() 返回false和它之前的拦截器的 preHandle() 都会执行。
preHandle() 返回false之后的拦截器的postHandle()都不执行。
拦截器的 preHandle() 返回 false 之前的拦截器的 afterCompletion() 会执行,当前拦截器的 afterCompletion() 不会执行。
除了自己配制的拦截器,SpringMVC还有一个自己默认的拦截器。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登录</title>
</head>
<body>
<%--在web-inf下面的所有页面或者资源,只能通过controller或者Servlet进行访问--%>
<h1>登录页面</h1>
<form action="${pageContext.request.contextPath}/user/login" method="post">
用户名:<input type="text" name="username">
密码:<input type="text" name="password">
<input type="submit" value="提交">
</form>
</body>
</html>
@Controller @RequestMapping("/user") public class LoginController { @RequestMapping("/main") public String main() { return "main"; } @RequestMapping("/goLogin") public String login(){ return "login"; } @RequestMapping("/login") public String login(HttpSession session, String username, String password){ if(null != username && null != password){ if("admin".equals(username) && "pword".equals(password)){ // 把用户的信息存在session中 session.setAttribute("userLoginInfo",username); } } return "redirect:/user/main"; } @RequestMapping("/goOut") public void goOut(HttpSession session, HttpServletResponse response) throws IOException { session.removeAttribute("userLoginInfo"); response.sendRedirect("/index.jsp"); } }
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>首页</title>
</head>
<body>
<h1>首页</h1>
<span>${password}</span>
<span>${username}</span>
<p>
<a href="${pageContext.request.contextPath}/user/goOut">注销</a>
</p>
</body>
</html>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>index</title>
</head>
<body>
<h1><a href="${pageContext.request.contextPath}/user/goLogin">登录页面</a></h1>
<h1><a href="${pageContext.request.contextPath}/user/main">首页</a></h1>
</body>
</html>
package pers.tianyu.config; import org.springframework.web.servlet.HandlerInterceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; public class LoginInterceptor implements HandlerInterceptor { public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { HttpSession session = request.getSession(); //放行:判断什么情况下登录 //登录页面也会放行 if (request.getRequestURI().contains("goLogin")) { return true; } if (request.getRequestURI().contains("login")) { return true; } if (session.getAttribute("userLoginInfo") != null) { return true; } //判断什么情况下没有登录 request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request,response); return false; } }
<!--关于拦截器的配置-->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean id="loginInterceptor" class="pers.tianyu.config.LoginInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
OK,测试登录拦截功能无误
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。