Spring MVC 自定义参数注解与解析

后台管理系统经常需要在Handler中获取已登录的用户信息,登录用户的存储可能是存于session或redis,那么如何让Handler快速获取用户信息且无需关心用户数据存放于何处,甚至后续登录用户数据存放的迁移也无需变动Handler。期望达到的效果如下:

@PostMapping("/user/getUserInfo")
@ResponseBody
public ResponseVO<UserInfo> getUserInfo(@Login UserInfo userInfo) {
	ResponseVO<UserInfo> responseVO = new ResponseVO<>();
	responseVO.setBizObj(userInfo);
	return responseVO;
}

那么如何实现上述效果呢?

1、定义自己的注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author katasea
 * 2020/5/18 17:43
 */

@Target(ElementType.PARAMETER)//表示此注解用于参数
@Retention(RetentionPolicy.RUNTIME)
public @interface Login {
}

2、编写解析自定义ArgumentResolver

本文使用的用户对象UserInfo读者无需关心,具体替换为自己的用户类即可

import com.health.bean.po.Login;
import com.health.bean.po.UserInfo;
import com.health.util.Global;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.MethodParameter;
import org.springframework.data.redis.core.RedisTemplate;
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 javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

/**
 * @author katasea
 * 2020/6/5 10:38
 */
@Configuration
public class LoginHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {
	//这里用户对象放于redis,根据实际场景自行调整
	@Resource
	private RedisTemplate<String,Object> redisTemplate;

	private Logger logger = LoggerFactory.getLogger(this.getClass());
	//判断当注解为Login时且用户对象为UserInfo【可替换为自己的对象】,才进行解析
	@Override
	public boolean supportsParameter(MethodParameter methodParameter) {
		return (null != methodParameter.getParameterAnnotation(Login.class) && UserInfo.class == methodParameter.getParameterType());
	}

	//如何获取当前登录用户的具体实现
	@Override
	public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {
		HttpServletRequest request = (HttpServletRequest) nativeWebRequest.getNativeRequest();
		try{ 
			UserInfo userInfo = (UserInfo) redisTemplate.opsForValue().get(request.getAttribute(Global.TOKEN));
			return userInfo;
		}catch (Exception e) { 
			return null;
		}
	}
}

3、增加拦截器配置

以下提供SpringBoot拦截器配置项

import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

import javax.annotation.Resource;
import java.util.List;

/**
 * @author katasea
 * 2020/5/12 13:48
 */
@Configuration
public class InterceptorConfig extends WebMvcConfigurationSupport {
		@Resource
		LoginHandlerMethodArgumentResolver userArgumentResolver; 
	
		//若已经存在拦截器配置,则只需增加以下方法即可。
		@Override
		public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
			argumentResolvers.add(userArgumentResolver);
		}
}

4、Handler尝试获取登录用户对象

//页面请求入参为空
@PostMapping("/user/getUserInfo")
@ResponseBody
public UserInfo getUserInfo(@Login UserInfo userInfo) { 
	return userInfo;
}

你可能感兴趣的:(技术分享)