拦截器的使用详细步骤(springboot版)
源码在git上,可直接下载
https://github.com/suojinxing/testInterceptor.git
一、什么是拦截器
(非官方,方言解释)当从浏览器输入路径访问资源的时候,需要验证一些信息的时候,就需要使用拦截器。比如任何一个系统的主页,想要登录home页面,必须先登录,那么如何判断请求中是否包含登录信息,就需要使用拦截器。
二、怎么使用拦截器
1)使用步骤
- 创建项目,包结构如下(idea和sts是一样的,开发工具大同小异)
- 创建测试的
controller
类,用来测试访问路径
package com.cy.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class InterceptorController {
// 测试的访问路径
@GetMapping("home")
public String testInterceptor() {
return "通过拦截器,进入主页";
}
@RequestMapping("noName")
public String errorPage() {
return "用户身份有误,拒绝登录";
}
}
- 创建拦截器,其实就是实现
HandlerInterceptor
接口。记得添加@Component
注解
package com.cy.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
@Component
public class TestInterceptor implements HandlerInterceptor{
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
String name = request.getParameter("name");
if(StringUtils.isEmpty(name)) {
// 没有用户名,拦截该请求
response.sendRedirect("noName"); // 返回错误页面
return false;
}
return true; // 返回true,表示放行.
}
}
- 拦截器创建好之后,需要告诉spring。也就是需要把拦截器注册到spring。新建类实现
WebMvcConfigurer
接口。在类中注册拦截器即可。
package com.cy.interceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Component
public class InterceptorConfig implements WebMvcConfigurer{
@Autowired
private TestInterceptor interceptor; // 注入拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(interceptor)
.addPathPatterns("/home/**"); // 表示拦截home路径下所有的请求
}
}
- 测试连接:
http://localhost:8080/home
http://localhost:8080/home?name=apple
会发现第一个路径会被拦截,第二个不会。因为这都是拦截器中的业务逻辑。自己可以随意控制拦截器业务。这只是demo演示。
2)拦截器的类和方法介绍
- 自己新建一个类实现
HandlerInterceptor
接口,该接口中有三个方法
preHandle
这个方法是在访问请求前时执行,可以判断请求路径是否符合业务需求。可以放行或拦截请求postHandler
是请求执行完之后,这个方法才会执行afterCompletion
在请求执行完后,视图处理器渲染完试图后在执行。可以用来关闭资源
拦截器请求过程
package com.jt.interceptor;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import com.alibaba.druid.util.StringUtils;
import com.jt.pojo.User;
import com.jt.util.CooKieUtil;
import com.jt.util.IPUtil;
import com.jt.util.ObjectMapperUtil;
import com.jt.util.UserThreadLocal;
import redis.clients.jedis.JedisCluster;
/**
* 拦截器,不登录,不可以访问购物车
* @author apple
*
*/
@Component
public class UserInterceptor implements HandlerInterceptor {
@Autowired // 注入redis集群
private JedisCluster jedisCluster;
/*
* 返回
* true ==> 放行
* false => 拦截,需要配合重定向使用
* 业务思路:
* 如何判断用户是否登录?
* 实现:
* 1. 动态获取Cookie中的JT_TICKET中的值
* 2. 校验下用户IP
* 3. 查询Redis服务器.获取userJSON数据
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
// 1. 获取Cookie属性
Cookie cookie = CooKieUtil.getCookie(request, "JT_TICKET");
if (cookie != null) {
String ticket = cookie.getValue();
if (!StringUtils.isEmpty(ticket)) {
if (jedisCluster.exists(ticket)) {
// ticket在redis中存在
// 2. 校验IP
String nowIp = IPUtil.getIpAddr(request);
String realIp = jedisCluster.hget(ticket, "JT_USER_IP");
if (nowIp.equals(realIp)) {
// 3. 获取用户json数据
String userJson = jedisCluster.hget(ticket, "JT_USER");
User user = ObjectMapperUtil.toObject(userJson, User.class);
// 3.1 方式1: 使用域对象进行传输
request.setAttribute("user", user);
// 3.2 方式2: 利用threadlocal对象
UserThreadLocal.setUser(user);
return true;
}
}
}
}
// 伪静态,加`.html`后缀
response.sendRedirect("/user/login.html");
return false;
}
/*
* 清空ThreadLocal数据
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
UserThreadLocal.remove();
}
}