SpringBoot使用自定义注解实现登录用户获取(详细步骤+图解)
简介
注解是一种能被添加到java代码中的元数据,类、方法、变量、参数和包都可以用注解来修饰。注解对于它所修饰的代码并没有直接的影响。
那么它可以用来做什么呢? 做日志记录、实现登录用户获取 等等等…
本文将通过几个简单步骤教大家如何使用自定义注解实现登录用户获取,废话不多说,直接上步骤。
- 先定义一个注解类(用户登录成功后,可用该注解获取用户id)
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author ChenTaWen
* @version 1.0
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface AuthUserId {
}
注解说明:
@Targe 说明 表明这个注解是什么类型
/** 类,接口(包括注解类型)或枚举的声明 */
TYPE,
/** 属性的声明 */
FIELD,
/** 方法的声明 */
METHOD,
/** 方法形式参数声明 */
PARAMETER,
/** 构造方法的声明 */
CONSTRUCTOR,
/** 局部变量声明 */
LOCAL_VARIABLE,
/** 注解类型声明 */
ANNOTATION_TYPE,
/** 包的声明 */
PACKAGE
-------------------------------------------------------------------------------
@Retention
注解的生命周期有三个阶段:
1、Java源文件阶段;
2、编译到class文件阶段;
3、运行期阶段。同样使用了RetentionPolicy枚举类型定义了三个阶段:SOURCE, CLASS,RUNTIME
---------------------------------------------------------------------------------
1、如果一个注解被定义为RetentionPolicy.SOURCE,则它将被限定在Java源文件中,那么这个注解即不会参与编译也不会在运行期起任何作用,这个注解就和一个注释是一样的效果,只能被阅读Java文件的人看到;
2、如果一个注解被定义为RetentionPolicy.CLASS,则它将被编译到Class文件中,那么编译器可以在编译时根据注解做一些处理动作,但是运行时JVM(Java虚拟机)会忽略它,我们在运行期也不能读取到;
3、如果一个注解被定义为RetentionPolicy.RUNTIME,那么这个注解可以在运行期的加载阶段被加载到Class对象中。那么在程序运行阶段,我们可以通过反射得到这个注解,并通过判断是否有这个注解或这个注解中属性的值,从而执行不同的程序代码段。我们实际开发中的自定义注解几乎都是使用的RetentionPolicy.RUNTIME;
在默认的情况下,自定义注解是使用的RetentionPolicy.CLASS。
---------------------------------------------------------------------------------
@Documented注解,是被用来指定自定义注解是否能随着被定义的java文件生成到JavaDoc文档当中。
---------------------------------------------------------------------------------
@Inherited注解,是指定某个自定义注解如果写在了父类的声明部分,那么子类的声明部分也能自动拥有该注解。
注:[@Inherited注解只对那些@Target被定义为ElementType.TYPE的自定义注解起作用]
- 定义一个类去实现 HandlerMethodArgumentResolver 并重写其方法(用来处理方法参数的解析器)
import com.auth0.jwt.interfaces.DecodedJWT;
import com.chentawen.springbootall.config.exception.MyException;
import com.chentawen.springbootall.util.JWTUtils;
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;
/**
* @author ChenTaWen
* @version 1.0
*/
public class UserIdResolver implements HandlerMethodArgumentResolver {
/**
* 判断是否是注解类,返回true则调用resolveArgument方法
*/
@Override
public boolean supportsParameter(MethodParameter methodParameter) {
return methodParameter.hasParameterAnnotation(AuthUserId.class);
}
/**
* 对@AuthUserId进行业务处理
*/
@Override
public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) {
//从请求头中获取token
String authorization = nativeWebRequest.getHeader("token");
if ("".equals(authorization)) {
throw new MyException("token不能为空");
}
//从token中拿到userId
DecodedJWT verify = JWTUtils.verify(authorization);
return verify.getClaim("userId").asInt();
}
}
- 将解析器注入到SpirngMVC
import com.chentawen.springbootall.config.annotation.UserIdResolver;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.List;
/**
* @author admin
*/
@Configuration
public class IntercaptorConfig implements WebMvcConfigurer {
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(new UserIdResolver());
}
}
- 编写Controller进行测试
import com.baomidou.mybatisplus.extension.api.R;
import com.chentawen.springbootall.config.annotation.AuthUserId;
import com.chentawen.springbootall.config.exception.MyException;
import com.chentawen.springbootall.model.User;
import com.chentawen.springbootall.util.JWTUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
/**
* @author admin
*/
@RestController
@RequestMapping("user")
public class UserLoginController {
@Value("${Login.username}")
private String realUsername;
@Value("${Login.password}")
private String realPassword;
@GetMapping("login")
public String login(String username, String password) {
if (username.equals(realUsername) && password.equals(realPassword)) {
User u = new User();
u.setId(99);
u.setPassword(password);
u.setUsername(username);
return JWTUtils.getToken(u);
}
return "登录失败!账号或者密码不对!";
}
@GetMapping("getUserId")
public R<Integer> getUserId(@AuthUserId Integer userId) {
return R.ok(userId);
}
}
- 使用Postman进行测试
登录接口-返回Jwt
测试自定义注解@AuthUserId-请求头带token,访问getUserId方法
注:为更贴合实际项目开发,本篇文章集成了MyBatis-Plus、Jwt,相关源码及依赖请看:
SpringBoot集成MyBatis-Plus以及MyBatis-Plus代码生成工具类(详细步骤+图解)
需要源码可滴滴! 有什么疑问可评论区提问!