文章目录
一、HandlerMethodArgumentResolver简介
直接看源码
/**
* 解析处理方法参数的类
*/
public interface HandlerMethodArgumentResolver {
/**
* 该方法的参数是否需要处理
*/
boolean supportsParameter(MethodParameter parameter);
/**
* 真正解析处理方法参数的地方
*/
@Nullable
Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;
}
二、使用步骤(分析@PathVariable )
1.自定义注解
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PathVariable {
/**
* Alias for {@link #name}.
*/
@AliasFor("name")
String value() default "";
/**
* The name of the path variable to bind to.
* @since 4.3.3
*/
@AliasFor("value")
String name() default "";
/**
* Whether the path variable is required.
* <p>Defaults to {@code true}, leading to an exception being thrown if the path
* variable is missing in the incoming request. Switch this to {@code false} if
* you prefer a {@code null} or Java 8 {@code java.util.Optional} in this case.
* e.g. on a {@code ModelAttribute} method which serves for different requests.
* @since 4.3.3
*/
boolean required() default true;
}
实现HandlerMethodArgumentResolver接口
/**
* Resolves {@link Map} method arguments annotated with an @{@link PathVariable}
* where the annotation does not specify a path variable name. The created
* {@link Map} contains all URI template name/value pairs.
*
* @author Rossen Stoyanchev
* @since 3.2
* @see PathVariableMethodArgumentResolver
*/
public class PathVariableMapMethodArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
PathVariable ann = parameter.getParameterAnnotation(PathVariable.class);
return (ann != null && Map.class.isAssignableFrom(parameter.getParameterType()) &&
!StringUtils.hasText(ann.value()));
}
/**
* Return a Map with all URI template variables or an empty map.
*/
@Override
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
@SuppressWarnings("unchecked")
Map<String, String> uriTemplateVars =
(Map<String, String>) webRequest.getAttribute(
HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST);
if (!CollectionUtils.isEmpty(uriTemplateVars)) {
return new LinkedHashMap<>(uriTemplateVars);
}
else {
return Collections.emptyMap();
}
}
}
三、实战演练
1.场景
我们在方法参数上经常需要接受用户的信息,比如用户的ID,然后根据用户的ID去数据库查询数据,如果直接拿前台传递的用户ID是不安全的,如果转递的别的用户的ID那么就可以看到别的用户的数据,正确的做法是后台接口中所有的用户信息,都应该获取当前登录的用户的信息(一般用户信息都会放在redis),前台传递的用户信息我们视为不安全的。
2.编写注解
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
public @interface RequestUserCode {
}
3.编写处理参数的类
@Service
public class RequestUserCodeArgumentResolver implements HandlerMethodArgumentResolver {
@Autowired
private RedisUtil redisUtil;
public RequestUserCodeArgumentResolver() {
}
public boolean supportsParameter(MethodParameter methodParameter) {
RequestUserCode annotation = (RequestUserCode)methodParameter.getParameterAnnotation(RequestUserCode.class);
return annotation != null;
}
public String resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {
//从redis获取用户信息
String id = nativeWebRequest.getHeader("user");
if (id != null) {
AuthUserInfo authUserInfoObj = this.redisUtil.getAuthUserInfo(id);
if (authUserInfoObj != null) {
return authUserInfoObj.getUserCode();
}
}
return null;
}
}
4.注册到spring mvc
@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {
@Autowired
private RequestUserCodeArgumentResolver requestUserCodeArgumentResolver;
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(requestUserCodeArgumentResolver);
}
/**
* 功能描述: 处理swagger不展示的问题
*/
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**").addResourceLocations(
"classpath:/static/");
registry.addResourceHandler("swagger-ui.html").addResourceLocations(
"classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**").addResourceLocations(
"classpath:/META-INF/resources/webjars/");
super.addResourceHandlers(registry);
}
}
5.使用
public Result<String> isPermission(@RequestUserCode String userCode) {
try {
return customerService.permission(customerCode);
} catch (OrderException e) {
return Result.error(e.getErrorCode(), e.getMsg());
}
}
总结
你的项目中有没有类似的需求呢,或者遇到一些问题用这种方式处理的话会更好,那就赶快动手试一下吧
欢迎打击关注我的微信公众号,您的关注就是我不懈的动力