简单的谈一下SpringMVC的工作流程

Scroll Down

简单的谈一下SpringMVC的工作流程

1.发送请求 Dispatcher(中央控制器)
2.调用 处理器映射器(HandlerMapping) 找到处理器
3.返回 HandlerExecutionChain
  包含:HandlerInterceptor(处理器拦截器)
       Handler(处理器对象)
4.通过 处理器适配器(HandlerAdapter) 调用具体的 处理器
5.调用处理器
6.返回ModelAndView
7.返回ModelAndView
8.视图解析器(ViewResolver)
9.返回view
10.渲染视图(view)
11.响应用户


SpringMVC工作流程图

image-1660472319493

  • 核心概念

    • 中央控制器 DispatcherServlet
    • 处理器映射器
    • 处理器拦截器
    • 处理器对象
    • 处理器适配器
    • 视图解析器
  • 核心类

    • org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
  • 源码分析

    • 通过debug追踪SpringMVC执行流程

    • 核心断点:

      • cn.wangzengqiang.interview.atguigu2019.javaee.spring.springmvc.handler.SpringMVCHandler.testMap 53行
      • org.springframework.web.servlet.DispatcherServlet.doDispatch 1101行,916行,923行,945行,959行,1012行,1204行,1225行,
      • org.springframework.web.servlet.view.AbstractView.render 257行, 266行, 374行
      • org.springframework.web.servlet.view.InternalResourceView.renderMergedOutputModel 173行,180行,189行,201行,209行
    • 核心断点图解

      • mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
        

      image-1660472382912

      • mappedHandler = getHandler(processedRequest);
        

      image-1660472400427

      • HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
        

      image-1660472416540

      • processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
        

      image-1660472434488

      • render(mv, request, response);
        

      image-1660472450523

      • view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);
        

      image-1660472470071

      • HandlerExecutionChain handler = hm.getHandler(request);
        

      image-1660472485820

      • renderMergedOutputModel(mergedModel, request, response);
        

      image-1660472506378

      • exposeModelAsRequestAttributes(model, requestToExpose);
        ...
        rd.include(requestToExpose, response);
        ...
        rd.forward(requestToExpose, response);
        

      image-1660472523154

      • request.setAttribute(modelName, modelValue);
        

    image-1660472541398

核心代码show

  • 代码结构图

image-1660472555961

  • springmvc.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
	
	<!-- 配置自动扫描到的包 -->
	<context:component-scan base-package="cn.wangzengqiang.interview.atguigu2019.javaee.spring.springmvc"></context:component-scan>
	
	<!-- 配置视图解析器 -->
	<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix" value="/WEB-INF/views/"></property>
		<property name="suffix" value=".jsp"></property>
	</bean>
	
	<!-- 配置不经过处理器方法直接到达响应页面 
		path属性:设置要映射请求地址
		view-name属性:设置视图名
	-->
	<mvc:view-controller path="/testViewResolver" view-name="success"/>
	<!-- 配置了不经过处理器方法直接到达响应页面之后,处理器方法上的@RequestMapping将失效,此时必须配置以下标签 -->
	<mvc:annotation-driven></mvc:annotation-driven>
</beans>

  • web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <!--
    解决post请求的请求乱码问题
    但是不能解决get请求乱码问题:
    1)修改server.xml找到Connector标签,加入URIEncoding="UTF-8"即可
    -->

    <!-- 设置CharacterEncodingFilter -->
    <filter>
        <filter-name>CharacterEncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <!-- 设置请求的字符集 -->
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
        <!-- 设置响应的字符集 -->
        <init-param>
            <param-name>forceEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>CharacterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <servlet>
        <servlet-name>springDispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>springDispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    <!-- 注册HiddenHttpMethodFilter,目的是为了将一个POST请求转换为PUT或者DELETE请求 -->
    <filter>
        <filter-name>HiddenHttpMethodFilter</filter-name>
        <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>HiddenHttpMethodFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>
  • SpringMVCHandler.java
@Controller
public class SpringMVCHandler {

    public static final String SUCCESS = "success";
    public static final String SUCCESS1 = "success1";

    //1.SpringMVC中如何解决POST请求中文乱码问题,GET的又如何处理呢

    /*
     * ★测试入参为POJO
     * Spring MVC会按请求参数名和 POJO属性名进行自动匹配,
     * 		    自动为该对象填充属性值。支持级联属性
     */
    @RequestMapping("/testPOJO")
    public String testPOJO(Employee employee) {
        System.out.println("员工的信息是:" + employee);
        return SUCCESS;
    }



    //1.简单的谈一下SpringMVC的工作流程

    //处理模型数据方式一:将方法的返回值设置为ModelAndView
    @RequestMapping("/testModelAndView")
    public ModelAndView testModelAndView() {
        //1.创建ModelAndView对象
        ModelAndView mav = new ModelAndView();
        //2.设置模型数据,最终会放到request域中
        mav.addObject("user", "admin");
        //3.设置视图
        mav.setViewName("success1");
        return mav;
    }
    /*
     * ★处理模型数据方式二:方法的返回值仍是String类型,在方法的入参中传入Map、Model或者ModelMap
     * 	不管将处理器方法的返回值设置为ModelAndView还是在方法的入参中传入Map、Model或者ModelMap,
     *  SpringMVC都会转换为一个ModelAndView对象
     */
    @RequestMapping("/testMap")
    public String testMap(Map<String , Object> map) {
        //向Map中添加模型数据,最终会自动放到request域中
        map.put("user", new Employee(1, "工一", "gongyi@wangzengqiang.cn", new Department(101, "教学部")));
        return SUCCESS1;
    }
}
  • success1.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h1>Success Page</h1>
	<h2>request域中的用户是:${requestScope.user }</h2>
</body>
</html>
  • index1.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
	<a href="${pageContext.request.contextPath }/testModelAndView">Test ModelAndView</a><br>
	<a href="${pageContext.request.contextPath }/testMap">Test Map</a><br>
</body>
</html>