springboot 框架项目持续更新 mysql+mybatis+maven+redis+https+日志配置+自定义拦截器+Druid (二)——自定义拦截器

上一篇文件讲述了搭建基本的springboot项目+mybatis+mysql数据库,详细的增删改查就不再写了,不知道的可以去百度或者提问。本文章开始讲述自定义拦截器的类容。

1.首先创建拦截器 AuthInterceptor 继承字 HandlerInterceptorAdapter 并重写 preHandle 方法

package com.bctc.servlet.Intercept;

import com.bctc.entity.SMKeyBeen;
import com.bctc.service.SSLService;
import com.bctc.servlet.TokenBeanRedisRepository;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.support.WebApplicationContextUtils;
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;

/**
 * 添加拦截器 AuthInterceptor 继承字 HandlerInterceptorAdapter 重写 preHandle 方法
 * 所有请求先进来这里
 */
@Component
public class AuthInterceptor extends HandlerInterceptorAdapter {
    private Logger log = Logger.getLogger(AuthInterceptor.class);
    @Autowired
    private SSLService sSLService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("--进入拦截器AuthInterceptor--");
        if (!HandlerMethod.class.isAssignableFrom(handler.getClass())) {
            System.out.println("--进入拦截器1,是用来判断一个类Class1和另一个类Class2是否相同或是另一个类的子类或接口。 ");
            return true;
        }

        // 如果不是映射到方法直接通过
       /* if (!(handler instanceof HandlerMethod)) {
            log.info("--进入拦截器,但该方法不需要拦截,用来判断一个对象实例是否是一个类或接口的或其子类子接口的实例。 ");
            return true;
        }*/

        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method method = handlerMethod.getMethod();
        String requestPath = request.getRequestURI();
        // log.debug("requestIp: " + getIpAddress(request));
        //log.debug("Method: " + method.getName() + ", OenIntercept: " + method.isAnnotationPresent(OenIntercept.class));
        //log.debug("requestPath: " + requestPath);
        if (!handlerMethod.hasMethodAnnotation(OenIntercept.class) && handlerMethod.getBeanType().getAnnotation(OenIntercept.class) == null ) {
            System.out.println("--进入拦截器,类和方法上都没有拦截注解");
            return true;
        }
        if (requestPath.contains("/111") || requestPath.contains("/swagger") || requestPath.contains("/configuration/ui")) {
            log.info("--1123");
            return true;
        }
        if (requestPath.contains("/error")) {
            log.info("--1111333");
            return true;
        }

        if (method.isAnnotationPresent(OenIntercept.class) || handlerMethod.hasMethodAnnotation(OenIntercept.class)) {

            log.info("--1111444IgnoreSecurity");
            String token = request.getHeader("ACCESS_TOKEN");
            token = "P100AFH00W";
            log.debug("token: " + token);
            if (token.equals("") || token == null) {
                throw new Exception("无效token");
            }
            SMKeyBeen ssLs = sSLService.getSSLs(token);
            System.out.println(ssLs.getId());
            request.setAttribute("currentUser", ssLs);
            return true;
        }
        
}
/*Class.isAssignableFrom()方法 与 instanceof 关键字的区别

1. Class.isAssignableFrom()
是用来判断一个类Class1和另一个类Class2是否相同或是另一个类的子类或接口。
格式为: Class1.isAssignableFrom(Class2)
调用者和参数都是java.lang.Class类型, 返回值:boolean类型

以:ObjectString为例
a. "StringObject的父类"
   String.class.isAssignableFrom(Object.class) 结果false

b. "ObjectString的父类"
   Object.class.isAssignableFrom(String.class) 结果true

c. "ObjectObject相同"
   Object.class.isAssignableFrom(Object.class) 结果true


2. instanceof
用来判断一个对象实例是否是一个类或接口的或其子类子接口的实例。
格式是:o instanceof TypeName
第一个参数是对象实例名,第二个参数是具体的类名或接口名。

以:ObjectString为例
String str = new String();
String obj = new Object();

a. "ObjectString的父类"
   str instanceof Object 结果true

b. "StringString相同"
   str instanceof String 结果true

*/

2.OenIntercept第一个拦截注解

package com.bctc.servlet.Intercept;
import java.lang.annotation.*;

/**
 * 第一个拦截注解
 */
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface OenIntercept {
}

3.OenCurrent 用于标识用户实体类入参,参数级注解

package com.bctc.servlet.Intercept;

import java.lang.annotation.*;

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
//@OenCurrent 用于标识用户实体类入参,参数级注解
public @interface OenCurrent {
}

4.添加参数解析器 OenCurrentMethodArgumentResolver

package com.bctc.servlet.Intercept;

import com.bctc.entity.SMKeyBeen;
import com.bctc.servlet.Intercept.OenCurrent;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.multipart.support.MissingServletRequestPartException;

//     添加参数解析器 OenCurrentMethodArgumentResolver
public class OenCurrentMethodArgumentResolver implements HandlerMethodArgumentResolver {
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        System.out.println("2222");
        return parameter.getParameterType().isAssignableFrom(SMKeyBeen.class)
                && parameter.hasParameterAnnotation(OenCurrent.class);
    }
    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        SMKeyBeen userInfo = (SMKeyBeen) webRequest.getAttribute("currentUser", RequestAttributes.SCOPE_REQUEST);
        if (userInfo != null) {
            System.out.println(userInfo.getId()+"----");
            return userInfo;
        }
        throw new MissingServletRequestPartException("currentUser");
    }
}

5.然后就是在Application配置拦截器(将下面内容复制进去就可以)

扫描二维码关注公众号,回复: 1763813 查看本文章
/**
 注册拦截器和参数解析器在 WebMvcConfigurerAdapter 中,需要注意,拦截器中引用了 UserService 所以在注册时需要使用 @Bean 的形式以告诉 Spring 注入
 */
@Configuration
public class MyWebMvcConfigurerAdapter extends WebMvcConfigurerAdapter {
    //关键,将拦截器作为bean写入配置中
    @Bean
    public AuthInterceptor myAuthInterceptor() {
        return new AuthInterceptor();
    }
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 注册拦截器
        InterceptorRegistration ir = registry.addInterceptor(myAuthInterceptor());
        // 配置拦截的路径
        ir.addPathPatterns("/**");
        // 配置不拦截的路径
        //ir.excludePathPatterns("/ssl/getssl");
        // 还可以在这里注册其它的拦截器
        //registry.addInterceptor(roleInterceptor).addPathPatterns("/getstudent");
        //registry.addInterceptor(new OtherInterceptor()).addPathPatterns("/**");
    }
    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
        //第一个参数解析器
        argumentResolvers.add(oenCurrentMethodArgumentResolver());
      
        super.addArgumentResolvers(argumentResolvers);
    }
    @Bean//第一个参数解析器
    public OenCurrentMethodArgumentResolver oenCurrentMethodArgumentResolver() {
        return new OenCurrentMethodArgumentResolver();
    }

    }
}


6.在controller层中的使

package com.bctc.controller;
import com.bctc.entity.SMKeyBeen;
import com.bctc.service.SSLService;
import com.bctc.servlet.Intercept.OenCurrent;
import com.bctc.servlet.Intercept.OenIntercept;
import com.bctc.servlet.Intercept.TwoCurrent;
import com.bctc.servlet.Intercept.TwoIntercept;
import com.bctc.servlet.TokenBeanRedisRepository;
import com.bctc.util.Ret;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import sun.java2d.pipe.SpanIterator;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping("/ssl")
public class SSLController {
    //将你要加入日志的类加进去
    private Logger logger = Logger.getLogger(SSLController.class);
    @Autowired
    private SSLService sSLService;
    @RequestMapping("/getssl")
    @ResponseBody
    public Ret<Map> getSSL(@RequestParam(required = true) String serialNumber) throws Exception {
        if (serialNumber != null && !serialNumber.equals("")) {
            Map getssl = sSLService.getSSL(serialNumber);
            if (getssl != null) {
                logger.info("ssl成功");
                return Ret.success(getssl);
            }
        }
        return Ret.error("500", "ssl获取失败");
    }

    @OenIntercept
    @RequestMapping("/test")
    String test(@OenCurrent SMKeyBeen sMKeyBeen) throws Exception {
 
        return sMKeyBeen.getId();
    }
  
}

请求getssl方式时,因为没有拦截器注解所以会执行

--进入拦截器AuthInterceptor--

--进入拦截器,类和方法上都没有拦截注解

也就是说在拦截器AuthInterceptor中执行了

if (!handlerMethod.hasMethodAnnotation(OenIntercept.class) && handlerMethod.getBeanType().getAnnotation(OenIntercept.class) == null) == null) {
    System.out.println("--进入拦截器,类和方法上都没有拦截注解");
    return true;
}

请求test方式时,因为该方法上有@OenIntercept的注解,同时有OenCurrent 用于标识用户实体类入参,参数级注解

所以会先进入AuthInterceptor中执行

if (method.isAnnotationPresent(OenIntercept.class) || handlerMethod.hasMethodAnnotation(OenIntercept.class)) {

            log.info("--1111444IgnoreSecurity");
            String token = request.getHeader("ACCESS_TOKEN");
            token = "P100AFH00W";
            log.debug("token: " + token);
            if (token.equals("") || token == null) {
                throw new Exception("无效token");
            }
            SMKeyBeen ssLs = sSLService.getSSLs(token);
            System.out.println(ssLs.getId());
            request.setAttribute("currentUser", ssLs);
            return true;
        }

然后进入执行OenCurrentMethodArgumentResolver,test方法就可接收到实体参数sMKeyBeen(原本请求路径为http://10.20.10.86:9080/ssl/test)并没有参数传递,同过拦截器实现了修改请求的参数。

7.多个拦截器注解和参数解析器。在代码中标注第一个xxx的地方复制粘贴即可,将Application.java中相关代码改为如下

/**
 注册拦截器和参数解析器在 WebMvcConfigurerAdapter 中,需要注意,拦截器中引用了 UserService 所以在注册时需要使用 @Bean 的形式以告诉 Spring 注入
 */
@Configuration
public class MyWebMvcConfigurerAdapter extends WebMvcConfigurerAdapter {
    //关键,将拦截器作为bean写入配置中
    @Bean
    public AuthInterceptor myAuthInterceptor() {
        return new AuthInterceptor();
    }
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 注册拦截器
        InterceptorRegistration ir = registry.addInterceptor(myAuthInterceptor());
        // 配置拦截的路径
        ir.addPathPatterns("/**");
        // 配置不拦截的路径
       // ir.excludePathPatterns("/ssl/getssl");
        // 还可以在这里注册其它的拦截器
        //registry.addInterceptor(roleInterceptor).addPathPatterns("/getstudent");
        //registry.addInterceptor(new OtherInterceptor()).addPathPatterns("/**");
    }
    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
        //第一个参数解析器
        argumentResolvers.add(oenCurrentMethodArgumentResolver());
        //第二个参数解析器
        argumentResolvers.add(twoCurrentUserMethodArgumentResolver());
        super.addArgumentResolvers(argumentResolvers);
    }
    @Bean//第一个参数解析器
    public OenCurrentMethodArgumentResolver oenCurrentMethodArgumentResolver() {
        return new OenCurrentMethodArgumentResolver();
    }
    @Bean//第二个参数解析器
    public TwoCurrentMethodArgumentResolver twoCurrentUserMethodArgumentResolver() {
        return new TwoCurrentMethodArgumentResolver();
    }
}

8.项目完整结构


猜你喜欢

转载自blog.csdn.net/qq_39526250/article/details/80782979