在springboot中,使用自定义拦截器,只需要将类实现HandlerIntercepter
接口(与原生的filter也基本差不多)。
HandlerIntercepeter源码:
package org.springframework.web.servlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.lang.Nullable;
import org.springframework.web.method.HandlerMethod;
public interface HandlerInterceptor {
default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return true;
}
default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
@Nullable ModelAndView modelAndView) throws Exception {
}
default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
@Nullable Exception ex) throws Exception {
}
}
preHandle():当某个 url 已经匹配到对应的 Controller 中的某个方法,且在这个方法执行之前 去执行。返回 true 则放行,返回 false 则不会向后执行。
postHandle():当某个 url 已经匹配到对应的 Controller 中的某个方法,且在执行完了该方法,但是在 DispatcherServlet视图渲染之前。所以在这个方法中有个 ModelAndView 参数,可以在此做一些修改动作。
afterCompletion():在整个请求处理完成后(包括视图渲染)执行,这时做一些资源的清理工作,这个方法只有在 preHandle(……) 被成功执行后并且返回 true才会被执行。
只有当用户正确登录以后,才允许用户去访问网站的其他页面和资源,即初始时拦截掉所有请求,除了登录页面的请求,登录成功以后放行访问其他页面。
目录结构如下:
配置pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-thymeleafartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-devtoolsartifactId>
<scope>runtimescope>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-configuration-processorartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
exclude>
excludes>
configuration>
plugin>
plugins>
build>
使用lombok,来快速生成有参无参构造器,以及get ,set方法和toString()方法
package com.robin.boot.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;
}
index.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}">titleh3>
<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}">titleh3>
账号:<p th:text="${loginUser.userName}">账号xxxp>
密码:<p th:text="${loginUser.password}">密码xxxp>
body>
html>
package com.robin.boot.controller;
import com.robin.boot.bean.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
@Controller
public class LoginController {
@PostMapping("/login")
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 "index";
}
}
}
package com.robin.boot.interceptor;
import lombok.extern.slf4j.Slf4j;
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;
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {
// 目标方法执行之前
@Override
public 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;
}
}
// 目标方法执行完毕
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
log.info("postHandle执行{}",modelAndView);
}
// 页面渲染以后
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
log.info("afterCompletion执行异常{}",ex);
}
}
通过addInterceptors(InterceptorRegistry registry)
方法,使用registry.addInterceptor()
将自定义拦截器注册。
并且通过InterceptorRegistration.addPathPatterns()
方法添加拦截的请求,InterceptorRegistration.excludePathPatterns()
方法放行请求。
package com.robin.boot.config;
import com.robin.boot.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 {
// 添加注册拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor())
.addPathPatterns("/**") // 拦截所有请求
.excludePathPatterns("/","/login"); // 放行 / 和 /login请求,
// 因为例子写的比较简单
// .excludePathPatterns("/","/login","/css/**","/js/**","/fonts/**","/images/**"); 平常可以写这样
}
}
访问首页:
输入错误的账号信息:
直接通过地址栏访问show.html,http://localhost:8080/show.html
,拦截器发送提示信息并请求转发到index.html
,因为是请求转发,所有地址栏不会发生改变。
输入正确的账号信息,成功访问: