本文主要介绍SpringMVC对Controller
中对外方法的参数的解析接口HandlerMethodArgumentResolver
,包括如下说明:
该接口在:org.springframework.web.method.support.HandlerMethodArgumentResolver
中,有2个核心方法:
public interface HandlerMethodArgumentResolver {
/**
* true:表示支持,调用下面的:resolveArgument() 方法。
*/
boolean supportsParameter(MethodParameter parameter);
/**
* 如何处理 这个方法参数。
* 重点:该返回值为Controller层中对外方法对外形参的值。[结合后续]
*/
@Nullable
Object resolveArgument(MethodParameter parameter,
@Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest,
@Nullable WebDataBinderFactory binderFactory) throws Exception;
这2个参数如何理解?
我们可以结合官方实现来看看。
我们先来看一个需求,当前Controller
层需要获取到某个cookie
的值,如何做?
@Controller
public class HelloWorldController {
/**
* 通过注解:@CookieValue(value="JSESSIONID") 就可以获取到!
* 但是你思考过为什么没有?
*/
@RequestMapping("/mic/cookie")
public void cookieTest(@CookieValue(value="JSESSIONID")String sessionId) {
System.out.println("通过@CookieValue获得JSESSIONID:"+sessionId);
}
Spring MVC在处理的时候,会将Controller层中每一个对外的方法的形参进行审核
(姑且这么形容),然后赋值
.
其利用的就是HandlerMethodArgumentResolver
这个处理类,接下来我们看看官方对于@CookieValue
的实现。
public abstract class AbstractCookieValueMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {
/**
* 第一个方法,参数匹配,如果为true表示可以执行后续
*/
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(CookieValue.class);
}
}
这个resolveArgument在其父类中,方法比较长,一个一个来看
@Override
@Nullable
public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
NamedValueInfo namedValueInfo = getNamedValueInfo(parameter);
MethodParameter nestedParameter = parameter.nestedIfOptional();
// 获取 cookie 对应的名称 jsessionId
Object resolvedName = resolveStringValue(namedValueInfo.name);
.....
// 获取jessionId对应的值,如果获取到,通常该流程就返回了
Object arg = resolveName(resolvedName.toString(), nestedParameter, webRequest);
if (arg == null) {
if (namedValueInfo.defaultValue != null) {
// 解析为默认值
arg = resolveStringValue(namedValueInfo.defaultValue);
}
else if (namedValueInfo.required && !nestedParameter.isOptional()) {
// 解析没有默认值,那么解析为 MissingValue
handleMissingValue(namedValueInfo.name, nestedParameter, webRequest);
}
// 最后进行nullValue处理。
arg = handleNullValue(namedValueInfo.name, arg, nestedParameter.getNestedParameterType());
}
else if ("".equals(arg) && namedValueInfo.defaultValue != null) {
arg = resolveStringValue(namedValueInfo.defaultValue);
}
return arg;
}
该处理器同名称一样,处理的是Argument
所以我们很容易猜到,当我们需要在Controller对外的方法中注入某个形参的时候,可以通过该接口进行处理。
比如很典型的例子:解析HTTP请求中的CookieId,通过Id从缓存中获取用户信息。
传统的方法可以从HttpServletRequest中获取并解析,但是如果很多地方都这么去写不利于代码维护,所以可以进行统一处理。
首先定义一个类MicUserArgumentResolver
来实现接口HandlerMethodArgumentResovler
@Component
public class MicUserArgumentResolver implements HandlerMethodArgumentResolver {
/**
* 通过返回值判定是否支持参数.
* 虽然没有查看源码,但是应该是将每个参数获取后进行处理的。
*/
@Override
public boolean supportsParameter(MethodParameter methodParameter) {
Class<?> parameterType = methodParameter.getParameterType();
return parameterType == MicUser.class;
}
@Override
public Object resolveArgument(MethodParameter methodParameter,
ModelAndViewContainer modelAndViewContainer,
NativeWebRequest nativeWebRequest,
WebDataBinderFactory webDataBinderFactory) {
//获取HttpServletRequest
HttpServletRequest request =
nativeWebRequest.getNativeRequest(HttpServletRequest.class);
//获取HttpServletResponse
HttpServletResponse response =
nativeWebRequest.getNativeResponse(HttpServletResponse.class);
String paramToken = request.getParameter("jessionId");
......
return new MicUser();
}
然后将这个参数解析器注入上下文,需要利用WebMvcConfigurer
这个类
@Configuration
public class CustomWebConfigure implements WebMvcConfigurer {
@Autowired
private MicUserArgumentResolver micUserArgumentResolver;
/**
* 参数处理:可以通过实现 HandlerMethodArgumentResolver 来解析"通用"的参数<br>
* 比如典型的案例就是通过参数中的cookie获取到用户对象
*
* @param resolvers
*/
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(micUserArgumentResolver);
}
}
然后在Controller的形参中注入试用
@RestController
public class TestController {
@GetMapping("/mic/user")
public MicUser micUser(MicUser micUser, String xx) {
return micUser;
}
}
大功告成!!!
其实后续几篇文章都会结合:WebMvcConfigurer
里面的接口方法进行讲解,欢迎收藏!