JAVA(自定义注解)统一获取用户信息

前言

项目中很多会用到获取用户基础信息,有时候我们会使用接口调用去数据库查询用户信息完成一系列操作,这样虽然也可以,但是很大一部分都是自己手动写好而且比较复杂化,所以JAVA有一个自定义注解,结合某些API的使用做一个标识提前封装好全局使用,只需要一个注解标识就可以获取用户一系列信息,是不是简单多了?OK(开怼)

核心依赖导入

<properties>
        <spring.cloud-version>Finchley.SR4</spring.cloud-version>
        <spring.cloud-other-version>2.0.4.RELEASE</spring.cloud-other-version>
        <boot-version>2.0.4.RELEASE</boot-version>
        <mysql-version>5.1.47</mysql-version>
        <mybatis-plus-version>2.2.0</mybatis-plus-version>
        <jwt-version>0.9.1</jwt-version>
    </properties>
    <dependencies>
        <!--SpringBoot核心依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
            <version>${boot-version}</version>
            <exclusions><!-- 去掉默认配置 -->
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>${boot-version}</version>
        </dependency>
        <!--SpringBoot核心依赖-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql-version}</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>${mybatis-plus-version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>${spring.cloud-version}</version>
            <!--TODO 必须添加如下设置才可导入Cloud-->
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-netflix-eureka-client</artifactId>
            <version>${spring.cloud-other-version}</version>
        </dependency>
        <!--TODO Cloud自动化配置-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter</artifactId>
            <version>${spring.cloud-other-version}</version>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>${jwt-version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
    </dependencies>
    <!--maven编译器指定jdk版本-->
    <build>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>true</filtering>
            </resource>
        </resources>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

自定义注解新增

import java.lang.annotation.*;

/**
 * @author xueWenLiang
 * @date 2021/4/29 17:30
 * @Description 描述信息
 */
@Documented
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestUser {
    /**
     * 是否查询LoginUser对象所有信息,true则通过rpc接口查询
     */
    boolean value() default false;
}

自定义拦截注解配置类

import com.xwl.annotation.RequestUser;
import com.xwl.config.enums.XwlResultErrorEnum;
import com.xwl.config.exception.XwlException;
import com.xwl.domain.XwlUser;
import com.xwl.utils.JwtUtils;
import lombok.AllArgsConstructor;
import org.springframework.core.MethodParameter;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
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;

/**
 * @author xueWenLiang
 * @date 2021/4/30 10:10
 * @Description 自定义注解控制器,解析token获取用户信息
 */
@AllArgsConstructor
@Component
public class XwlUserArgumentResolver  implements HandlerMethodArgumentResolver {
    /**
     * 执行判断是否满足使用规范
     * @param methodParameter
     * @return true即跳出进行业务处理(resolveArgument)|| false不执行
     */
    @Override
    public boolean supportsParameter(MethodParameter methodParameter) {
        //是否是注解元素
        boolean isTrueRequestUser = methodParameter.hasParameterAnnotation(RequestUser.class);
        //是否注在指定用户信息对象
        boolean isAnnotationXwlUser = methodParameter.getParameterType().isAssignableFrom(XwlUser.class);
        return isTrueRequestUser==isAnnotationXwlUser;
    }

    /**
     * 解析token封装用户信息
     * @param methodParameter
     * @param modelAndViewContainer
     * @param nativeWebRequest
     * @param webDataBinderFactory
     * @return
     * @throws Exception
     */
    @Override
    public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {
        HttpServletRequest request = nativeWebRequest.getNativeRequest(HttpServletRequest.class);
        XwlUser xwlUser= null;
        try {
            xwlUser = JwtUtils.getUserParameters(request);
        } catch (Exception e) {
            throw new XwlException(XwlResultErrorEnum.FORBIDDEN);
        }
        //不排除以下情况->抛出无鉴权权限
        if (ObjectUtils.isEmpty(xwlUser))throw new XwlException(XwlResultErrorEnum.FORBIDDEN);
        return xwlUser;
    }
}

自定义注解配置类装载器

/**
 * @author xueWenLiang
 * @date 2021/4/30 14:09
 * @Description 描述信息
 */
@Configuration
@Component
@SuppressWarnings("all")
public class RequestMvcConfigutaionFilter  implements WebMvcConfigurer {
    /**
     * 自定义注解控制器集合体处理
     * @param resolvers
     */
    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        //注入用户信息注解控制器
        resolvers.add(new XwlUserArgumentResolver());
    }
}

token工具类(生成,解析)

import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;
import com.xwl.domain.XwlUser;
import org.springframework.stereotype.Component;
import io.jsonwebtoken.*;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author xueWenLiang
 * @date 2021/4/30 10:21
 * @Description 描述信息
 * iss: jwt签发者
 *
 * sub: jwt所面向的用户
 *
 * aud: 接收jwt的一方
 *
 * exp: jwt的过期时间,这个过期时间必须要大于签发时间
 *
 * nbf: 定义在什么时间之前,该jwt都是不可用的.
 *
 * iat: jwt的签发时间
 *
 * jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击
 */
@Component
public class JwtUtils {
    private static final String SIGN_NAME = "xuewenliang";
    private static final String HEADER_TOKEN_KEY = "xwl_token";
    private static long mill = 60000L;
    private static final String ZHANG_SAN="eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiLlvKDkuIkiLCJzdWIiOiIyNTAiLCJpYXQiOjE2MTk3NTM3MDF9.FyRuh7hvuB_mPDbCqCBGxB8YW4YDxj--XmVj2d-KzU4";
    private static final String LI_SI="eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiLmnY7lm5siLCJzdWIiOiLmuZbljZfnnIEiLCJpYXQiOjE2MjAyOTA2NDB9.iQa7ICboE6JHpJvvx8tFoOa-kWgw8Z0IYDeh8h0OXPo";

    /**
     * 生成token
     *
     * @param name
     * @param emailAdress
     * @return
     */
    public static String createTokenByParams(String name, String emailAdress) {
        //当前时间-毫秒
        long now = System.currentTimeMillis();
        JwtBuilder builder = Jwts.builder().setId(name)
                .setSubject(emailAdress)
                .signWith(SignatureAlgorithm.HS256, SIGN_NAME)
                .setIssuedAt(new Date());
        String compact = builder.compact();
        return compact ;
    }

    /**
     * 解析token
     *
     * @param token
     * @return
     */
    public static Claims parseClaimsByToken(String token) {
        Claims claims = null;
        try {
            claims = Jwts.parser().setSigningKey(SIGN_NAME).parseClaimsJws(token).getBody();
        } catch (ExpiredJwtException e) {
            System.out.println("token异常");
        } catch (UnsupportedJwtException e) {
            System.out.println("token异常");
        } catch (MalformedJwtException e) {
            System.out.println("token异常");
        } catch (SignatureException e) {
            System.out.println("token异常");
        } catch (IllegalArgumentException e) {
            System.out.println("无权限");
        }
        return claims;
    }

    /**
     * 根据自定义注解注入分析请求头token封装用户信息返回
     * @param request
     * @return
     */
    public static XwlUser getUserParameters(HttpServletRequest request) {
        String tokenValue = request.getHeader(HEADER_TOKEN_KEY);
        //这里不用判断是否为空
        // TODO 备注:因为是否携带token由其它层负责拦截,用户信息获取token解析已经进入业务层
        //解析token串获取信息
        Claims claims = parseClaimsByToken(tokenValue);
        XwlUser xwlUser = new XwlUser();
        //设置名称
        xwlUser.setUserName(claims.getId());
        //设置地址
        xwlUser.setUserAddress(claims.getSubject());
        return xwlUser;
    }
}

封装返回体工具类

import com.xwl.config.enums.XwlResultErrorEnum;
import lombok.Data;

/**
 * @author xueWenLiang
 * @date 2021/4/29 16:31
 * @Description 描述信息
 */
@Data
public class R<T> {


    private Integer code;
    private String message;
    private T data;

    /**
     * 无参成功返回体
     *
     * @param <T>
     * @return
     */
    public static <T> R<T> OK() {
        return result(null, XwlResultErrorEnum.SUCCESS.getCode(),  XwlResultErrorEnum.SUCCESS.getMsg());
    }

    /**
     * 有数据返回体
     *
     * @param <T>
     * @return
     */
    public static <T> R<T> OK(T data) {
        return result(data, XwlResultErrorEnum.SUCCESS.getCode(),  XwlResultErrorEnum.SUCCESS.getMsg());
    }

    /**
     * 无备注服务器异常
     *
     * @param <T>
     * @return
     */
    public static <T> R<T> serverError() {
        return result(null, XwlResultErrorEnum.ERROR.getCode(),  XwlResultErrorEnum.ERROR.getMsg());
    }

    /**
     * 自定义异常回执信息
     *
     * @param <T>
     * @return
     */
    public static <T> R<T> exceptionReturn(XwlResultErrorEnum xwlResultErrorEnum) {
        return result(null, xwlResultErrorEnum.getCode(), xwlResultErrorEnum.getMsg());
    }

    /**
     * 统一封装异常体
     *
     * @param data
     * @param code
     * @param message
     * @param <T>
     * @return
     */
    public static <T> R<T> result(T data, int code, String message) {
        R<T> r = new R<>();
        r.setCode(code);
        r.setData(data);
        r.setMessage(message);
        return r;
    }
}

自定义异常处理类

import com.xwl.config.enums.XwlResultErrorEnum;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.springframework.stereotype.Component;

/**
 * @author xueWenLiang
 * @date 2021/4/30 14:20
 * @Description 描述信息
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class XwlException extends RuntimeException {
    /**
     * 枚举异常控制
     */
    private XwlResultErrorEnum xwlResultErrorEnum;

}

异常枚举类

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

/**
 * @author xueWenLiang
 * @date 2021/4/30 14:23
 * @Description 描述信息
 */
@Getter
@NoArgsConstructor
@AllArgsConstructor
@SuppressWarnings("ALL")
public enum XwlResultErrorEnum {
    SUCCESS(200, "操作成功"),
    FAILURE(400, "业务异常"),
    NOT_FOUND(404, "服务或资源未找到"),
    ERROR(500, "服务异常"),
    TOKEN_EXPIRE(401, "token过期,请重新登录!"),
    FORBIDDEN(403, "访问被拒绝,您无权访问!"),
    USER_NOT_NULL(404, "该用户不存在");
    //异常编号
    private Integer code;
    //异常注释
    private String msg;
}

全局异常拦截器

import com.xwl.config.exception.XwlException;
import com.xwl.utils.R;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * @author xueWenLiang
 * @date 2021/4/30 14:35
 * @Description 自定义拦截异常返回
 */
@ControllerAdvice
@ResponseBody
public class RequestErrorExceptionFilter  {
    /**
     * 业务异常返回拦截并返回
     * @param xwlException
     * @return
     */
    @ExceptionHandler(XwlException.class)
    public R returnException(XwlException xwlException){
        return R.exceptionReturn(xwlException.getXwlResultErrorEnum());

    }
}

核心配置YML

#端口配置
server:
  port: 8787
  #数据库基础配置信息
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/xwl?characterEncoding=utf-8
    username: root
    password: root
    driver-class-name: com.mysql.jdbc.Driver
  application:
    name: 自定义注解服务
mybatis-plus:
  configuration:
    map-underscore-to-camel-case: true #开启驼峰命名规则支持
    cache-enabled: true
    #扫描mapper持久层接口
  mapper-locations: classpath:com.xwl/**/mapper/*Mapper.xml
eureka:
  client:
    fetch-registry: false
    register-with-eureka: false

启动类

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

/**
 * @author xueWenLiang
 * @date 2021/4/29 16:26
 * @Description 描述信息
 */
@SpringBootApplication
@EnableDiscoveryClient
@MapperScan("com.xwl.mapper")
public class CustomApplication {

    public static void main(String[] args) {
        SpringApplication.run(CustomApplication.class,args);
    }
}

数据库脚本

库名:xwl

DROP TABLE IF EXISTS `xwl_user`;
CREATE TABLE `xwl_user`  (
  `id` bigint(50) NOT NULL,
  `user_name` varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL,
  `user_address` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_unicode_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of xwl_user
-- ----------------------------
INSERT INTO `xwl_user` VALUES (1, '张三', '河南省');
INSERT INTO `xwl_user` VALUES (2, '李四', '湖南省');

SET FOREIGN_KEY_CHECKS = 1;

工程结构图

在这里插入图片描述

测试

不传token

在这里插入图片描述

传错误token

在这里插入图片描述

传正确(张三)token

在这里插入图片描述

传李四的token

在这里插入图片描述

结语

可以看到,有了自定义用户注解,可以统一获取用户信息体,无需一层一层的实现再去查库等操作,后续也可以拓展放置缓存,随时随地获取当前登录用户,这样的话解决一些日常业务问题还是很方便的,你学会了吗?

源码地址

https://github.com/xwlgithub/xuewenliang/tree/master/my-annotation
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值