在SpringBoot中,我们可以使用自定义注解来实现很多功能,比如权限控制,一般只需要四步就可以实现自定义注解。今天,我们就来简单总结一下SpringBoot实现自定义注解的方法。
业务场景:现在我需要对部分用户进行拦截,通过注解的方式,假如有这么一个注解@WithOutLogin,只要他作用在方法上,那么请求都不需要带token,反之,如果请求没有带token,那么请求方法将会失败。
一. 自定义注解
定义一个@interface类。
- package com.exam.common.security;
- import java.lang.annotation.*;
- @Target(ElementType.METHOD)
- @Retention(RetentionPolicy.RUNTIME)
- @Documented
- public @interface WithOutLogin {
- }
@Target:用于描述注解的使用范围。
ElementType.TYPE:类、接口(包括注解类型) 或enum声明。ElementType.METHOD:方法。
@Retention:注解的生命周期,用于表示该注解会在什么时期保留。
RetentionPolicy.RUNTIME:运行时保留,这样就可以通过反射获得了。
@Documented:表示该注解会被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化。
二. 编写拦截器类
注解定义好了,接下来使用Springboot拦截器,创建类继承HandlerInterceptor,并实现preHandle、postHandle、afterCompletion方法。然后在preHandle方法中编写业务逻辑,实现注解的业务功能。
- package com.exam.common.security;
- import lombok.extern.slf4j.Slf4j;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Component;
- import org.springframework.web.method.HandlerMethod;
- import org.springframework.web.servlet.HandlerInterceptor;
- import org.springframework.web.servlet.ModelAndView;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- @Component
- @Slf4j
- public class PermissionInterceptor implements HandlerInterceptor {
- //在请求已经返回之后执行
- public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handle, Exception ex) throws Exception {
- }
- //执行目标方法之后执行
- public void postHandle(HttpServletRequest request, HttpServletResponse response, Object hadnler, ModelAndView ex) throws Exception {
- }
- //在执行目标方法之前执行
- public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object hadnler) throws Exception {
- //判断是否方法级别的
- if (hadnler instanceof HandlerMethod) {
- HandlerMethod handlerMethod = (HandlerMethod) hadnler;
- WithOutLogin withOutLogin = handlerMethod.getMethodAnnotation(WithOutLogin.class);
- //有注解,则不验证token
- if (withOutLogin != null) {
- return true;
- }
- }
- String token = request.getHeader("X-Auth-Token");
- if (StringUtils.isBlank(token)) {
- log.error("未登录 userId is :{}, token is null.", token);
- return false;
- }
- return true;
- }
- }
三. 拦截器类注册
创建一个普通类,让该类继承WebMvcConfigurerAdapter,并且使用@Configuration注解标注在类名上,使其成为一个配置类。然后重写addInterceptors方法,当服务器启动时,会自动调用此方法。
- package com.exam.common.security;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
- 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 PermissionConfigure extends WebMvcConfigurerAdapter {
- @Autowired
- private PermissionInterceptor permissionInterceptor;
- @Override
- public void addInterceptors(InterceptorRegistry registry) {
- registry.addInterceptor(permissionInterceptor).addPathPatterns("/user/**");
- super.addInterceptors(registry);
- }
- }
四. 编写controller类
在Controller中的业务方法上选择是否标注@WithOutLogin注解,如果有,那么无需登录就可以执行该方法。如果没有此注解,就需要登录后才可以执行。
- package com.exam.api.rest;
- import com.exam.common.security.WithOutLogin;
- import lombok.extern.slf4j.Slf4j;
- import org.springframework.web.bind.annotation.PutMapping;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RestController;
- import javax.servlet.http.HttpServletRequest;
- @RestController
- @RequestMapping("/user")
- @Slf4j
- public class UserController extends RestBaseController {
- @WithOutLogin
- @PutMapping(value = "/findPassword")
- public String smsLogin(HttpServletRequest request){
- return "找回密码不需要登录";
- }
- @PostMapping(value = "/modifyMobile")
- public String modifyMobile(ModifyMobileRequest entity, HttpServletRequest request){
- return "修改手机号需要登录";
- }
- }
至此,我们启动服务器,访问接口,就能看到效果了,这里不再做示范。
本文已通过「原本」原创作品认证,转载请注明文章出处及链接。