mockRequest构建request请求
private static HttpServletRequest mockRequest(){
MockHttpServletRequest request = new MockHttpServletRequest();
request.setParameter("name1","zhangsan");
request.setParameter("name2","lisi");
request.setParameter("age","18");
return new StandardServletMultipartResolver().resolveMultipart(request);
}
定义controller
static class Controller{
public void test(
@RequestParam("name1") String name1,
String name2,
@RequestParam("age") int age,
@RequestParam(value = "home",defaultValue = "${JAVA_HOME}") String home1
){
}
}
解析过程
public static void main(String[] args) throws Exception {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(WebConfig.class);
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
HttpServletRequest multiRequest = mockRequest();
// 控制器方法封装为 handlerMethod
HandlerMethod handlerMethod = new HandlerMethod(new Controller(),Controller.class.getMethod("test", String.class, String.class, int.class,String.class));
// 数据绑定工厂
DefaultDataBinderFactory factory = new DefaultDataBinderFactory(null);
// ModelAndViewContainer 存储Model结果.
ModelAndViewContainer container = new ModelAndViewContainer();
// 拿到当前控制器方法得参数信息
for (MethodParameter methodParameter : handlerMethod.getMethodParameters()) {
// 创建解析器对象 -> 是在HandlerMethodAdapter中
RequestParamMethodArgumentResolver resolver = new RequestParamMethodArgumentResolver(beanFactory,false);
// 拿到当前的参数
methodParameter.initParameterNameDiscovery(new DefaultParameterNameDiscoverer());
// 当前解析器支持这个参数进行处理 如果标注了@RequestParam注解从请求参数里找到对应的信息
if (resolver.supportsParameter(methodParameter)) {
Object v = resolver.resolveArgument(methodParameter,container,new ServletWebRequest(multiRequest),factory);
System.out.println("[" + methodParameter.getParameterIndex() + "]" + methodParameter.getParameterType().getSimpleName() + " " + methodParameter.getParameterName() + "->" + v);
}else{
System.out.println("[" + methodParameter.getParameterIndex() + "]" + methodParameter.getParameterType().getSimpleName() + " " + methodParameter.getParameterName());
}
}
}
通过handlerMethod.getMethodParameters拿到方法对应的全部的参数,然后对参数内容进行解析,
RequestParamMethodArgumentResolver用来解析@RequestParam注解;
首先通过supportsParameter看当前参数是否满足解析要求;
如果满足则进行参数解析赋值;resolver.resolveArgument
使用组合解析器进行优化
每个参数的解析需要用到不同的参数解析器,那么我们可以定义一个组合的参数解析器,进行解析时逐个去解析我们组合解析器中参数解析找到满足的一个然后进行解析。
// 创建解析器组合对象内部会循环找到当前参数满足的解析器进行解析
HandlerMethodArgumentResolverComposite composite = new HandlerMethodArgumentResolverComposite();
composite.addResolvers(
new RequestParamMethodArgumentResolver(beanFactory,false), // 解析@RequestParam
new PathVariableMethodArgumentResolver(), // 解析@PathVariable
new RequestHeaderMethodArgumentResolver(beanFactory), // 解析 @RequestHeader
new ServletCookieValueMethodArgumentResolver(beanFactory), // 解析@Cookie()
new ExpressionValueMethodArgumentResolver(beanFactory) // 解析@Value
new ServletModelAttributeMethodProcessor(false), // 必须有@ModelAttribute注解
new RequestResponseBodyMethodProcessor(List.of(new MappingJackson2HttpMessageConverter())), // @RequestBody 解析json
new ServletModelAttributeMethodProcessor(true) // 可以不加@ModelAttribute注解
// 其中ModelAttribute注解作用主要是用来将请求中的数据映射为一个Java对象.
);
// 拿到当前的参数
methodParameter.initParameterNameDiscovery(new DefaultParameterNameDiscoverer());
// 当前解析器支持这个参数进行处理 如果标注了@RequestParam注解从请求参数里找到对应的信息
if (composite.supportsParameter(methodParameter)) {
Object v = composite.resolveArgument(methodParameter,container,new ServletWebRequest(multiRequest),factory);
System.out.println("[" + methodParameter.getParameterIndex() + "]" + methodParameter.getParameterType().getSimpleName() + " " + methodParameter.getParameterName() + "->" + v);
}else{
System.out.println("[" + methodParameter.getParameterIndex() + "]" + methodParameter.getParameterType().getSimpleName() + " " + methodParameter.getParameterName());
}
request请求的设置
private static HttpServletRequest mockRequest(){
MockHttpServletRequest request = new MockHttpServletRequest();
request.setParameter("name1","zhangsan");
request.setParameter("name2","lisi");
Map<String,String> map = new AntPathMatcher().extractUriTemplateVariables("/test/{id}","/test/123");
request.setAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, map);
request.setParameter("age","18");
return new StandardServletMultipartResolver().resolveMultipart(request);
}
controller中的设置
static class Controller{
public void test(
@RequestParam("name1") String name1,
String name2,
@RequestParam("age") int age,
@RequestParam(value = "home",defaultValue = "${JAVA_HOME}") String home1,
@PathVariable("id") int id,
@RequestHeader("Content-Type") String header,
@CookieValue("token") String token,
@Value("${JAVA_HOME}") String home2,
@ModelAttribute User user // name=zhangsan&age=18
@RequestBody User user3 // json
){
}
}
controller中执行器方法参数名的获取
- javac编译java文件之后生成的.class文件中,方法得参数名会被替换为var 1 var 2
例如·
public void foo(String name,int age){
}
编制之后
public void foo(String var1,int var2){
}
编译时使用javac -parameters .\Bean2.java
加了这个之后编制之后的methodParameters会被保存起来;
对于这种方式可以通过反射来获取参数名
javac -g .\Bean2.java
使用这个命令编译。
会多出一个localVariableTable记录
对于这种情况需要ASM获取。