目录

前言

Spring 项目的企业开发中,在 Controller 层的某一个方法中获取当前登录人的信息是一个非常常见的需求,比如你可以根据当前登录人信息判断是否有操作权限、记录操作日志等等,但是如何更好、更简单的获取到该信息?今天就教大家一个使用自定参数解析器来完成的获取登录人(使用Cookie+Session)的方法,主要分享思路。

SpringBoot实战 - 自定参数解析器自动注入已登录用户

期望

我们以查看当前登录人画像信息为例,看看我们所期望的获取方式。

画像接口定义:

package cn.notemi.demo.controller;

import cn.notemi.demo.annotations.LoginAuth;
import cn.notemi.demo.annotations.ResponseResult;
import cn.notemi.demo.model.bo.LoginUser;
import cn.notemi.demo.model.po.User;
import cn.notemi.demo.model.qo.LoginQO;
import cn.notemi.demo.model.vo.LoginVO;
import cn.notemi.demo.repository.UserRepository;
import cn.notemi.demo.service.LoginService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.Date;
import java.util.List;
import java.util.UUID;

/**
 * Title:UserController
 **/
@RestController
@RequestMapping("/api/user")
@ResponseResult
public class UserController {

    @Autowired
    private UserRepository userRepository;

    @GetMapping("/mine")
    @LoginAuth
    public LoginUser mine(LoginUser loginUser) {
        return loginUser;
    }

}

备注

期望只需要在 Controller 方法上使用 LoginUser loginUser 这个对象类作为参数,便可以自动获取到登录人信息

同时在当前方法或类上需增加 @LoginAuth 注解,该注解是代表该方法访问时用户必须是在登录状态下(如果不清楚该功能怎么实现,可以看下这篇文章 SpringBoot 实战 - 拦截器+自定义注解实现接口的登录校验

PostMan调用截图

SpringBoot实战 - 自定参数解析器自动注入已登录用户

代码实现

现在我们来说下本篇文章的重头戏,HandlerMethodArgumentResolver 接口,在 spring mvc 中用于处理方法参数的解析,其下仅仅有两个方法

//根据方法参数判断是否需要对其做转换
boolean supportsParameter(MethodParameter parameter);
//supportsParameter方法返回true后,进入该方法,返回值即为要转化对象的结果
Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,  
            NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception;  

可能你还不是特别清楚,下面我们以上述功能的实现,看看这个类在具体功能上的使用

登录用户参数解析器

package cn.notemi.demo.resolver;

import cn.notemi.demo.annotations.LoginAuth;
import cn.notemi.demo.helper.LoginTokenHelper;
import cn.notemi.demo.model.bo.LoginUser;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import java.lang.reflect.Method;

/**
 * @desc 登录用户参数解析器
 */
@Slf4j
public class LoginUserArgumentResolver implements HandlerMethodArgumentResolver {

    //根据方法参数判断是否需要对其做转换
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        final Method method = parameter.getMethod();
        final Class<?> clazz = parameter.getMethod().getDeclaringClass();

        boolean isHasLoginAuthAnn = clazz.isAnnotationPresent(LoginAuth.class) || method.isAnnotationPresent(LoginAuth.class);
        boolean isHasLoginUserParameter = parameter.getParameterType().isAssignableFrom(LoginUser.class);

        return isHasLoginAuthAnn && isHasLoginUserParameter;
    }

    //supportsParameter方法返回true后,进入该方法,返回值即为要转化对象的结果
    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        return LoginTokenHelper.getLoginUserFromRequest();
    }
}

备注

可以看到在方法 supportsParameter 中有 isHasLoginAuthAnn 和 isHasLoginUserParameter 参数,代表着当前方法或类上有 @LoginAuth 注解并且有 LoginUser 这个类型的参数时进行转化。

在 resolveArgument 中仅仅只有一句 LoginTokenHelper.getLoginUserFromRequest(),这个其实是我们早在拦截器层就已经把用户的登录信息放入request中了,所以现在直接通过该类获取登录用户信息即可,具体的实现逻辑,可以看 SpringBoot 企业实战 - 拦截器+自定义注解实现接口的登录校验

配置自定义解析器

package cn.notemi.demo.config;

import cn.notemi.demo.resolver.LoginUserArgumentResolver;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

import java.util.List;

/**
 * 配置自定义解析器
 */

@Configuration
public class ArgumentResolverConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
        argumentResolvers.add(new LoginUserArgumentResolver());
    }

}

GitHub地址:https://github.com/FlickerMi/notemi-demo