这里讲一个很强大的线程数据传递功能, 可以controller、service甚至dao、静态util工具类里面,不通过参数,可以得到用户的登录会话方法。
h5或者rest接口端,经常会通过filter和公共的控制器,来得到本次会话得到用户的登录对象user以及request信息,但是很多在service里面、公共工具类里面,又想要根据当前登录用户来获取相关数据,但是又不得不传参。
Thread.currentThread()
这里利用java一个请求一条线程贯穿整个业务的原理,得到当前线程对象,通过一个中转的静态发放,来实现
比如用户User.class,来参考一个实例
你可能觉得这个地方有啥用,我传个参数不就好了嘛~~~之前我也是这么想的,多个参数嘛,不影响啥。
但是后来业务场景越来越多的时候,我发现了这个方式的妙用,比如我在某一次请求中,根据敏感操作次数来记录日志,但是我怎么得到这个用户的敏感操作次数呢?方法体有业务参数,返回有固定对象,但是我却要根据是否执行了此方法来进行判断用户是否进行过敏感操作,那么,这里利用点就来了。
~~
可能说的有点模糊,也没有想到确切的使用场景,总之一句话:在方法参数和返回值以外,我还可以在多个方法间进行数据传递。
以后会碰上业务场景的,这里丢下代码
/**
* @describe:处理用户session 的操作
* @author: jiahong.xing/
* @version: v1.0
* @date 2019/1/315:47
*/
public class SessionUserUtil {
/**
* 专用
*/
//用来存放登录用户的一个全局map
private static Map threadMap = Collections.synchronizedMap(new HashMap());
public static void set(Object object) {
if (null == object) {
return;
}
threadMap.put(Thread.currentThread(), object);
}
public static <T> T get() {
Thread currentThread = Thread.currentThread();
Object obj = threadMap.get(currentThread);
if (obj == null && !threadMap.containsKey(currentThread)) {
obj = initialValue();
threadMap.put(currentThread, obj);
}
return (T) obj;
}
public static void remove() {
threadMap.remove(Thread.currentThread());
}
private static Object initialValue() {
return null;
}
public static User getUser() {
User user = get();
if (null != user) {
try {
user = SystemConstant.baseService.get(User.class, user.getId());
} catch (Exception e) {
e.printStackTrace();
}
}
return user;
}
//直接从缓存获取
public static User getSessionUser() {
User user = get();
return user;
}
}
利用一个静态工具类,在公共的Filter里面进行写入以及数据销毁。这里用User对象作为代表,可以任意对象,比如JOSN、List、Map等对象。
但是这里涉及到一个公共静态的Map对象,这个对象会在老年代甚至持久代里面一直占用内存,会不会越来越大导致内存溢出?
/**
* @param request
* @param response
* @param chain
*/
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
//得到当前用户
User user = (User) httpServletRequest.getSession().getAttribute(SystemConstant.session_name);
//保存进入
SessionUserUtil.set(user);
try {
chain.doFilter(request, response);
}finally {
//销毁线程数据
SessionUserUtil.remove();
}
}
这种做法有没有问题?放心,没问题的。上面得到当前用户这一方法,可以在任意地方(这里是过滤器里面)
还比如
当然,有写入就肯定要进行销毁,销毁往往是放在请求的必经之路里面,及时是报错了也会进行销毁,不会让map进行一直增长下去,如果不知道什么地方会写入,那么就直接放在过滤器里面,用finaly进行统一销毁
User user = SessionUserUtil.getUser();
这种类似的方法使用的场景太多了,不需要传参,不需要某个方法改变了对象需要返回,不用request,直接得到当前登录用户进行数据操作。比如shiro,我们项目没有用他,所有功能全部手写自定义实现
也许暂时没有找到场景,但是记录下来总会用到的
有安全问题、性能问题都可以找我探讨,QQ1121076248