拦截器


文章目录

  • 拦截器
  • 官方文档介绍
  • 拦截器如何实现
  • 拦截器的代码实现
  • 登陆拦截器
  • 鉴权拦截器
  • 拦截器添加到拦截列表
  • 业务逻辑处理Controller
  • 流程顺序
  • 模拟登陆拦截
  • 配置登陆拦截器
  • 添加登陆拦截器
  • controller层
  • HTML页面


官方文档介绍

所有实现都支持处理程序拦截器,当您要将特定功能应用于某些请求(例如,检查主体)时,这些拦截器非常有用。拦截器必须使用三种方法从包中实现,这些方法应提供足够的灵活性来执行各种预处理和后处理:HandlerMapping HandlerInterceptor org.springframework.web.servlet

  • preHandle(..):在运行实际处理程序之前,
  • postHandle(..):运行处理程序后
  • afterCompletion(..):完成请求后

拦截器如何实现

实现一个自己的拦截器,需要实现HandlerInterceptor接口。接口内的三个核心方法如下:

  1. preHandle():该方法在业务处理器处理请求之前调用。主要用来进行一些前置初始化操作或者是对当前请求的预处理,也可以进行一些判断来决定请求是否要继续下去,该方法的返回值类型位boolean值,如果返回位false,就表示当前请求结束,如果返回为true,那么就会继续调用下一个Interceptor 的 preHandle 方法,如果已经是最后一个 Interceptor 的时候就会调用当前请求的 Controller 方法。
  2. postHandle():这个方法在当前请求进行处理之后,也就是Controller方法调用之后执行,但是它会在DispatcherServlet 进行视图返回渲染之前被调用,所以我们可以在这个方法中对Controller处理之后的ModelAndView 对象进行操作。
  3. afterCompletion():在postHandle执行之后执行,发生异常也会执行。该方法将在整个请求结束之后,也就是在DispatcherServlet渲染了对应的视图之后执行。这个方法的主要作用是用于进行资源清理工作的。

拦截器的代码实现

登陆拦截器

public class LogInterceptor extends HandlerInterceptorAdapter {

    //在执行Controller方法之前来执行的
    //用于用户认证校验、用户权限校验
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        long startTime = System.currentTimeMillis();
        System.out.println("\n-------- LogInterception.preHandle --- ");
        System.out.println("Request URL: " + request.getRequestURL());
        System.out.println("Start Time: " + System.currentTimeMillis());

        request.setAttribute("startTime", startTime);

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

        System.out.println("\n-------- LogInterception.postHandle --- ");
        System.out.println("Request URL: " + request.getRequestURL());

        // You can add attributes in the modelAndView
        // and use that in the view page
    }

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

        long startTime = (Long) request.getAttribute("startTime");
        long endTime = System.currentTimeMillis();
        System.out.println("Request URL: " + request.getRequestURL());
        System.out.println("End Time: " + endTime);

        System.out.println("Time Taken: " + (endTime - startTime));
    }

}

鉴权拦截器

public class AdminInterceptor extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {

        System.out.println("\n-------- AdminInterceptor.preHandle --- ");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, //
                           Object handler, ModelAndView modelAndView) throws Exception {

        System.out.println("\n-------- AdminInterceptor.postHandle --- ");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, //
                                Object handler, Exception ex) throws Exception {

        System.out.println("\n-------- AdminInterceptor.afterCompletion --- ");
    }

}

拦截器添加到拦截列表

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // LogInterceptor apply to all URLs.
        // LogInterceptor应用于所有url。
        registry.addInterceptor(new LogInterceptor());

       
        // 这个拦截器应用于/admin/*这样的URL
        // Exclude /admin/oldLogin
        registry.addInterceptor(new AdminInterceptor())//
                .addPathPatterns("/admin/*");
    }

}

业务逻辑处理Controller

@Controller
public class InterceptorTestController {

    @RequestMapping(value = { "/", "/test" })
    public String test(Model model) {

        System.out.println("\n-------- MainController --- ");

        System.out.println(" ** You are in Controller ** ");

        return "test";
    }

    @RequestMapping(value = { "/admin/login" })
    public String login(Model model) {

        System.out.println("\n-------- MainController.login --- ");

        System.out.println(" ** You are in Controller ** ");

        return "login";
    }

}

流程顺序

SpringShell命令不存在拦截 spring实现拦截器_java

模拟登陆拦截

配置登陆拦截器

public class LoginInterceptor2 implements  HandlerInterceptor{
    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle方法在控制器的处理请求方法调用之前执行");
        String uri = request.getRequestURI();
        //判断当前请求地址是否登录地址
        if(uri.contains("login") || uri.contains("toLoginPage"))
        {
            //直接放行
            return true;
        }
        else
        {
            //判断用户是否登录
            if(request.getSession().getAttribute("userName")!=null)
                //说明已经登录,放行
                return true;           
            else
                //没有登录,重定向到登录界面
                response.sendRedirect(request.getContextPath() + "/toLoginPage");   
        }

        //默认拦截
        return false;
    }
    @Override
    public void postHandle(HttpServletRequest request,
                           HttpServletResponse response, Object handler,
                           ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle方法在控制器的处理请求方法调用之后,解析视图之前执行");
    }
    @Override
    public void afterCompletion(HttpServletRequest request,
                                HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        System.out.println("afterCompletion方法在控制器的处理请求方法执行完成后执行,即视图渲染结束之后执行");
    }
}

添加登陆拦截器

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addViewControllers(ViewControllerRegistry registry)
    {
        registry.addViewController("/toIndexPage").setViewName("/index");
        registry.addViewController("/").setViewName("/index");
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor2())
            .addPathPatterns("/**") //所有路径都被拦截
            .excludePathPatterns( //添加不拦截路径
                "/toLoginPage", //登录页面
                "/login",       //登录请求
                "/**/*.html",   //html静态资源
                "/**/*.js",     //js静态资源
                "/**/*.css"     //css静态资源
        );
    }
}

controller层

@Controller
public class UserController {

    /**
     * 登录页面
     */
    @RequestMapping("/toLoginPage")
    public String toLoginPage()
    {
        //跳转至登录页面
        return "login.html";
    }
    /**
     * 登录
     */
    @RequestMapping(value = "/login", method = RequestMethod.POST)
    public String login(Model model, HttpServletRequest request, String userName, String password)
    {
        //验证登录信息
        if (userName.equals("xiaoqi") && password.equals("123456"))
        {
            //验证成功,记录Session信息
            request.getSession().setAttribute("userName", userName);
            //重定向到首页
            return "redirect:toIndexPage";
        }
        else
        {
            model.addAttribute("errorMsg", "账号或密码错误!");
        }
        //跳转至登录页面
        return toLoginPage();
    }

    /**
     * 登出
     */
    @RequestMapping(value = "/logout")
    public String logout(HttpServletRequest request)
    {
        //销毁session对象
        request.getSession().invalidate();
        //重定向到登录页面
        return "redirect:toLoginPage";
    }
}

HTML页面

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>用户登录</title>
</head>
<body>
<div align="center">请输入登录信息
    <form name="Mfrom" method="post" action="/login" onsubmit="SubmitLogin()">
        <table>
            <tr>
                <td>用户姓名:</td>
                <td><input type="text" name="userName" value="xiaoqi" class="txtBox" /></td>
            </tr>
            <tr>
                <td>登录密码:</td>
                <td><input type="password" name="password" value="123456" class="txtBox"/></td>
            </tr>
            <!-- 以下是提交、取消按钮 -->
            <tr>
                <td>
                    <input type="submit" value="登录" />
                </td>
                <td>
                    <input type="reset" value="取消" />
                </td>
            </tr>
        </table>
        <p style="color:red" th:text="${errorMsg}"></p>
    </form>
</div>
</body>
<script>
    //提交登录
    function SubmitLogin() {
        //判断用户名是否为空
        if (!Mfrom.userName.value) {
            alert("请输入用户姓名!");
            Mfrom.userName.focus();
            return false;
        }

        //判断密码是否为空
        if (!Mfrom.password.value) {
            alert("请输入登录密码!");
            Mfrom.password.focus();
            return false;
        }
        return true;
    }
</script>
</html>
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
    <meta name="author" content="pan_junbiao的博客">
</head>
<body>
<h1>首页</h1>
<p>当前Session中保存的登录人名称:<span th:text="${session.userName}"/></p>
<a href="logout" onclick="return confirm('确定注销吗?');">注销</a>
</body>
</html>

代码参考于https://o7planning.org/11689/spring-boot-interceptor