目录
1.TenantKeyContext(ThreadLocal的工具类)
概述
实现的步骤如下:
- 将登录需要的信息塞入当前线程(ThreadLocal)。
- 使用拦截器拦截controller的请求,让ThreadLocal的信息保留。
- 将接收的request参数转化为body接收参数。(拦截器不支持接收body的参数)
- 在Serviceimpl调用ThreadLocal拿到信息。
实现效果
首先登陆信息是空的,通过body把登陆信息传递进去。
body中传入登陆所需要的信息,从而实现了登陆。
1.TenantKeyContext(ThreadLocal的工具类)
主要是创建一个本地线程。
public class TenantKeyContext{
private static final ThreadLocal<String> TENANT_KEY = new ThreadLocal<String>();
public static void setTenantKey(String tenantKey) {
TENANT_KEY.set(tenantKey);
}
public static String getTenantKey() {
return TENANT_KEY.get();
}
public static void remove(){
TENANT_KEY.remove();
}
}
2.WebMvcConfig注册拦截器
注册一个拦截器,然后拦截controller所有请求。
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebMvcConfigimplements WebMvcConfigurer {
@Bean
public WebMvcConfiggetMyWebMvcConfig(){
return new WebMvcConfig() {
//注册拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new TenantKeyInterceptor()).addPathPatterns("/**");
}
};
}
}
3.TenantKeyInterceptor拦截器
主要分为几个步骤:
- 使用getTenantKeyFromRequest将传递进来的request请求改为接收传入body请求,实现body传参。
- 调用TenantKeyContext工具类,传入request请求的参数。
- 使用完成之后将本地线程销毁掉。
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.weaver.front.monitor.util.common.TenantKeyContext;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
@Component
public class TenantKeyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
String tenantKey = getTenantKeyFromRequest(request);
TenantKeyContext.setTenantKey(tenantKey);
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
TenantKeyContext.remove();
}
/**
* 从request中获取tenantKey
* @param request
* @return
*/
public static String getTenantKeyFromRequest(HttpServletRequest request) {
String tenantKey = null;
StringBuilder sb = new StringBuilder();
try (InputStream inputStream = request.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
String line = "";
while ((line = reader.readLine()) != null) {
sb.append(line);
}
JSONObject jo = JSON.parseObject(sb.toString());
tenantKey = jo.getString("tenantKey");
} catch (Exception ignore) {
}
return tenantKey;
}
}
总结
这样就实现了,将登录信息或者需要的某一个信息塞入本地线程,然后在需要的Service层去调用。
但是这样就存在一个问题,就是如果调用的地方,拿到的是一个空的信息怎么办,需要抛出一个异常,每层都往上抛很麻烦,这就涉及到了全局异常的捕获,然后手动直接抛出异常。
详情见手动抛出异常全局捕获异常,手动抛出异常