在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 "修改手机号需要登录"; } }
至此,我们启动服务器,访问接口,就能看到效果了,这里不再做示范。