zoukankan      html  css  js  c++  java
  • spring boot 与 自定义interceptor

    前面学习过过滤器, 但是过滤器是针对servlet的, 用在springmvc和spring boot里面, 功能上, 感觉并不是很好用.

    那这里来学习一下拦截器.

    一. 拦截器的执行顺序

    1. 目录

    2. 拦截器

    拦截器里面, 我加了三个(First,Two,Third), 但是内容都差不多.

    package org.elvin.boot.interceptor;
    
    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    public class FirstInterceptor implements HandlerInterceptor {
        @Override
        public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
            System.out.println("FirstInterceptor preHandle");
            return true;
        }
    
        @Override
        public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
            System.out.println("FirstInterceptor postHandle");
        }
    
        @Override
        public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
            System.out.println("FirstInterceptor afterCompletion");
        }
    }

    preHandle 返回true, 才会继续下面的执行.

    拦截器注册:

    package org.elvin.boot.interceptor;
    
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
    
    @Configuration
    public class RegisterInterceptor extends WebMvcConfigurerAdapter {
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(new FirstInterceptor());
            registry.addInterceptor(new TwoInterceptor());
            registry.addInterceptor(new ThirdInterceptor());
    
            super.addInterceptors(registry);
        }
    }

    为了验证执行顺序, 这里使用了 thymeleaf, 然后在前台访问了我后台传过去的属性, 在访问的时候, 就会打印信息到控制台

    package org.elvin.boot.pojo;
    
    public class Book {
        private String name ;
    
        public String getName() {
            System.out.println("view : Book'name is " + name);
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }

    Controller:

    package org.elvin.boot.Controller;
    
    import org.elvin.boot.pojo.Book;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    @Controller
    @RequestMapping("first")
    public class FirstController {
        private String controllerPath = "first/";
    
        @GetMapping("index")
        public String index(Model model){
            System.out.println("controller : FirstController index doing...");
            Book book = new Book();
            book.setName("spring boot");
            model.addAttribute("book", book);
            return controllerPath + "index";
        }
    }

    View:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8" />
        <title>Title</title>
    </head>
    <body>
        <h1 th:text="${book.name}"></h1>
    </body>
    </html>

    在访问 localhost:8080/first/index 的时候, 就会在控制台输出响应的信息.

    这样, 就能看出单个拦截器的执行顺序.

    1. 在控制器方法执行之前, 执行的 preHandle 方法

    2. 执行控制器的action方法

    3. 执行完action, 解析view之前(如果有的话), 执行拦截器的 posthandle 方法

    4. 解析view

    5. 解析完之后, 执行 afterCompletion 方法

    当注册多个拦截器的时候, 执行顺序, 如图上所示了.

    二. 拦截器实现权限验证

    同样的, 先加入权限拦截器

    package org.elvin.boot.interceptor;
    
    import org.elvin.boot.annotation.NoLogin;
    import org.springframework.util.StringUtils;
    import org.springframework.web.method.HandlerMethod;
    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.HttpSession;
    
    public class LoginInterceptor implements HandlerInterceptor {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handle) throws Exception {
            HandlerMethod method = (HandlerMethod ) handle;
            Class<?> controllerType = method.getBeanType();
    
            if(method.getMethodAnnotation(NoLogin.class) != null || controllerType.getAnnotation(NoLogin.class) != null){
                return true;
            }
    
            HttpSession session = request.getSession();
            String token = (String)session.getAttribute("token");
            if(!StringUtils.isEmpty(token)){
                return true;
            }
    
            response.sendRedirect("/login/index");
            return false;
        }
    
        @Override
        public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
    
        }
    
        @Override
        public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
    
        }
    }

    然后注册权限拦截器

    package org.elvin.boot.interceptor;
    
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
    
    @Configuration
    public class RegisterInterceptor extends WebMvcConfigurerAdapter {
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
    
            registry.addInterceptor(new LoginInterceptor());
    
            super.addInterceptors(registry);
        }
    }

    在控制器中加入登录控制器, 提供登录页面和注销方法

    package org.elvin.boot.Controller;
    
    import org.elvin.boot.annotation.NoLogin;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.HttpSession;
    
    @NoLogin
    @Controller
    @RequestMapping("login")
    public class LoginController {
    
        @Autowired
        private HttpServletRequest request;
    
        @Autowired
        private HttpServletResponse response;
    
        private  String controllerPath = "login/";
    
        //@NoLogin
        @GetMapping("index")
        public String index(){
            HttpSession session = request.getSession();
            session.setAttribute("token", "token");
            return controllerPath + "index";
        }
    
        //@NoLogin
        @PostMapping("checkOut")
        @ResponseBody
        public String checkOut(){
            HttpSession session = request.getSession();
            session.setAttribute("token", null);
    
            return "ok";
        }
    }

    这里我做了一个免登录注解, 可以加在Controller上, 也可以加在 action 上. 

    package org.elvin.boot.annotation;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Target({ElementType.TYPE, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface NoLogin {
    }

    注解里面, 并不需要任何内容. 

    登录页面(这里登录页面只是为了注销用的, 所以访问过这个页面之后, 就表示登录成功了).

    <!DOCTYPE html>
    <html xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8"/>
        <title>Title</title>
    </head>
    <body>
    <div class="container">
        <input type="button" value="注销" id="checkOut"/>
    </div>
    
    
    <script th:src="@{/js/jquery-1.11.1.js}"></script>
    <script th:inline="javascript">
        $(function () {
            $(".container").delegate("#checkOut", "click", function () {
                $.ajax({
                    url: [[@{/login/checkOut}]],
                    type: 'post',
                    data: {},
                    success: function (res) {
                        if (res == "ok") {
                            alert("注销成功");
                        }
                    }
                });
            });
        });
    </script>
    </body>
    </html>

    结果演示方式:

     在浏览器中, 先打开 http://localhost:8080/login/index 页面, 然后在新标签中访问  http://localhost:8080/first/index 页面. 

     你会发现访问 first/index 的时候, 是可以访问的.

       此时, 在login/index页面中, 点击注销按钮之后, 再刷新 first/index 页面, 就会直接跳去登录页面.

  • 相关阅读:
    备注下Windows可能会用到的运行命令
    SQL2008R2 收缩数据库问题
    转:SQL Server服务器名称与默认实例名不一致的修复方法
    mac下初始化eclipse的安卓开发ndk开发环境
    eclipse android ndk 提示Type 'JNIEnv' could not be resolved 等信息解决办法
    eclipse ndk 配置和简单开发demo
    ubuntu15.10运行android studio出错unable to run mksdcard sdk tool
    Pavilion M4-1016TX 加装固态硬盘(SSD)+UEFI+GPT安装WIN8.1
    package.json和package-lock.json的区别
    Vue生命周期中mounted和created的区别
  • 原文地址:https://www.cnblogs.com/elvinle/p/8093062.html
Copyright © 2011-2022 走看看