SpringMVC如何获取登陆用户信息

说到Java web,那么在web端获取登陆用户信息几乎是所有系统都需要实现的功能,下面我们就来讲一下几种获取登陆用户信息的方法。

从session中获取

这是我们刚刚接触Java web时就了解的一种解决方案,配置一个登陆过滤器或者登陆拦截器,在用户登陆的时候将用户信息放到session中,然后控制层在session中取出用户信息,这是最简单也是最常见的一种解决方案。

随着用户量的增大,单部署的服务往往不能满足我们的需求,这时候往往我们会引入集群来分摊服务器的压力。但是引入集群后,从session中存取用户信息就会变得不那么靠谱了。

大家都知道session是存在服务端的,那么如果用户在集群机器A中登陆,用户信息就存储在了机器A上,此时如果用户新的请求被分发到集群机器B上,就无法获取用户信息了。

这是集群情况下用户信息被存储在集群中的单个服务器上导致的,解决方案主要有两种:
- 让用户后续的所有请求都分发到用户登陆的那台机器
- 把用户信息存储在缓存中间件中,而不是集群中的每个服务器上

第一种方案可以在代理服务器(apache,nginx等)上配置session黏着,这样就能保证用户后续请求都会被路由到同一台机器上,这就解决了集群情况下拿不到用户信息的问题了。

当然,对ip进行hash算法使某一个用户的请求永远随机到某一台机器上也是一种思路。

从缓存中间件获取

从缓存中间件获取,就是把用户信息存储在缓存中间件中,控制层直接从缓存中间件中获取用户信息。

用户在登陆成功后,会生成一个token,然后以token为键,用户信息为值存储在缓存中间件中,并且把token发送到页面端。

页面端向服务端发送请求的时候带上这个token,服务端控制层可以根据这个token从缓存中间件中获取用户信息。

在集群情况下,用户信息还是存储在一个独立出来的缓存服务器上,这样就可以避免获取不到用户信息的问题了。


以上两种方法就是获取登陆用户信息的两种主要解决方案了,这里再从代码层面上给出一个小分享。

不论是从session中获取还是从缓存中间件中获取用户信息,不可避免的是在控制层需要显式的去获取用户

User user = (User)session.get("login_user");

或者

User user = (User)redisService.get(token);

几乎每个控制层方法都需要执行上面的语句获取一下用户信息,着就会显得很罗嗦,所以下面给出一个小分享来使用注解和HandlerMethodArgumentResolver结合优化控制层代码。

我们先来了解一下HandlerMethodArgumentResolver, SpringMvc中的HandlerAdapter会检测所有的 HandlerMethodArgumentResolver,对参数进行处理和加工。

这样,我们就可以自定义一个HandlerMethodArgumentResolver,读取请求中的token,根据token获取到用户信息,将用户信息通过自定义注解的方式传递到控制层。

没错,这个小分享是基于SpringMVC的,下面给出详细代码。

  • 首先自定义一个注解,用来传递用户信息
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface Logined {

}
  • 自定义一个HandlerMethodArgumentResolver,用来获取用户信息
public class LoginedArgumentResolver implements HandlerMethodArgumentResolver {

    private RedisService<String, Object> redisService;

    public LoginedArgumentResolver(RedisService<String, Object> redisService) {
        this.redisService = redisService;
    }

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        if (parameter.getParameterAnnotation(Logined.class) != null
                && parameter.getParameterType() == LoginUser.class) {
            // 如果该参数注解有@Logined才会执行下面的resolveArgument方法
            return true;
        }
        return false;
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
            NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        HttpServletRequest request = (HttpServletRequest) webRequest.getNativeRequest();
        String accessToken = request.getHeader(LocalConstant.ACCESS_TOKEN_KEY);
        LoginUser loginUser = (LoginUser)redisService.get(LocalConstant.REDIS_LOGIN_USER_KEY + accessToken);
        return loginUser;
    }
}
  • 控制层获取用户信息
@GetMapping("/getLoginUser")
public LoginUser addCouple(@Logined LoginUser loginUser){
    return loginUser;
}

通过上面的Logined注解和LoginedArgumentResolver结合,在控制层中需要获取用户信息,若需要在参数中添加@Logined就可以了,是不是简单了很多呢,希望今天的分享可以给大家带来帮助。

扫码关注,不迷路
扫码关注

猜你喜欢

转载自blog.csdn.net/Leon_cx/article/details/81058504