SpringMVC拦截器的使用场景

微信公众号:javaFramework
欢迎关注

1.SpringMVC拦截器

1.1 拦截器简介

Spring web MVC的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器 进行预处理和后处理。

1.2 常见应用场景

1、日志记录 :记录请求信息的日志
2、权限检查,如登录检查
3、性能检测:检测方法的执行时间

1.2.1 日志记录
package com.yaspeed.web.interceptor;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Map;
import java.util.Map.Entry;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.NamedThreadLocal;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

/**
 * 日志拦截器 
* 记录信息:访问时间-Controller路径-对应方法名-请求参数信息-请求相对路径-请求处理时长 * * @author Administrator * */
public class LogInterceptor implements HandlerInterceptor { public static final Logger LOGGER = LoggerFactory.getLogger(LogInterceptor.class); private static final ThreadLocal startTimeThreadLocal = new NamedThreadLocal("ThreadLocal StartTime"); private String getParamString(Map map) { StringBuilder sb = new StringBuilder(); for (Entry e : map.entrySet()) { sb.append(e.getKey()).append("="); String[] value = e.getValue(); if (value != null && value.length == 1) { sb.append(value[0]).append("\t"); } else { sb.append(Arrays.toString(value)).append("\t"); } } return sb.toString(); } /** * 将ErrorStack转化为String. */ public static String getStackTraceAsString(Throwable e) { if (e == null) { return ""; } StringWriter stringWriter = new StringWriter(); e.printStackTrace(new PrintWriter(stringWriter)); return stringWriter.toString(); } @Override /** * 该方法将在请求处理之前进行调用
* 多个Interceptor,然后在SpringMVC会根据声明的前后顺序一个接一个的执行,而且所有的Interceptor中的preHandle方法都会在
* COntroller方法之前调用。SpringMVC的这种Interceptor链式结构也是可以中断的,这种中断方式时令preHandler的返回值为false
* 当prehandler的返回值为false的时候整个请求就结束了。 */
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { long startTime = System.currentTimeMillis(); request.setAttribute("startTime", startTime); startTimeThreadLocal.set(startTime); // 线程绑定变量(该数据只有当前请求的线程可见) if (HandlerMethod.class.equals(handler.getClass())) { StringBuilder sb = new StringBuilder(1000); sb.append("-----------------------开始计时:").append(new SimpleDateFormat("hh:mm:ss.SSS").format(startTime)) .append("-------------------------------------\n"); HandlerMethod h = (HandlerMethod) handler; sb.append("Controller: ").append(h.getBean().getClass().getName()).append("\n"); sb.append("Method : ").append(h.getMethod().getName()).append("\n"); sb.append("Params : ").append(getParamString(request.getParameterMap())).append("\n"); sb.append("URI : ").append(request.getRequestURI()).append("\n"); LOGGER.debug(sb.toString()); } return true; } /** * 在当前请求进行处理之后,也就是Controller 方法调用之后执行,但是它会在DispatcherServlet * 进行视图返回渲染之前被调用,所以我们可以在这个方法中对Controller 处理之后的ModelAndView 对象进行操作。 */ @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { long startTime = (Long) request.getAttribute("startTime"); long endTime = System.currentTimeMillis(); long executeTime = endTime - startTime; if (HandlerMethod.class.equals(handler.getClass())) { StringBuilder sb = new StringBuilder(1000); sb.append("CostTime : ").append(executeTime).append("ms").append("\n"); sb.append("-------------------------------------------------------------------------------"); LOGGER.debug(sb.toString()); } } /** * 该方法将在整个请求结束之后,也就是在DispatcherServlet 渲染了对应的视图之后执行。这个方法的主要作用是用于进行资源清理工作的。 */ @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { // 打印JVM信息。 if (LOGGER.isDebugEnabled()) { long beginTime = startTimeThreadLocal.get();// 得到线程绑定的局部变量(开始时间) long endTime = System.currentTimeMillis(); // 2、结束时间 // 如果controller报错,则记录异常错误 if (ex != null) { LOGGER.debug("Controller异常: " + getStackTraceAsString(ex)); } LOGGER.debug("计时结束:" + new SimpleDateFormat("hh:mm:ss.SSS").format(endTime) + " 耗时:" + (endTime - beginTime) + " URI:" + request.getRequestURI()); startTimeThreadLocal.remove(); } } }

springmvc.xml 中的配置

          
    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <bean class="com.yaspeed.web.interceptor.LogInterceptor">bean>
        mvc:interceptor>
    mvc:interceptors>
1.2.2 权限检查
/**
 * 权限检查
 * 
 * @author Administrator
 *
 */
public class PermissionInterceptor implements HandlerInterceptor {

    // 在执行handler之前来执行的
    // 用于用户认证校验、用户权限校验
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {

        // 得到请求的url
        String url = request.getRequestURI();

        // 判断是否是公开 地址
        // 实际开发中需要公开 地址配置在配置文件中
        // 从配置中取逆名访问url
        List open_urls = ResourcesUtil.gekeyList("anonymousURL");
        // 遍历公开 地址,如果是公开 地址则放行
        for (String open_url : open_urls) {
            if (url.indexOf(open_url) >= 0) {
                // 如果是公开 地址则放行
                return true;
            }
        }

        // 从配置文件中获取公共访问地址
        List common_urls = ResourcesUtil.gekeyList("commonURL");
        // 遍历公用 地址,如果是公用 地址则放行
        for (String common_url : common_urls) {
            if (url.indexOf(common_url) >= 0) {
                // 如果是公开 地址则放行
                return true;
            }
        }

        // 获取session
        HttpSession session = request.getSession();
        ActiveUser activeUser = (ActiveUser) session.getAttribute("activeUser");
        // 从session中取权限范围的url
        List permissions = activeUser.getPermissions();
        for (SysPermission sysPermission : permissions) {
            // 权限的url
            String permission_url = sysPermission.getUrl();
            if (url.indexOf(permission_url) >= 0) {
                // 如果是权限的url 地址则放行
                return true;
            }
        }
        // 执行到这里拦截,跳转到无权访问的提示页面
        request.getRequestDispatcher("/WEB-INF/jsp/refuse.jsp").forward(request, response);
        // 如果返回false表示拦截不继续执行handler,如果返回true表示放行
        return false;
    }

    // 在执行handler返回modelAndView之前来执行
    // 如果需要向页面提供一些公用 的数据或配置一些视图信息,使用此方法实现 从modelAndView入手
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
        System.out.println("HandlerInterceptor1...postHandle");

    }

    // 执行handler之后执行此方法
    // 作系统 统一异常处理,进行方法执行性能监控,在preHandle中设置一个时间点,在afterCompletion设置一个时间,两个时间点的差就是执行时长
    // 实现 系统 统一日志记录
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        System.out.println("HandlerInterceptor1...afterCompletion");
    }

}
1.2.3 性能检测
/**
 * 实现统计应用性能 拦截器 的实现是单例的,因此不管用户请求多少次 都 只访问一个拦截器实例,即线程不安全
* 解决方案:使用ThreadLocal,它是线程绑定的变量,提供线程局部变量 (一个线程一个ThreadLocal) * * @author Administrator * */
public class TimeInterceptor implements HandlerInterceptor { public static final Logger logger = LoggerFactory.getLogger(TimeInterceptor.class); // 统计应用性能 private NamedThreadLocal startTimeThreadLocal = new NamedThreadLocal<>("StopWatch-StartTime"); @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 1,开始时间 long startTime = System.currentTimeMillis(); // 线程绑定变量(该数据只有当前请求的线程可见) startTimeThreadLocal.set(startTime); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { // 2.结束时间 long endTime = System.currentTimeMillis(); // 得到线程绑定的局部 变量(开始时间) long beginTime = startTimeThreadLocal.get(); // 3.计算消耗时间 long consumeTime = endTime - beginTime; logger.debug("监控==========================: " + String.format("%s consume %d millis", request.getRequestURI(), consumeTime)); startTimeThreadLocal.remove(); } }

SpringMVC拦截器的使用场景_第1张图片

你可能感兴趣的:(SpringMVC)