Learn03-SpringBoot中使用拦截器

拦截器的使用详细步骤(springboot版)

源码在git上,可直接下载
https://github.com/suojinxing/testInterceptor.git

一、什么是拦截器

(非官方,方言解释)当从浏览器输入路径访问资源的时候,需要验证一些信息的时候,就需要使用拦截器。比如任何一个系统的主页,想要登录home页面,必须先登录,那么如何判断请求中是否包含登录信息,就需要使用拦截器。

二、怎么使用拦截器

1)使用步骤

  1. 创建项目,包结构如下(idea和sts是一样的,开发工具大同小异)
    在这里插入图片描述
  2. 创建测试的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 "用户身份有误,拒绝登录";
	}
}

  1. 创建拦截器,其实就是实现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,表示放行.
	}
}

  1. 拦截器创建好之后,需要告诉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路径下所有的请求
	}
}

  1. 测试连接:
    http://localhost:8080/home
    在这里插入图片描述
    http://localhost:8080/home?name=apple
    在这里插入图片描述
    会发现第一个路径会被拦截,第二个不会。因为这都是拦截器中的业务逻辑。自己可以随意控制拦截器业务。这只是demo演示。

2)拦截器的类和方法介绍

  1. 自己新建一个类实现HandlerInterceptor接口,该接口中有三个方法
    接口中的方法
  2. preHandle这个方法是在访问请求前时执行,可以判断请求路径是否符合业务需求。可以放行或拦截请求
  3. postHandler是请求执行完之后,这个方法才会执行
  4. 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();
	}
}

发布了18 篇原创文章 · 获赞 7 · 访问量 369

猜你喜欢

转载自blog.csdn.net/weixin_44074551/article/details/103337955