目录
[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;
}
}