1. 介绍

1.1 什么是拦截器(Interceptor)?

Java里的拦截器是动态拦截Action调用的对象,它提供了一种机制可以使开发者在一个Action执行的前后执行一段代码,也可以在一个Action执行前阻止其执行,同时也提供了一种可以提取Action中可重用部分代码的方式。拦截器(Interceptor)同过滤器(Filter)一样,都是面向切面编程(AOP)的具体实现。

1.2 自定义拦截器使用步骤

  • 第一步: 自定义一个实现了Interceptor接口的类,或者继承抽象类AbstractInterceptor。
  • 第二步: 在配置文件中注册定义的拦截器,拦截指定规则的请求

2. 基于URL拦截

2.1 创建登录拦截器

新建文件: LoginVerifyInterceptor.java 继承HandlerInterceptorAdapter抽象类

package com.hui.javalearn.common;

import com.hui.javalearn.common.enums.ResultEnum;
import com.hui.javalearn.exception.ApiException;
import com.hui.javalearn.service.TokenService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
* 登录拦截器
*/
public class LoginVerifyInterceptor extends HandlerInterceptorAdapter {

@Autowired
private TokenService tokenService;

/**
* 拦截Controller方法,验证token是否失效
* @param request
* @param response
* @param handler
* @return
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
String requestURI = request.getRequestURI();
if (isValidateUri(requestURI)) {
// 这里是 验证token逻辑
String token = request.getHeader("TOKEN");
String uid = request.getHeader("UID");
if (!tokenService.verifyToken(uid,token)) {
throw new ApiException(ResultEnum.ERROR_TOKEN_ERROR);
}
}
return true;
}

/**
* 是否需要 拦截uri
* @param uri
* @return
*/
private Boolean isValidateUri(String uri){
boolean isValidateUri = true;
String[] filterPathRule = {
//过滤登录注册
"(/user/(.*)login)|(/user/register)",
//过滤swagger相关
"(/swagger-resources)|(/swagger-resources/(.*))|(/doc.html)|(/(.*)/bycdao-ui/(.*))",
//过滤错误页面
"(/error)",
// 过滤静态资源
"((.*).css)|((.*).js)|((.*).html)|((.*).jpg)",
};
for (String rule : filterPathRule) {
if (uri.toLowerCase().matches(rule)) {
isValidateUri = false;
break;
}
}
return isValidateUri;
}
}

拦截器方法介绍

  • preHandle:用于在将请求发送到控制器( Controller)之前执行操作。此方法应返回true,以将响应返回给客户端。
  • postHandle:方法在当前请求处理完成之后,也就是 Controller 方法调用之后执行,但是它会在DispatcherServlet 进行视图返回渲染之前被调用,所以我们可以在这个方法中对 Controller 处理之后的 ModelAndView 对象进行操作。
  • afterCompletion:在DispatcherServlet完全处理完请求后被调用,可用于清理资源等。返回处理(已经渲染了页面);

2.2 注册登录拦截器

新建文件: InterceptorConfig

package com.hui.javalearn.config;

import com.hui.javalearn.common.LoginVerifyInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;


@Configuration
public class InterceptorConfig implements WebMvcConfigurer {

/**
* 添加拦截器
* @param registry
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 拦截所有请求
registry.addInterceptor(VerifyInterceptor()).addPathPatterns("/**");
}
/**
* 登录拦截器
* @return
*/
@Bean
public LoginVerifyInterceptor VerifyInterceptor(){
return new LoginVerifyInterceptor();
}
}

到此基于URL的拦截器就完成了!

3. 基于注解拦截

3.1 创建注解

新建自定义注解: LoginRequired.java

package com.hui.javalearn.tools.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LoginRequired {

}

3.2 创建拦截器

新建文件: LoginAnnotationInterceptor.java

package com.hui.javalearn.common;

import com.hui.javalearn.common.enums.ResultEnum;
import com.hui.javalearn.exception.ApiException;
import com.hui.javalearn.service.TokenService;
import com.hui.javalearn.tools.annotation.LoginRequired;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;

public class LoginAnnotationInterceptor extends HandlerInterceptorAdapter {
@Autowired
private TokenService tokenService;
/**
* 拦截Controller方法,验证token是否失效
* @param request
* @param response
* @param handler
* @return
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
// 如果不是映射到方法直接通过
if (! (handler instanceof HandlerMethod)){
return false;
}
// 解析拦截器
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
// 判断方法是否有需要登录的注解
LoginRequired annotation = method.getAnnotation(LoginRequired.class);
if (annotation != null) {
// 验证token
String token = request.getHeader("TOKEN");
String uid = request.getHeader("UID");
if (!tokenService.verifyToken(uid,token)) {
throw new ApiException(ResultEnum.ERROR_TOKEN_ERROR);
}
}
return true;
}
}

3.3 注册拦截器

package com.hui.javalearn.config;

import com.hui.javalearn.common.LoginAnnotationInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;


@Configuration
public class InterceptorConfig implements WebMvcConfigurer {

/**
* 添加拦截器
* @param registry
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 拦截所有请求
registry.addInterceptor(LoginVerifyByAnnotation()).addPathPatterns("/**");

}

/**
* 登录拦截器
* @return
*/
@Bean
public LoginAnnotationInterceptor LoginVerifyByAnnotation(){
return new LoginAnnotationInterceptor();
}
}

3.5 使用

package com.hui.javalearn.controller;

import com.hui.javalearn.common.ResponseResult;
import com.hui.javalearn.common.enums.ResultEnum;
import com.hui.javalearn.dto.response.UserResponse;
import com.hui.javalearn.model.UserModel;
import com.hui.javalearn.service.UserService;
import com.hui.javalearn.tools.annotation.LoginRequired;
import com.hui.javalearn.tools.annotation.Phone;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;


/**
* @author liuqh
*/
@RestController
@Api(tags = "用户模块")
@RequestMapping("/user")
@Validated
@Slf4j
public class UserController {
@Autowired
private UserService userService;

@ApiOperation("查询用户")
@PostMapping("/getUser")
@LoginRequired // 有这个注解时会验证登录token
public ResponseResult<UserResponse> getUser(@Phone @RequestParam(value = "phone") String phone) {
try {
UserModel userModel = userService.searchUserByPhone(phone);
UserResponse userResponse = UserResponse.model2Response(userModel);
return ResponseResult.success(userResponse);
} catch (Exception e) {
return ResponseResult.error(ResultEnum.ERROR.getCode(), e.getMessage());
}
}
}