文章出處

前面學習過過濾器, 但是過濾器是針對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 頁面, 就會直接跳去登錄頁面.


文章列表




Avast logo

Avast 防毒軟體已檢查此封電子郵件的病毒。
www.avast.com


arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()