03-MVC执行流程-参数解析与Model

重要组件



准备Model,Controller

java 复制代码
@Configuration
public class WebConfig {

    @ControllerAdvice
    static class MyControllerAdvice {

        @ModelAttribute("b")
        public String bar() {
            return "bar";
        }

    }

    @Controller
    static class Controller1 {

        @ResponseStatus(HttpStatus.OK)  // 添加此注解  这里不测试返回值处理器
        public ModelAndView foo(@ModelAttribute("u") User user) {
            System.out.println("Controller1.foo");
            System.out.println("user = " + user);
            return null;
        }

    }

    @Data
    static class User {
        private String name;
    }
}

准备参数解析器

java 复制代码
private static HandlerMethodArgumentResolverComposite argumentResolverComposite(AnnotationConfigApplicationContext annotationConfigApplicationContext) {
        DefaultListableBeanFactory beanFactory = annotationConfigApplicationContext.getDefaultListableBeanFactory();
        HandlerMethodArgumentResolverComposite resolverComposite = new HandlerMethodArgumentResolverComposite();
        resolverComposite.addResolvers(
                // @RequestParam参数解析器       false表示参数上必须有注解才会解析
                new RequestParamMethodArgumentResolver(beanFactory, false),
                // @PathVariable
                new PathVariableMethodArgumentResolver(),
                // @RequestHeader
                new RequestHeaderMethodArgumentResolver(beanFactory),
                // @CookieValue
                new ServletCookieValueMethodArgumentResolver(beanFactory),
                // Spring表达式参数解析器
                new ExpressionValueMethodArgumentResolver(beanFactory),
                // HttpServletRequest
                new ServletRequestMethodArgumentResolver(),
                // 是否不需要注解@ModelAttribute false:需要  即没有@ModelAttribute的实体参数不解析
                new ServletModelAttributeMethodProcessor(false),
                // @RequestBody
                new RequestResponseBodyMethodProcessor(CollUtil.newArrayList(new MappingJackson2HttpMessageConverter())),
                /**
                 *是否不需要注解@ModelAttribute true:不需要  即没有@ModelAttribute的实体参数也解析
                 * 注意!!!  这个解析器必须放在@RequestBody解析器后面,否则这个解析器将会优先被使用去解析
                 */
                new ServletModelAttributeMethodProcessor(true),
                /**
                 * @RequestParam 参数解析器 true表示参数上没有注解也会解析
                 * 注意!!!  这个解析器必须放在后面 否则其它类型参数将使用这个解析器解析
                 */
                new RequestParamMethodArgumentResolver(beanFactory, true)
        );
        return resolverComposite;
    }

测试MVC流程

java 复制代码
// 1. 准备容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(WebConfig.class);

// 2. 准备RequestMappingHandlerAdapter  测试:获取模型工厂并获取初始化时配置在ControllerAdvice中的模型数据
RequestMappingHandlerAdapter requestMappingHandlerAdapter = new RequestMappingHandlerAdapter();
requestMappingHandlerAdapter.setApplicationContext(applicationContext);
requestMappingHandlerAdapter.afterPropertiesSet();
Method getModelFactoryMethod = RequestMappingHandlerAdapter.class.getDeclaredMethod("getModelFactory", HandlerMethod.class, WebDataBinderFactory.class);
getModelFactoryMethod.setAccessible(true);

// 3. 准备请求
MockHttpServletRequest mockHttpServletRequest = new MockHttpServletRequest();
mockHttpServletRequest.setParameter("name", "zhoujunlin");
ServletWebRequest servletWebRequest = new ServletWebRequest(mockHttpServletRequest);

// 4. 准备servletInvocableHandlerMethod
ServletInvocableHandlerMethod servletInvocableHandlerMethod = new ServletInvocableHandlerMethod(new Controller1(), Controller1.class.getDeclaredMethod("foo", WebConfig.User.class));
// 这里没有特殊参数绑定  入参传null
ServletRequestDataBinderFactory servletRequestDataBinderFactory = new ServletRequestDataBinderFactory(null, null);
servletInvocableHandlerMethod.setDataBinderFactory(servletRequestDataBinderFactory);
servletInvocableHandlerMethod.setParameterNameDiscoverer(new DefaultParameterNameDiscoverer());
servletInvocableHandlerMethod.setHandlerMethodArgumentResolvers(argumentResolverComposite(applicationContext));
// 暂不研究返回值处理器

// 5. 准备ModelAndViewContainer容器
ModelAndViewContainer modelAndViewContainer = new ModelAndViewContainer();

// 6. 获取模型工厂并初始化模型数据
ModelFactory modelFactory = (ModelFactory) getModelFactoryMethod.invoke(requestMappingHandlerAdapter, servletInvocableHandlerMethod, servletRequestDataBinderFactory);
modelFactory.initModel(servletWebRequest, modelAndViewContainer, servletInvocableHandlerMethod);

// 7. 方法执行
servletInvocableHandlerMethod.invokeAndHandle(
        servletWebRequest,
        modelAndViewContainer);

System.out.println("modelAndViewContainer.getModel() = " + modelAndViewContainer.getModel());

// 8. 关闭容器
applicationContext.close();
相关推荐
架构源启6 小时前
文档接入与智能解析:基于 Spring AI 1.1.x 的多格式解析、版面理解与结构化抽取
java·人工智能·spring
大模型码小白10 小时前
JAVA 集合框架进阶:List 与 Set 的深度解析与实战
java·开发语言·人工智能·windows·语言模型·list·ai编程
名字还没想好☜10 小时前
Go 的 time.Ticker 陷阱:定时任务里被忽略的内存泄漏与正确关闭
java·数据库·golang·go·定时器
音符犹如代码11 小时前
后端视角看 EventBus:发布订阅总线的原理、场景与用法
java·spring boot·guava
前端炒粉11 小时前
手撕小汇总
java·前端·javascript
唐青枫11 小时前
Java Kafka 实战指南:从 Topic、分区到 Spring Boot 可靠消息处理
java
脱胎换骨-军哥12 小时前
C++零成本抽象理论深度拆解:现代C++如何在不牺牲性能的前提下提供高级语法封装
java·开发语言·c++
我是唐青枫13 小时前
Java Netty 实战指南:从 NIO 线程模型到 TCP 编解码和心跳机制
java·tcp/ip·nio
小白说大模型13 小时前
从向量嵌入到复杂 Agent:LLM、LangChain、LangGraph 完整科普
java·开发语言·人工智能·gpt·深度学习·langchain
风起洛阳@不良使14 小时前
springIOC创建对象的方式--spring容器中的注入
java·spring