隸屬文章:Java高級 | (二十二)Java常用類庫-CSDN博客
系列文章:Java高級 | 【實驗一】Springboot安裝及測試 |最新-CSDN博客
? ? ? ? ? ? ? ? ??Java高級 | 【實驗二】Springboot 控制器類+相關注解知識-CSDN博客
? ? ? ? ? ? ? ? ??Java高級 | 【實驗三】Springboot 靜態資源訪問-CSDN博客
? ? ? ? ? ? ? ? ??Java高級 | 【實驗四】Springboot 獲取前端數據與返回Json數據-CSDN博客
? ? ? ? ? ? ? ? ??Java高級 | 【實驗五】Spring boot+mybatis操作數據庫-CSDN博客
? ? ? ? ? ? ? ? ??Java高級 | 【實驗六】Springboot文件上傳和下載-CSDN博客
目錄
一、【過濾器】Filter
1.1 過濾器的功能
1.2 過濾器的工作原理
二、過濾器實驗
2.1 實驗項目結構
2.2?源碼
(1)CorsFilter類
(2)FilterConfig類
(3)TimingFilter類
(4)TestController控制器類
2.3測試
(1)postman中測試結果
(2)Idea控制臺輸出的結果
三、【攔截器】interceptor
3.1 Interceptor使用場景
3.2 實現
3.3 工作/運行流程
四、?攔截器實驗
4.1 新建工程
4.2 編寫代碼
(1)實體類
(2)攔截器類
(3)配置攔截器類
(4)編寫控制器類
(5)創建前端頁面
(6)修改主類
4.3 測試
一、【過濾器】Filter
? ? ? ?過濾器是對數據進行過濾,預處理過程,當我們訪問網站時,有時候會發布一些敏感信息,發完以后有的會用*替代,還有就是登陸權限控制等,一個資源,沒有經過授權,肯定是不能讓用戶隨便訪問的,這個時候,也可以用到過濾器。
1.1 過濾器的功能
還有很多,例如實現URL級別的權限控制、壓縮響應信息、編碼格式等等。攔截掉我們不需要的接口請求,修改請求(request)和響應(response)內容,完成CORS跨域請求等等。
1.2 過濾器的工作原理
二、過濾器實驗
2.1 實驗項目結構
? ? ? Myfilter包中定義了兩個過濾器類和一個過濾器配置類:
- CorsFilter:跨域處理
- FilterConfig:配置兩個過濾器
- TimingFilter:記錄請求時間
2.2?源碼
(1)CorsFilter類
package myfilter;import jakarta.servlet.*;
import jakarta.servlet.FilterConfig;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.core.annotation.Order;import java.io.IOException;
@WebFilter
public class CorsFilter implements Filter {// 初始化方法(Filter 容器啟動時調用一次)@Overridepublic void init(FilterConfig filterConfig) throws ServletException {System.out.println("CorsFilter 初始化完成");}// 核心過濾方法(每個請求觸發一次)@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {HttpServletResponse httpResponse = (HttpServletResponse) response;httpResponse.setHeader("Access-Control-Allow-Origin", "*");httpResponse.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");System.out.println("CorsFilter 前置處理");chain.doFilter(request, response); // 繼續后續處理System.out.println("CorsFilter 后置處理");}// 銷毀方法(應用關閉時調用一次)@Overridepublic void destroy() {System.out.println("CorsFilter 銷毀");}
}
(2)FilterConfig類
package myfilter;import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FilterConfig {// 注冊 TimingFilter(順序1)@Beanpublic FilterRegistrationBean<TimingFilter> timingFilterRegistration() {FilterRegistrationBean<TimingFilter> registration = new FilterRegistrationBean<>();registration.setFilter(new TimingFilter());registration.addUrlPatterns("/*"); // 攔截所有路徑registration.setOrder(1); // 優先級最高(數值越小優先級越高)return registration;}// 注冊 CorsFilter(順序2)@Beanpublic FilterRegistrationBean<CorsFilter> corsFilterRegistration() {FilterRegistrationBean<CorsFilter> registration = new FilterRegistrationBean<>();registration.setFilter(new CorsFilter());registration.addUrlPatterns("/*");registration.setOrder(2); // 優先級次之return registration;}
}
(3)TimingFilter類
package myfilter;import jakarta.servlet.*;
import jakarta.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter // 可選注解(需配合 @ServletComponentScan)
public class TimingFilter implements Filter {private long startTime; // 記錄請求開始時間// 初始化方法(Filter 容器啟動時調用一次)public void init(FilterConfig filterConfig) throws ServletException {System.out.println("TimingFilter 初始化完成");// 可讀取 Filter 配置參數(如 filterConfig.getInitParameter("key"))}// 核心過濾方法(每個請求觸發一次)@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {startTime = System.currentTimeMillis();System.out.println("TimingFilter 前置處理開始");// 繼續 Filter 鏈或 Controllerchain.doFilter(request, response);long endTime = System.currentTimeMillis();System.out.println("TimingFilter 后置處理,總耗時:" + (endTime - startTime) + "ms");}// 銷毀方法(應用關閉時調用一次)@Overridepublic void destroy() {System.out.println("TimingFilter 銷毀");}
}
(4)TestController控制器類
package controller;import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {@GetMapping("/test")public String test() {System.out.println("Controller 方法執行");return "Hello from Controller!";}
}
(5)修改MyfilterApplication主類
package com.example.myfilter;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
@ComponentScan(basePackages = {"controller"})
@ComponentScan(basePackages = {"myfilter"})
public class MyfilterApplication {public static void main(String[] args) {SpringApplication.run(MyfilterApplication.class, args);}
}
2.3測試
(1)postman中測試結果
(2)Idea控制臺輸出的結果
三、【攔截器】interceptor
? ? ? ?攔截器(Interceptor)同 Filter 過濾器一樣,它倆都是面向切面編程——AOP 的具體實現(AOP切面編程只是一種編程思想而已)。
- 使用 Interceptor 來執行某些任務,例如在 Controller 處理請求之前編寫日志,添加或更新配置等等
- 在 Spring中,當請求發送到Controll時,在被Controller處理之前,它必須經過 Interceptors(0或多個)。
3.1 Interceptor使用場景
日志記錄:記錄請求信息的日志,以便進行信息監控、信息統計、計算 PV(Page View)等;
權限檢查:如登錄檢測,進入處理器檢測是否登錄;
性能監控:通過攔截器在進入處理器之前記錄開始時間,在處理完后記錄結束時間,從而得到該請求的處理時間。(反向代理,如 Apache 也可以自動記錄)
通用行為:讀取 Cookie、session、header等?得到用戶信息并將用戶對象放入請求,從而方便后續流程使用。?
3.2 實現
通常用戶可以自定義攔截器。
自定義 Interceptor 必須實現 org.springframework.web.servlet.HandlerInterceptor接口或繼承 org.springframework.web.servlet.handler.HandlerInterceptorAdapter類,并且需要重寫下面下面 3 個方法:
3.3 工作/運行流程
1、攔截器執行順序是按照Spring配置文件中定義的順序而定的。
2、會先按照順序執行所有攔截器的preHandle方法,一直遇到return false為止,比如第二個preHandle方法是return false,則第三個以及以后所有攔截器都不會執行。若都是return true,則按順序加載完preHandle方法。
3、然后執行主方法(自己的controller接口),若中間拋出異常,則跟return false效果一致,不會繼續執行postHandle,只會倒序執行afterCompletion方法。
4、在主方法執行完業務邏輯(頁面還未渲染數據)時,按倒序執行postHandle方法。若第三個攔截器的preHandle方法return false,則會執行第二個和第一個的postHandle方法和afterCompletion(postHandle都執行完才會執行這個,也就是頁面渲染完數據后,執行after進行清理工作)方法。(postHandle和afterCompletion都是倒序執行)。
四、?攔截器實驗
4.1 新建工程
工程名稱為“test_interceptor”,創建工程的時候勾選Lombok、Spring Web、Thymeleaf。
工程創建完畢后在java包中創建bean、config、controller、interceptor等四個包。
本實驗完整的工程圖如下圖所示:
4.2 編寫代碼
(1)實體類
在bean包中創建User類,其代碼如下:
package bean;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
@ToString
@NoArgsConstructor
@AllArgsConstructor
@Data
public class User {private String userName;private String password;
}
(2)攔截器類
在interceptor包中創建一個名為“LoginInterceptor”類,該類實現了HandlerInterceptor接口,說明該類是一個攔截器類。其代碼如下:
package interceptor;import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {// 目標方法執行之前@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 攔截請求輸出String requestURI = request.getRequestURI();log.info("攔截了請求{}", requestURI);// 登錄檢查邏輯,是否登錄,登錄成功以后放行資源,未登錄則攔截資源HttpSession session = request.getSession();Object loginUser = session.getAttribute("loginUser");if (loginUser != null) {// 登錄成功放行資源return true;} else {// 提示錯誤信息request.setAttribute("msg", "請先登錄!");// 請求轉發request.getRequestDispatcher("/").forward(request, response);// 未登錄攔截資源return false;}}// 目標方法執行完畢@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {log.info("postHandle執行{}",modelAndView);}// 頁面渲染以后@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {log.info("afterCompletion執行異常{}",ex);}
}
(3)配置攔截器類
該類主要功能是攔截哪些請求和不攔截哪些請求。
在config包中創建一個名為“MyWebConfig”的類,該類實現了WebMvcConfigurer接口。其代碼如下:
package config;import interceptor.LoginInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
// 自定義springboot配置類
@Configuration
public class MyWebConfig implements WebMvcConfigurer {// 添加注冊攔截器@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/**") // 攔截所有請求.excludePathPatterns("/","/login","/mylogin"); // 放行請求//平常可以寫這樣 // .excludePathPatterns("/","/login","/css/**","/js/**","/fonts/**","/images/**");}
}
(4)編寫控制器類
在controller包中編寫一個名為“LoginController”的類,該類的代碼如下啊:
package controller;import bean.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;@Controller
public class LoginController {@PostMapping("/mylogin")public String login(User user, Model model){System.out.println(user);if ("robin".equals(user.getUserName())&&"123456".equals(user.getPassword())){model.addAttribute("loginUser",user);return "show";}else{model.addAttribute("msg","登錄失敗,請檢查賬號密碼信息..");return "login";}}@RequestMapping("/login")public String ft_login() {return "login";}@RequestMapping("/show")public String ft_show() {return "show";}
}
(5)創建前端頁面
login.html的代碼:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>登錄頁面</title>
</head>
<body>
<h3 th:text="${msg}">title</h3>
<form action="/login" method="post"><input type="text" name="userName"><br><input type="password" name="password"><br><input type="submit" value="登錄">
</form>
</body>
</html>
show.html的代碼:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>顯示頁面</title>
</head>
<body>
<h3 th:text="${msg}">title</h3>
賬號:<p th:text="${loginUser.userName}">賬號xxx</p>
密碼:<p th:text="${loginUser.password}">密碼xxx</p>
</body>
</html>
(6)修改主類
在TestInterceptorApplication類中加入注解,注入控制器類和web配置類。修改后的代碼如下:
package com.example.test_interceptor;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
@ComponentScan(basePackages = {"controller"})
@ComponentScan(basePackages = {"config"})
public class TestInterceptorApplication {public static void main(String[] args) {SpringApplication.run(TestInterceptorApplication.class, args);}}