SpringBoot之HandlerInterceptor拦截器的使用 ——(二)自定义注解

在上一篇博客已经介绍了HandlerInterceptor的基本用法这里就不重复了详见:SpringBoot之HandlerInterceptor拦截器的使用 ——(一)

功能简介

拦截所有添加了我们自定义的注解的方法,并将userId和userMobile放入HttpServletRequest,之后通过对应的注解取值。

包格式

所需要的类

首先我们来先定义三个注解

根据需求其实UserId和UserMobile可以不要,不影响拦截器的使用

package com.xxx.core.annotation;

import javax.ws.rs.NameBinding;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(value = RetentionPolicy.RUNTIME)
@NameBinding
public @interface UserAuthenticate
{
	/**
	 * 是否需要校验访问权限 默认不校验
	 * 这是预留给咱们后台管理系统的,后台管理员角色不同访问权限不同。所以将这个设置为True后 拦截器做登录校验后,还可以做接口权限校验
	 * @return
	 */
	boolean permission() default false;

}
package com.xxx.core.annotation;

import java.lang.annotation.*;

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface UserId {
}
package com.xxx.core.annotation;

import java.lang.annotation.*;

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface UserMobile {
}

常量类

package com.xxx.core.handler;

public class HeaderCons {

    /**
     * 用户ID
     */
    public static final String USER_ID = "H-User-Id";

    /**
     * 用户手机号
     */
    public static final String USER_MOBILE = "H-User-Mobile";
}

拦截器

package com.xxx.core.filter;

import com.xxx.exception.FastRuntimeException;
import com.xxx.core.annotation.UserAuthenticate;
import com.xxx.core.handler.HeaderCons;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

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


public class TestFilter extends HandlerInterceptorAdapter {
	private final Logger logger = LoggerFactory.getLogger(TestFilter.class);
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		logger.info("request请求地址path[{}] uri[{}]", request.getServletPath(),request.getRequestURI());
		HandlerMethod handlerMethod = (HandlerMethod) handler;
		Method method = handlerMethod.getMethod();
		UserAuthenticate userAuthenticate = method.getAnnotation(UserAuthenticate.class);
		//如果没有加注解则userAuthenticate为null
		if (Objects.nonNull(userAuthenticate)) {
			Long userId= getUserId(request);
			//userAuthenticate.permission()取出permission判断是否需要校验权限
			if (userId == null || (userAuthenticate.permission() && !checkAuth(userId,request.getRequestURI()))){
				throw new FastRuntimeException(20001,"No access");
			}
		}
		return true;
	}

	/**
	 * 根据token获取用户ID
	 * @param request
	 * @return
	 */
	private Long getUserId(HttpServletRequest request){
		//添加业务逻辑根据token获取用户UserId
		request.getHeader("H-User-Token");
		Long userId = 1L;
		String userMobile = "18888888888";
		request.setAttribute(HeaderCons.USER_ID,userId);
		request.setAttribute(HeaderCons.USER_MOBILE,userMobile);
		return userId;
	}

	/**
	 * 校验用户访问权限
	 * @param userId
	 * @param requestURI
	 * @return
	 */
	private boolean checkAuth(Long userId,String requestURI){
		//添加业务逻辑根据UserId获取用户的权限组然后校验访问权限
		return true;
	}

	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
						   ModelAndView modelAndView) throws Exception {}

	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
			throws Exception {}
}
package com.xxx.core;

import com.xxx.core.filter.TestFilter;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

@Configuration
public class WebAppConfigurer extends WebMvcConfigurerAdapter {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 可添加多个,这里选择拦截所有请求地址,进入后判断是否有加注解即可
            registry.addInterceptor(new TestFilter()).addPathPatterns("/**");
    }
}

如果不需要使用UserId和UserMobile这两个注解到这里已经结束了。不过为了方便业务层的使用直接获取用户的id、mobile等信息我这里就加上了

添加如下类即可取出我们在拦截器中set进去的值

package com.xxx.core.handler;

import com.xxx.core.annotation.UserId;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import javax.servlet.http.HttpServletRequest;


public class UserIdMethodArgumentResolver implements HandlerMethodArgumentResolver {
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.hasParameterAnnotation(UserId.class);
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
        return servletRequest.getAttribute(HeaderCons.USER_ID);
    }
}
package com.xxx.core.handler;

import com.xxx.core.annotation.UserMobile;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import javax.servlet.http.HttpServletRequest;


public class UserMobileMethodArgumentResolver implements HandlerMethodArgumentResolver {
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.hasParameterAnnotation(UserMobile.class);
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
        return servletRequest.getAttribute(HeaderCons.USER_MOBILE);
    }
}

以上类是根据你定义的注解来建设的取出放在request里面的值,如果有多个就再加就行了

package com.xxx.core.filter;


import com.xxx.core.annotation.UserId;
import com.xxx.core.annotation.UserMobile;
import com.xxx.core.handler.UserIdMethodArgumentResolver;
import com.xxx.core.handler.UserMobileMethodArgumentResolver;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

import java.util.List;


@Configuration
public class FilterAutoConfiguration {


    @Configuration
    @ConditionalOnWebApplication
    @ConditionalOnClass({UserId.class, UserMobile.class})//多个用逗号隔开
    protected static class ArgumentResolverAutoConfiguration extends WebMvcConfigurerAdapter {
        protected ArgumentResolverAutoConfiguration() {
        }

        public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
        //可添加多个
            argumentResolvers.add(new UserIdMethodArgumentResolver());
            argumentResolvers.add(new UserMobileMethodArgumentResolver());
        }
    }
}

大功告成 接下来我们看看如何使用



package com.xxx.controller;


import com.xxx.common.response.Response;
import com.xxx.common.Urls;
import com.xxx.core.annotation.UserAuthenticate;
import com.xxx.core.annotation.UserId;
import com.xxx.core.annotation.UserMobile;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@Validated
@RestController
public class TestAuthController {
	@UserAuthenticate
	@GetMapping(value = Urls.Test.TEST)
	public Response testAuth(@UserId Long userId,@UserMobile String userMobile) {
		System.out.println("userId : "+ userId + "  userMobile :" + userMobile);
		return new Response();
	}
}

浏览器输入地址 后台打印
userId : 1 userMobile :18888888888

下一篇带来如何解决获取request中body内容后,导致字符流关闭,后续controller无法获取的问题
SpringBoot之HandlerInterceptor拦截器的使用 ——(三)获取请求参数解决java.io.IOException: Stream closed
SpringBoot之HandlerInterceptor拦截器的使用 ——(四)防重复提交

  • 29
    点赞
  • 114
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 19
    评论
好的,以下是一个关于Spring Boot中的HandlerInterceptor拦截器的源码解析及使用的经验案例: 在Spring Boot中,HandlerInterceptor拦截器同样是一个非常重要的组件,它可以在请求处理之前或之后对请求进行拦截,并进行一些处理。下面我们来详细介绍HandlerInterceptor的源码和使用方法。 首先,我们需要实现HandlerInterceptor接口,该接口包含三个方法:preHandle、postHandle和afterCompletion。其中,preHandle方法在请求处理之前被调用,postHandle方法在请求处理之后被调用,而afterCompletion方法在视图渲染之后被调用。 在preHandle方法中,我们可以进行一些前置处理,比如对请求进行权限验证、登录验证等。如果验证失败,我们可以返回false,使请求不会被处理。如果验证成功,我们可以返回true,使请求继续被处理。 在postHandle方法中,我们可以对请求的响应进行一些处理,比如添加一些自定义的头信息、设置响应的状态码等。在afterCompletion方法中,我们可以进行一些资源的清理工作,比如关闭数据库连接、删除临时文件等。 接下来,我们需要将HandlerInterceptor注册到Spring Boot中,以便它能够被正确的调用。我们可以通过配置类的方式来实现。 在配置类中,我们需要继承WebMvcConfigurerAdapter类,并重写addInterceptors方法,如下所示: ``` @Configuration public class AppConfig extends WebMvcConfigurerAdapter { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**"); } } ``` 以上配置的含义是:将所有请求的路径都映射到MyInterceptor拦截器上。 最后,我们需要测试HandlerInterceptor是否生效。我们可以在拦截器中添加一些输出语句,比如System.out.println("Interceptor preHandle..."),以便我们观察到拦截器的工作情况。 在本案例中,我们介绍了Spring Boot中HandlerInterceptor拦截器的源码和使用方法,包括实现HandlerInterceptor接口、配置拦截器、添加拦截器等步骤。希望这个案例能够帮助你更好地理解和使用HandlerInterceptor拦截器

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 19
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhibo_lv

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值