【TJXT】DAY2

目录

前言

[1. 开发新业务流程](#1. 开发新业务流程)

[2. 枚举类中的注解](#2. 枚举类中的注解)

[3. 登录用户的传递](#3. 登录用户的传递)


前言

供大家学习使用,记录平时没怎么遇到的,但是实用的知识

1. 开发新业务流程

2. 枚举类中的注解

java 复制代码
public enum LessonStatus implements BaseEnum {
    NOT_BEGIN(0, "未学习"),
    LEARNING(1, "学习中"),
    FINISHED(2, "已学完"),
    EXPIRED(3, "已过期"),
    ;
    @JsonValue
    @EnumValue
    int value;
    String desc;

    LessonStatus(int value, String desc) {
        this.value = value;
        this.desc = desc;
    }

    @JsonCreator(mode = JsonCreator.Mode.DELEGATING)
    public static LessonStatus of(Integer value){
        if (value == null) {
            return null;
        }
        for (LessonStatus status : values()) {
            if (status.equalsValue(value)) {
                return status;
            }
        }
        return null;
    }
}

@JsonValue 表示返回给前端时候,是该注解之下的属性值

@EnumValue 表示在往数据库中存储的时候,先会转化为该注解之下的属性值再储存到数据库,该注解来自MP


3. 登录用户的传递

在微服务中,是多模块的分类,每个模块中间几乎相互独立,那么怎么将在当前模块登录的用户进行传递呢?答案就是使用JWT令牌,通过将用户信息封装的令牌中,然后解析令牌,获取到用户信息。

但是JWT令牌采用非对称加密,每次解析需要耗费时间,所以应该在controller之前就解析获取到用户,然后储存本地,每次需要登录用户信息只需要在本地获取,相对就很快。在controller请求执行业务之前执行的业务的是拦截器,因此需要编写拦截器进行对请求拦截。

又由于会有多个模块需要对用户进行拦截,存在多个模块都需要编写拦截器,出现重复编码,冗余。所以对拦截器进行抽取,抽取拦截器封装起来,只要引用依赖就可以执行拦截器。

复制代码
exchange.mutate()
        .request(builder -> builder.header(
                USER_HEADER, 
                r.getData().getUserId().toString()
)).build();

**过滤器:**其中表示添加请求头,键是USER_HEADER,值是UserId

java 复制代码
@Component
public class AccountAuthFilter implements GlobalFilter, Ordered {

    private final AuthUtil authUtil;
    private final AuthProperties authProperties;
    private final AntPathMatcher antPathMatcher = new AntPathMatcher();

    public AccountAuthFilter(AuthUtil authUtil, AuthProperties authProperties) {
        this.authUtil = authUtil;
        this.authProperties = authProperties;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 1.获取请求request信息
        ServerHttpRequest request = exchange.getRequest();
        String method = request.getMethodValue();
        String path = request.getPath().toString();
        String antPath = method + ":" + path;

        // 2.判断是否是无需登录的路径
        if(isExcludePath(antPath)){
            // 直接放行
            return chain.filter(exchange);
        }

        // 3.尝试获取用户信息
        List<String> authHeaders = exchange.getRequest().getHeaders().get(AUTHORIZATION_HEADER);
        String token = authHeaders == null ? "" : authHeaders.get(0);
        R<LoginUserDTO> r = authUtil.parseToken(token);

        // 4.如果用户是登录状态,尝试更新请求头,传递用户信息
        if(r.success()){
            exchange.mutate()
                    .request(builder -> builder.header(USER_HEADER, r.getData().getUserId().toString()))
                    .build();
        }

        // 5.校验权限
        authUtil.checkAuth(antPath, r);

        // 6.放行
        return chain.filter(exchange);
    }

    private boolean isExcludePath(String antPath) {
        for (String pathPattern : authProperties.getExcludePath()) {
            if(antPathMatcher.match(pathPattern, antPath)){
                return true;
            }
        }
        return false;
    }

    @Override
    public int getOrder() {
        return 1000;
    }
}

**拦截器:**其中没获取到用户id直接放行,因为这个拦截器不是登录拦截器,只是用户信息的拦截器,当没有用户信息代表该请求不需要传递用户信息。

java 复制代码
@Slf4j
public class UserInfoInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 1.尝试获取头信息中的用户信息
        String authorization = request.getHeader(JwtConstants.USER_HEADER);
        // 2.判断是否为空
        if (authorization == null) {
            return true;
        }
        // 3.转为用户id并保存
        try {
            Long userId = Long.valueOf(authorization);
            UserContext.setUser(userId);
            return true;
        } catch (NumberFormatException e) {
            log.error("用户身份信息格式不正确,{}, 原因:{}", authorization, e.getMessage());
            return true;
        }
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 清理用户信息
        UserContext.removeUser();
    }
}


/** 以下才是登录的拦截器 */
@Slf4j
public class LoginAuthInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 1.尝试获取用户信息
        Long userId = UserContext.getUser();
        // 2.判断是否登录
        if (userId == null) {
            response.setStatus(401);
            response.sendError(401, "未登录用户无法访问!");
            // 2.3.未登录,直接拦截
            return false;
        }
        // 3.登录则放行
        return true;
    }
}
相关推荐
Lhappy嘻嘻6 小时前
Java IO|File 文件操作 + 字节流 / 字符流完整笔记 + 递归删除文件实战
java·笔记·php
伊玛目的门徒6 小时前
试用leetcode之典中典 二数之和问题
java·算法·leetcode
懒鸟一枚9 小时前
深入理解 Linux 内存、Swap 交换分区与分页机制的关系
java·linux·数据库
我命由我1234511 小时前
执行 Gradle 指令报错,无法将“grep”项识别为 cmdlet、函数、脚本文件或可运行程序的名称
android·java·java-ee·android studio·android jetpack·android-studio·android runtime
考虑考虑11 小时前
Sentinel安装
java·后端·微服务
凤凰院凶涛QAQ12 小时前
《Java版数据结构 & 集合类剖析》栈与队列:“push/pop 是栈的灵魂,offer/poll 是队列的骨架——四组 API,两种人生”
java·开发语言·数据结构
掘金_答案13 小时前
上线那天,一个 ConcurrentHashMap 差点送走我的 AI 客服——3 天排查 JVM 血泪史
java·后端·架构
猿与禅14 小时前
CosId 分布式 ID 生成器完全教程:从架构原理到生产落地
java·shardingsphere·雪花算法·分布式id·高性能·cosid·号段模式
MindUp14 小时前
企业网盘权限模型解析:多层级访问控制与审计能力选型指南
java·linux·运维
NG47714 小时前
【软件设计与体系结构】-策略设计模式
java·设计模式·软件工程