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
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Java自定义注解和AOP切面是两个不同的概念,但它们可以结合使用来实现一些非常有用的功能。 Java自定义注解Java语言中的一种特殊的语法结构,它允许开发者在代码中添加一些元数据,以便后续处理程序能够基于这些元数据来进行特定的操作。Java自定义注解可以在类、方法、属性等各种代码元素上进行声明,并且可以指定注解的属性,以提供更多的元数据信息。 AOP(面向切面编程)是一种编程思想,它允许开发者在不改变原有代码的情况下,通过添加额外的代码来实现某些横切关注点的功能。AOP切面是一个包含一组通知(Advice)和切点(Pointcut)的类,它可以在程序运行时自动拦截指定的方法或类,并执行相应的通知。 在Java中,我们可以通过将自定义注解和AOP切面结合使用,来实现一些非常有用的功能。例如,我们可以定义一个名为 @Log 的注解,在程序中使用该注解来标记需要记录日志的方法,然后编写一个AOP切面来拦截这些方法,并在方法执行前后记录日志。这样,我们就可以轻松地实现统一的日志记录功能,而不需要在每个方法中都编写日志记录代码。 下面是一个简单的示例代码,演示了如何使用Java自定义注解和AOP切面来实现统一的日志记录功能: ```java // 定义一个名为 @Log 的注解 @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface Log { } // 编写一个AOP切面,拦截带有 @Log 注解的方法,并记录日志 @Aspect @Component public class LogAspect { @Around("@annotation(log)") public Object around(ProceedingJoinPoint joinPoint, Log log) throws Throwable { String methodName = joinPoint.getSignature().getName(); System.out.println("方法 " + methodName + " 开始执行..."); Object result = joinPoint.proceed(); System.out.println("方法 " + methodName + " 执行完成,返回值为:" + result); return result; } } // 在程序中使用 @Log 注解标记需要记录日志的方法 @Service public class UserService { @Log public String getUserInfo(String userId) { // ... } } ``` 在上面的代码中,我们首先定义了一个名为 @Log 的注解,并指定了它的作用范围为方法。然后,我们编写了一个AOP切面 LogAspect,使用 @Around 注解来指定切点为所有带有 @Log 注解的方法。在切面的 around 方法中,我们通过 ProceedingJoinPoint 对象获取当前执行的方法名,并在方法执行前后打印日志。最后,我们在 UserService 类的 getUserInfo 方法上使用了 @Log 注解,表示这个方法需要记录日志。 当程序运行时,LogAspect 切面会自动拦截 UserService 类的 getUserInfo 方法,并执行 around 方法中的逻辑,从而实现了统一的日志记录功能。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值