Notas de SpringMVC para aprender SSM rápidamente

Directorio de artículos

1. Introducción a SpringMVC

1. ¿Qué es MVC?

MVC es una idea de arquitectura de software que divide el software en modelos, vistas y controladores.

M: Modelo, capa de modelo, se refiere a JavaBean en el proyecto, su función es procesar datos

Los JavaBeans se dividen en dos categorías:

  • Un tipo se denomina beans de entidad: se utilizan específicamente para almacenar datos comerciales, como estudiantes, usuarios, etc.
  • Un tipo se llama beans de procesamiento de negocios: se refiere a objetos de Servicio o Dao, que se utilizan especialmente para procesar la lógica de negocios y el acceso a datos.

V: Vista, capa de vista, se refiere a las páginas html o jsp del proyecto, su función es interactuar con los usuarios y mostrar datos.

C: Controlador, capa de control, se refiere al servlet en el proyecto, que se utiliza para recibir solicitudes y responder al navegador.

Flujo de trabajo MVC:
el usuario envía una solicitud al servidor a través de la capa de vista. La solicitud es recibida por el Controlador en el servidor. El Controlador llama a la capa Modelo correspondiente para procesar la solicitud. Después del procesamiento, el resultado se devuelve al Controlador. Luego, el Controlador encuentra la Vista correspondiente según el resultado del procesamiento de la solicitud Vista, después de representar los datos, la respuesta final se envía al navegador.

2. ¿Qué es SpringMVC?

SpringMVC es un producto de seguimiento de Spring y un subproyecto de Spring

SpringMVC es un conjunto completo de soluciones proporcionadas por Spring para el desarrollo de la capa de presentación. Después de que el marco de la capa de presentación haya pasado por sucesivas generaciones de productos como Strust, WebWork y Strust2, la industria generalmente ha elegido SpringMVC como la solución preferida para el desarrollo de la capa de presentación de proyectos Java EE .

Nota: La arquitectura de tres niveles se divide en capa de presentación (o capa de presentación), capa de lógica empresarial y capa de acceso a datos. La capa de presentación representa la página principal y el servlet de fondo.

3. Características de SpringMVC

  • Un producto nativo de la familia Spring , perfectamente integrado con infraestructura como contenedores IOC
  • Basado en el servlet nativo , el potente controlador front-end DispatcherServlet se utiliza para procesar solicitudes y respuestas de manera uniforme.
  • Los problemas que deben resolverse en cada subdivisión de la capa de presentación se cubren de manera integral y se brindan soluciones integrales .
  • El código es nuevo y conciso , lo que mejora enormemente la eficiencia del desarrollo.
  • El grado de componente interno es alto y los componentes conectables son plug-and-play . Puede configurar los componentes correspondientes según las funciones que desee.
  • Excelente rendimiento , especialmente adecuado para los requisitos modernos de proyectos de Internet grandes y ultragrandes.

2. Hola mundo

1. Entorno de desarrollo

IDE: idea 2019.2

Herramienta de compilación: maven3.5.4

Servidor: tomcat7

Versión de primavera: 5.3.1

2. Crea un proyecto maven

a>Agregar módulo web
b>Método de embalaje: guerra
c>Introducir dependencias
<dependencies>
    <!-- SpringMVC -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.3.1</version>
    </dependency>

    <!-- 日志 -->
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.2.3</version>
    </dependency>

    <!-- ServletAPI -->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>3.1.0</version>
        <scope>provided</scope>
    </dependency>

    <!-- Spring5和Thymeleaf整合包 -->
    <dependency>
        <groupId>org.thymeleaf</groupId>
        <artifactId>thymeleaf-spring5</artifactId>
        <version>3.0.12.RELEASE</version>
    </dependency>
</dependencies>

Nota: Debido a la naturaleza transitiva de Maven, no tenemos que configurar dependencias en todos los paquetes requeridos, sino configurar las dependencias más importantes e importar las demás de forma transitiva.

La transferencia de la imagen del enlace externo falló. El sitio de origen puede tener un mecanismo anti-leeching. Se recomienda guardar la imagen y cargarla directamente.

3. Configurar web.xml

Registre el controlador front-end de SpringMVC DispatcherServlet

a>Método de configuración predeterminado

Bajo esta configuración, el archivo de configuración SpringMVC se encuentra en WEB-INF de forma predeterminada, y el nombre predeterminado es <servlet-name> -servlet.xml. Por ejemplo, el archivo de configuración SpringMVC correspondiente a la siguiente configuración se encuentra en WEB-INF y el nombre del archivo es springMVC-servlet.xml

<!-- 配置SpringMVC的前端控制器,对浏览器发送的请求统一进行处理 -->
<servlet>
    <servlet-name>springMVC</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>springMVC</servlet-name>
    <!--
        设置springMVC的核心控制器所能处理的请求的请求路径
        /所匹配的请求可以是/login或.html或.js或.css方式的请求路径
        但是/不能匹配.jsp请求路径的请求
    -->
    <url-pattern>/</url-pattern>
</servlet-mapping>
b>Método de configuración extendido

Puede establecer la ubicación y el nombre del archivo de configuración SpringMVC a través de la etiqueta init-param y establecer el tiempo de inicialización del controlador front-end SpringMVC DispatcherServlet a través de la etiqueta load-on-startup.

<!-- 配置SpringMVC的前端控制器,对浏览器发送的请求统一进行处理 -->
<servlet>
    <servlet-name>springMVC</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!-- 通过初始化参数指定SpringMVC配置文件的位置和名称 -->
    <init-param>
        <!-- contextConfigLocation为固定值 -->
        <param-name>contextConfigLocation</param-name>
        <!-- 使用classpath:表示从类路径查找配置文件,例如maven工程中的src/main/resources -->
        <param-value>classpath:springMVC.xml</param-value>
    </init-param>
    <!-- 
 		作为框架的核心组件,在启动过程中有大量的初始化操作要做
		而这些操作放在第一次请求时才执行会严重影响访问速度
		因此需要通过此标签将启动控制DispatcherServlet的初始化时间提前到服务器启动时
	-->
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>springMVC</servlet-name>
    <!--
        设置springMVC的核心控制器所能处理的请求的请求路径
        /所匹配的请求可以是/login或.html或.js或.css方式的请求路径
        但是/不能匹配.jsp请求路径的请求
    -->
    <url-pattern>/</url-pattern>
</servlet-mapping>

Nota:

La diferencia entre usar / y /* en la etiqueta <url-pattern>:

La solicitud coincidente con / puede ser una ruta de solicitud de /login o .html o .js o .css, pero / no puede coincidir con la solicitud de ruta de solicitud .jsp.

Por lo tanto, se puede evitar que al acceder a la página jsp, la solicitud sea procesada por DispatcherServlet y no se pueda encontrar la página correspondiente.

/* puede coincidir con todas las solicitudes. Por ejemplo, cuando se utiliza un filtro, si necesita filtrar todas las solicitudes, debe utilizar el método de escritura /*

4. Cree un controlador de solicitudes

Dado que el controlador de front-end procesa de manera uniforme las solicitudes enviadas por el navegador, pero las solicitudes específicas tienen diferentes procedimientos de procesamiento, es necesario crear una clase que maneje solicitudes específicas, es decir, un controlador de solicitudes.

Cada método en el controlador de solicitudes que maneja la solicitud se convierte en un método de controlador.

Debido a que el controlador de SpringMVC es servido por un POJO (clase Java ordinaria), debe identificarse como un componente de la capa de control a través de la anotación @Controller y entregarse a la administración del contenedor IoC de Spring. En este momento, SpringMVC puede reconocer la existencia del controlador. .

@Controller
public class HelloController {
    
    
    
}

5. Cree el archivo de configuración springMVC

<!-- 自动扫描包 -->
<context:component-scan base-package="com.atguigu.mvc.controller"/>

<!-- 配置Thymeleaf视图解析器 -->
<bean id="viewResolver" class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
    <property name="order" value="1"/>
    <property name="characterEncoding" value="UTF-8"/>
    <property name="templateEngine">
        <bean class="org.thymeleaf.spring5.SpringTemplateEngine">
            <property name="templateResolver">
                <bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
    
                    <!-- 视图前缀 -->
                    <property name="prefix" value="/WEB-INF/templates/"/>
    
                    <!-- 视图后缀 -->
                    <property name="suffix" value=".html"/>
                    <property name="templateMode" value="HTML5"/>
                    <property name="characterEncoding" value="UTF-8" />
                </bean>
            </property>
        </bean>
    </property>
</bean>

<!-- 
   处理静态资源,例如html、js、css、jpg
  若只设置该标签,则只能访问静态资源,其他请求则无法访问
  此时必须设置<mvc:annotation-driven/>解决问题
 -->
<mvc:default-servlet-handler/>

<!-- 开启mvc注解驱动 -->
<mvc:annotation-driven>
    <mvc:message-converters>
        <!-- 处理响应中文内容乱码 -->
        <bean class="org.springframework.http.converter.StringHttpMessageConverter">
            <property name="defaultCharset" value="UTF-8" />
            <property name="supportedMediaTypes">
                <list>
                    <value>text/html</value>
                    <value>application/json</value>
                </list>
            </property>
        </bean>
    </mvc:message-converters>
</mvc:annotation-driven>

6. Prueba Hola Mundo

a>Lograr acceso a la página de inicio

Cree un método en el controlador de solicitudes para manejar la solicitud.

// @RequestMapping注解:处理请求和控制器方法之间的映射关系
// @RequestMapping注解的value属性可以通过请求地址匹配请求,/表示的当前工程的上下文路径
// localhost:8080/springMVC/
@RequestMapping("/")
public String index() {
    
    
    //设置视图名称
    return "index";
}
b> Saltar a la página especificada a través de un hipervínculo

Establecer hipervínculos en la página de inicio index.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
</head>
<body>
    <h1>首页</h1>
    <a th:href="@{/hello}">HelloWorld</a><br/>
</body>
</html>

Cree un método en el controlador de solicitudes para manejar la solicitud.

@RequestMapping("/hello")
public String HelloWorld() {
    
    
    return "target";
}

7. Resumen

El navegador envía una solicitud. Si la dirección de la solicitud coincide con el patrón de URL del controlador de front-end, la solicitud será procesada por el controlador de front-end DispatcherServlet. El controlador de front-end leerá el archivo de configuración central de SpringMVC, buscará el controlador escaneando los componentes y hará coincidir la dirección de solicitud con el valor del atributo de valor de la anotación @RequestMapping en el controlador. Si la coincidencia es exitosa, el método del controlador identificado por la anotación es el método de solicitud de procesamiento. El método de procesamiento de la solicitud debe devolver un nombre de vista de tipo cadena. El nombre de la vista será analizado por el analizador de vistas, más el prefijo y el sufijo para formar la ruta de la vista. La vista se representará a través de Thymeleaf y finalmente se reenviará a la página correspondiente a la vista.

3. Anotación @RequestMapping

1. Función de la anotación @RequestMapping

Por el nombre de la anotación, podemos ver que la función de la anotación @RequestMapping es asociar la solicitud con el método del controlador que maneja la solicitud y establecer una relación de mapeo.

Cuando SpringMVC recibe la solicitud especificada, encontrará el método de controlador correspondiente en la relación de mapeo para manejar la solicitud.

2. La ubicación de la anotación @RequestMapping

@RequestMapping identifica una clase: establece la información inicial de la ruta de solicitud de la solicitud de mapeo

@RequestMapping identifica un método: establece la información específica de la ruta de solicitud de solicitud de mapeo

@Controller
@RequestMapping("/test")
public class RequestMappingController {
    
    
	//此时请求映射所映射的请求的请求路径为:/test/testRequestMapping
    @RequestMapping("/testRequestMapping")
    public String testRequestMapping(){
    
    
        return "success";
    }
}

3. El atributo de valor de la anotación @RequestMapping

El atributo de valor de la anotación @RequestMapping coincide con la asignación de solicitud a través de la dirección de solicitud solicitada.

El atributo de valor de la anotación @RequestMapping es una matriz de tipo cadena, lo que indica que la asignación de solicitudes puede coincidir con solicitudes correspondientes a múltiples direcciones de solicitud.

Se debe establecer el atributo de valor de la anotación @RequestMapping, al menos haciendo coincidir la asignación de solicitud con la dirección de solicitud.

<a th:href="@{/testRequestMapping}">测试@RequestMapping的value属性-->/testRequestMapping</a><br>
<a th:href="@{/test}">测试@RequestMapping的value属性-->/test</a><br>
@RequestMapping(
        value = {
    
    "/testRequestMapping", "/test"}
)
public String testRequestMapping(){
    
    
    return "success";
}

4. El atributo de método de la anotación @RequestMapping

El atributo de método de la anotación @RequestMapping coincide con la asignación de la solicitud a través del método de solicitud (obtener o publicar)

El atributo de método de la anotación @RequestMapping es una matriz de tipo RequestMethod, lo que indica que la asignación de solicitudes puede coincidir con solicitudes en múltiples métodos de solicitud.

Si la dirección de solicitud de la solicitud actual satisface el atributo de valor de la asignación de solicitud, pero el método de solicitud no satisface el atributo de método, el navegador informará el error 405: Método de solicitud 'POST' no compatible

<a th:href="@{/test}">测试@RequestMapping的value属性-->/test</a><br>
<form th:action="@{/test}" method="post">
    <input type="submit">
</form>
@RequestMapping(
        value = {
    
    "/testRequestMapping", "/test"},
        method = {
    
    RequestMethod.GET, RequestMethod.POST}
)
public String testRequestMapping(){
    
    
    return "success";
}

Nota:

1. Para los métodos de controlador que manejan métodos de solicitud específicos, SpringMVC proporciona la anotación derivada @RequestMapping

Mapeo que maneja solicitudes de obtención–>@GetMapping

Mapeo para procesar solicitudes de publicación–>@PostMapping

Mapeo para procesar solicitudes de venta–>@PutMapping

Mapeo para manejar solicitudes de eliminación–>@DeleteMapping

2. Los métodos de solicitud más utilizados incluyen obtener, publicar, colocar y eliminar.

Sin embargo, los navegadores actuales solo admiten obtener y publicar. Si se establece otra cadena de método de solicitud (poner o eliminar) para el método al enviar el formulario, se procesará de acuerdo con el método de solicitud predeterminado obtener.

Para enviar solicitudes de colocación y eliminación, debe pasar el filtro HiddenHttpMethodFilter proporcionado por Spring, que se analizará en la parte RESTful.

5. Atributo de parámetros de la anotación @RequestMapping (comprender)

El atributo params de la anotación @RequestMapping coincide con el mapeo de la solicitud a través de los parámetros de la solicitud.

El atributo params de la anotación @RequestMapping es una matriz de tipo cadena. La relación de coincidencia entre los parámetros de solicitud y el mapeo de solicitudes se puede establecer mediante cuatro expresiones.

"param": la solicitud que coincide con la asignación de solicitudes debe llevar el parámetro de solicitud param

"!param": la solicitud que coincide con la asignación de solicitudes no debe contener parámetros de solicitud de parámetro

"param=value": la solicitud que coincide con la asignación de solicitudes debe llevar el parámetro de solicitud param y param=value

"param!=value": la solicitud que coincide con la asignación de solicitudes debe llevar el parámetro de solicitud param pero param!=value

<a th:href="@{/test(username='admin',password=123456)">测试@RequestMapping的params属性-->/test</a><br>
@RequestMapping(
        value = {
    
    "/testRequestMapping", "/test"}
        ,method = {
    
    RequestMethod.GET, RequestMethod.POST}
        ,params = {
    
    "username","password!=123456"}
)
public String testRequestMapping(){
    
    
    return "success";
}

Nota:

Si la solicitud actual satisface los atributos de valor y método de la anotación @RequestMapping, pero no satisface el atributo params, la página devolverá el error 400: Las condiciones del parámetro "nombre de usuario, contraseña! = 123456" no se cumplen para los parámetros de solicitud reales: nombre de usuario = {admin}, contraseña ={123456}

6. Atributo de encabezados de la anotación @RequestMapping (comprender)

El atributo de encabezados de la anotación @RequestMapping coincide con el mapeo de la solicitud a través de la información del encabezado de la solicitud.

El atributo de encabezado de la anotación @RequestMapping es una matriz de tipo cadena. La relación de coincidencia entre la información del encabezado de la solicitud y el mapeo de la solicitud se puede establecer mediante cuatro expresiones.

"encabezado": la solicitud que coincide con la asignación de solicitudes debe contener información del encabezado de la solicitud

"!header": la solicitud que coincide con la asignación de solicitudes no debe contener información del encabezado de la solicitud

"encabezado = valor": la solicitud que coincide con la asignación de solicitud debe contener información del encabezado de la solicitud y encabezado = valor

"encabezado! = valor": la solicitud que coincide con la asignación de solicitud debe contener información del encabezado de la solicitud y encabezado! = valor

Si la solicitud actual satisface los atributos de valor y método de la anotación @RequestMapping, pero no satisface el atributo de encabezados, la página mostrará un error 404, es decir, no se encuentra el recurso.

7. SpringMVC admite rutas estilo hormiga

? : representa cualquier carácter individual

*: representa 0 o más caracteres

**: Indica uno o más niveles de directorios

Nota: Cuando se utiliza **, solo se puede utilizar el método /**/xxx

8. SpringMVC admite marcadores de posición en rutas (énfasis)

Método original: /deleteUser?id=1

Modo de reposo:/deleteUser/1

Los marcadores de posición en la ruta SpringMVC se usan a menudo en estilo RESTful. Cuando ciertos datos se transmiten al servidor a través de la ruta en la ruta de solicitud, se pueden representar mediante el marcador de posición {xxx} en el atributo de valor de la anotación @RequestMapping correspondiente. Los datos transmitidos se pasan a través de la anotación @PathVariable y los datos representados por el marcador de posición se asignan al parámetro formal del método del controlador.

<a th:href="@{/testRest/1/admin}">测试路径中的占位符-->/testRest</a><br>
@RequestMapping("/testRest/{id}/{username}")
public String testRest(@PathVariable("id") String id, @PathVariable("username") String username){
    
    
    System.out.println("id:"+id+",username:"+username);
    return "success";
}
//最终输出的内容为-->id:1,username:admin

4. SpringMVC obtiene los parámetros de solicitud

1. Obtener a través de ServletAPI

Utilice HttpServletRequest como parámetro formal del método del controlador. En este momento, el parámetro de tipo HttpServletRequest representa un objeto que encapsula el mensaje de solicitud de la solicitud actual.

@RequestMapping("/testParam")
public String testParam(HttpServletRequest request){
    
    
    String username = request.getParameter("username");
    String password = request.getParameter("password");
    System.out.println("username:"+username+",password:"+password);
    return "success";
}

2. Obtenga los parámetros de solicitud a través de los parámetros formales del método del controlador.

En la posición del parámetro formal del método del controlador, establezca el parámetro formal con el mismo nombre que el parámetro de solicitud. Cuando el navegador envía una solicitud y coincide con la asignación de la solicitud, el parámetro de solicitud se asignará al parámetro formal correspondiente en DispatcherServlet.

<a th:href="@{/testParam(username='admin',password=123456)}">测试获取请求参数-->/testParam</a><br>
@RequestMapping("/testParam")
public String testParam(String username, String password){
    
    
    System.out.println("username:"+username+",password:"+password);
    return "success";
}

Nota:

Si hay varios parámetros de solicitud con el mismo nombre en los parámetros de solicitud transmitidos por la solicitud, puede configurar una matriz de cadenas o un parámetro de tipo de cadena en el parámetro formal del método del controlador para recibir este parámetro de solicitud.

Si se utiliza un parámetro formal de tipo matriz de cadenas, la matriz de este parámetro contiene cada dato.

Si se utiliza un parámetro de tipo cadena, el valor de este parámetro es el resultado de concatenar cada dato con una coma.

3、@RequestParam

@RequestParam crea una relación de mapeo entre los parámetros de solicitud y los parámetros formales del método del controlador.

La anotación @RequestParam tiene tres atributos:

valor: especifica el nombre del parámetro de solicitud asignado al parámetro formal.

requerido: establezca si este parámetro de solicitud debe transmitirse, el valor predeterminado es verdadero

Si se establece en verdadero, la solicitud actual debe transmitir el parámetro de solicitud especificado por valor. Si el parámetro de solicitud no se transmite y el atributo defaultValue no está establecido, la página informará el error 400: el parámetro de cadena requerido 'xxx' no está presente; si establecido en false, entonces la solicitud actual no tiene que transmitir el parámetro de solicitud especificado por valor. Si no se transmite, el valor del parámetro formal identificado por la anotación es nulo.

defaultValue: independientemente de si el valor del atributo requerido es verdadero o falso, cuando el parámetro de solicitud especificado por el valor no se transmite o el valor transmitido es "", se utiliza el valor predeterminado para asignar el parámetro formal.

4、@RequestHeader

@RequestHeader crea una relación de mapeo entre la información del encabezado de la solicitud y los parámetros formales del método del controlador.

La anotación @RequestHeader tiene tres atributos: valor, requerido y valor predeterminado, y su uso es el mismo que @RequestParam.

5、@CookieValue

@CookieValue crea una relación de mapeo entre los datos de las cookies y los parámetros formales del método del controlador.

La anotación @CookieValue tiene tres atributos: valor, requerido y valor predeterminado, y su uso es el mismo que @RequestParam.

6. Obtener parámetros de solicitud a través de POJO

Puede establecer un parámetro formal del tipo de clase de entidad en la posición del parámetro formal del método del controlador. En este momento, si el nombre del parámetro del parámetro de solicitud transmitido por el navegador es consistente con el nombre del atributo en la clase de entidad, entonces el Al parámetro de solicitud se le asignará un valor para este atributo.

<form th:action="@{/testpojo}" method="post">
    用户名:<input type="text" name="username"><br>
    密码:<input type="password" name="password"><br>
    性别:<input type="radio" name="sex" value=""><input type="radio" name="sex" value=""><br>
    年龄:<input type="text" name="age"><br>
    邮箱:<input type="text" name="email"><br>
    <input type="submit">
</form>
@RequestMapping("/testpojo")
public String testPOJO(User user){
    
    
    System.out.println(user);
    return "success";
}
//最终结果-->User{id=null, username='张三', password='123', age=23, sex='男', email='[email protected]'}

7. Resuelva el problema confuso de obtener parámetros de solicitud

Para resolver el problema confuso de obtener parámetros de solicitud, puede utilizar el filtro de codificación CharacterEncodingFilter proporcionado por SpringMVC, pero debe estar registrado en web.xml

<!--配置springMVC的编码过滤器-->
<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>forceResponseEncoding</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>CharacterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

Nota:

El filtro de codificación en SpringMVC debe configurarse antes que otros filtros; de lo contrario, no será válido.

5. Datos compartidos del objeto de dominio.

1. Utilice ServletAPI para compartir datos y solicitar objetos de dominio.

@RequestMapping("/testServletAPI")
public String testServletAPI(HttpServletRequest request){
    
    
    request.setAttribute("testScope", "hello,servletAPI");
    return "success";
}

2. Utilice ModelAndView para compartir datos con el objeto de dominio de solicitud

@RequestMapping("/testModelAndView")
public ModelAndView testModelAndView(){
    
    
    /**
     * ModelAndView有Model和View的功能
     * Model主要用于向请求域共享数据
     * View主要用于设置视图,实现页面跳转
     */
    ModelAndView mav = new ModelAndView();
    //向请求域共享数据
    mav.addObject("testScope", "hello,ModelAndView");
    //设置视图,实现页面跳转
    mav.setViewName("success");
    return mav;
}

3. Utilice el modelo para compartir datos con objetos del dominio de solicitud.

@RequestMapping("/testModel")
public String testModel(Model model){
    
    
    model.addAttribute("testScope", "hello,Model");
    return "success";
}

4. Utilice el mapa para compartir datos con objetos del dominio de solicitud

@RequestMapping("/testMap")
public String testMap(Map<String, Object> map){
    
    
    map.put("testScope", "hello,Map");
    return "success";
}

5. Utilice ModelMap para compartir datos con objetos del dominio de solicitud

@RequestMapping("/testModelMap")
public String testModelMap(ModelMap modelMap){
    
    
    modelMap.addAttribute("testScope", "hello,ModelMap");
    return "success";
}

6. La relación entre Modelo, ModelMap y Map.

Los parámetros de tipo Model, ModelMap y Map son en realidad del tipo BindingAwareModelMap.

public interface Model{}
public class ModelMap extends LinkedHashMap<String, Object> {}
public class ExtendedModelMap extends ModelMap implements Model {}
public class BindingAwareModelMap extends ExtendedModelMap {}

7. Compartir datos con el dominio de la sesión.

@RequestMapping("/testSession")
public String testSession(HttpSession session){
    
    
    session.setAttribute("testSessionScope", "hello,session");
    return "success";
}

8. Compartir datos con el dominio de la aplicación.

@RequestMapping("/testApplication")
public String testApplication(HttpSession session){
    
    
	ServletContext application = session.getServletContext();
    application.setAttribute("testApplicationScope", "hello,application");
    return "success";
}

6. Vista de SpringMVC

La vista en SpringMVC es la interfaz Ver. La función de la vista es representar datos y mostrarlos en el modelo al usuario.

Hay muchos tipos de vistas SpringMVC, de forma predeterminada, hay vistas de reenvío y vistas de redirección.

Cuando el proyecto introduce la dependencia de jstl, la vista reenviada se convertirá automáticamente a JstlView.

Si la tecnología de vista utilizada es Thymeleaf, el analizador de vistas de Thymeleaf se configura en el archivo de configuración SpringMVC, y lo que se obtiene después del análisis por parte del analizador de vistas es ThymeleafView.

1. Vista de hoja de tomillo

Cuando el nombre de la vista establecido en el método del controlador no tiene ningún prefijo, el nombre de la vista en este momento será analizado por el analizador de vistas configurado en el archivo de configuración SpringMVC. La ruta final obtenida al unir el nombre de la vista con el prefijo de la vista y la vista se pasará el sufijo Implementar el salto reenviando

@RequestMapping("/testHello")
public String testHello(){
    
    
    return "hello";
}

La transferencia de la imagen del enlace externo falló. El sitio de origen puede tener un mecanismo anti-leeching. Se recomienda guardar la imagen y cargarla directamente.

2. Vista frontal

La vista de reenvío predeterminada en SpringMVC es InternalResourceView

La situación de crear una vista de reenvío en SpringMVC:

Cuando el nombre de la vista establecido en el método del controlador tiene el prefijo "forward:", se crea la vista InternalResourceView. El nombre de la vista en este momento no será analizado por el analizador de vistas configurado en el archivo de configuración SpringMVC, pero tendrá el prefijo " adelante. :"Elimínelo y la parte restante se utilizará como ruta final para saltar a través del reenvío.

Por ejemplo "reenviar:/", "reenviar:/empleado"

@RequestMapping("/testForward")
public String testForward(){
    
    
    return "forward:/testHello";
}

La transferencia de la imagen del enlace externo falló. El sitio de origen puede tener un mecanismo anti-leeching. Se recomienda guardar la imagen y cargarla directamente.

3. Vista de redireccionamiento

La vista de redireccionamiento predeterminada en SpringMVC es RedirectView

Cuando el nombre de la vista establecido en el método del controlador tiene el prefijo "redirect:", se crea la vista RedirectView. El nombre de la vista en este momento no será analizado por el analizador de vistas configurado en el archivo de configuración SpringMVC, pero tendrá el prefijo " redirigir: "Elimínelo y la parte restante se utilizará como ruta final para saltar a través de la redirección.

Por ejemplo "redireccionar:/", "redireccionar:/empleado"

@RequestMapping("/testRedirect")
public String testRedirect(){
    
    
    return "redirect:/testHello";
}

La transferencia de la imagen del enlace externo falló. El sitio de origen puede tener un mecanismo anti-leeching. Se recomienda guardar la imagen y cargarla directamente.

Nota: Al analizar la vista redirigida, el prefijo redirigir: se eliminará primero y luego se determinará si la parte restante comienza con /. Si es así, la ruta de contexto se unirá automáticamente.

4. Ver controlador ver-controlador

Cuando el método del controlador solo se usa para implementar saltos de página, es decir, cuando solo necesita configurar el nombre de la vista, el método del procesador se puede expresar usando la etiqueta del controlador de vista.

<!--
	path:设置处理的请求地址
	view-name:设置请求地址所对应的视图名称
-->
<mvc:view-controller path="/testView" view-name="success"></mvc:view-controller>

Nota:

Cuando se configura cualquier controlador de vista en SpringMVC, todas las asignaciones de solicitudes en otros controladores no serán válidas. En este momento, debe configurar la etiqueta para habilitar el controlador de anotaciones mvc en el archivo de configuración principal de SpringMVC:

<mvc:controlado por anotaciones />

7. DESCANSO

1. Introducción a RESTful

REST: Representational State Transfer , transferencia de estado de recursos de la capa de presentación .

a>Recursos

Recursos es una forma de ver un servidor como si estuviera formado por muchos recursos discretos. Cada recurso es una abstracción con nombre en el servidor. Debido a que los recursos son un concepto abstracto, no sólo pueden representar cosas específicas como un archivo en el sistema de archivos del servidor, una tabla en la base de datos, etc. Los recursos pueden diseñarse para que sean tan abstractos como su imaginación lo permita. Y los desarrolladores de aplicaciones cliente entiendelo. De manera similar al diseño orientado a objetos, los recursos se organizan en torno a sustantivos, siendo los sustantivos el primer enfoque. Un recurso puede identificarse mediante uno o más URI. URI es tanto el nombre del recurso como la dirección del recurso en la Web. Las aplicaciones cliente que estén interesadas en un recurso pueden interactuar con él a través del URI del recurso.

b>Representación de recursos

Una representación de un recurso es una descripción del estado del recurso en un momento específico. Se puede transferir (intercambiar) entre cliente-servidor. La descripción de los recursos puede estar en una variedad de formatos, como HTML/XML/JSON/texto sin formato/imágenes/video/audio, etc. El formato de representación de los recursos se puede determinar mediante un mecanismo de negociación. Las direcciones de solicitud-respuesta suelen expresarse en diferentes formatos.

c>Transferencia estatal

La transferencia de estado se refiere a la transferencia de representaciones del estado de los recursos entre el cliente y el servidor. El propósito de operar recursos se logra indirectamente mediante la transferencia y operación de expresiones de recursos.

2. Implementación de RESTful

Específicamente, en el protocolo HTTP, hay cuatro verbos que indican métodos de operación: GET, POST, PUT y DELETE.

Corresponden a cuatro operaciones básicas: GET se usa para obtener recursos, POST se usa para crear recursos, PUT se usa para actualizar recursos y DELETE se usa para eliminar recursos.

El estilo REST aboga por el uso de un diseño de estilo unificado para las direcciones URL. Cada palabra de adelante hacia atrás está separada por barras diagonales. Los pares clave-valor de signos de interrogación no se utilizan para transportar los parámetros de solicitud. En cambio, los datos que se enviarán al servidor se utiliza como parte de la dirección URL para garantizar la coherencia del estilo general.

funcionar manera tradicional estilo DESCANSO
operación de consulta getUserById?id=1 usuario/1–>obtener método de solicitud
Guardar operación guardarUsuario usuario–>método de solicitud de publicación
Eliminar operación eliminarUsuario?id=1 usuario/1–>eliminar método de solicitud
operación de actualización actualizarUsuario usuario–>método de solicitud de entrada

3. Filtro de método Http oculto

Dado que el navegador solo admite el envío de solicitudes de obtención y publicación, ¿cómo enviar solicitudes de colocación y eliminación?

SpringMVC proporciona HiddenHttpMethodFilter para ayudarnos a convertir solicitudes POST en solicitudes DELETE o PUT

Condiciones para que HiddenHttpMethodFilter procese solicitudes de colocación y eliminación:

a> El método de solicitud de la solicitud actual debe ser posterior

b>La solicitud actual debe transmitir la solicitud parámetro_método

Si se cumplen las condiciones anteriores, el filtro HiddenHttpMethodFilter convertirá el método de solicitud de la solicitud actual en el valor del parámetro de solicitud _method, por lo que el valor del parámetro de solicitud _method es el método de solicitud final.

Registre HiddenHttpMethodFilter en web.xml

<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>

Nota: Hasta ahora, se proporcionan dos filtros en SpringMVC: CharacterEncodingFilter y HiddenHttpMethodFilter

Al registrarse en web.xml, primero debe registrar CharacterEncodingFilter y luego HiddenHttpMethodFilter.

razón:

  • Configure el juego de caracteres mediante el método request.setCharacterEncoding (codificación) en CharacterEncodingFilter

  • El método request.setCharacterEncoding(codificación) requiere que no pueda haber operaciones previas para obtener los parámetros de la solicitud.

  • Y HiddenHttpMethodFilter tiene exactamente una operación para obtener el método de solicitud:

Cadena paramValue = request.getParameter(this.methodParam);

8. Caso RESTful

1. Preparación

Al igual que el CRUD tradicional, puede agregar, eliminar, modificar y verificar la información de los empleados.

  • Entorno de construcción

  • Preparar clase de entidad

    package com.atguigu.mvc.bean;
    public class Employee {
          
          
       private Integer id;
       private String lastName;
    
       private String email;
       //1 male, 0 female
       private Integer gender;
       
       public Integer getId() {
          
          
          return id;
       }
    
       public void setId(Integer id) {
          
          
          this.id = id;
       }
    
       public String getLastName() {
          
          
          return lastName;
       }
    
       public void setLastName(String lastName) {
          
          
          this.lastName = lastName;
       }
    
       public String getEmail() {
          
          
          return email;
       }
    
       public void setEmail(String email) {
          
          
          this.email = email;
       }
    
       public Integer getGender() {
          
          
          return gender;
       }
    
       public void setGender(Integer gender) {
          
          
          this.gender = gender;
       }
    
       public Employee(Integer id, String lastName, String email, Integer gender) {
          
          
          super();
          this.id = id;
          this.lastName = lastName;
          this.email = email;
          this.gender = gender;
       }
    
       public Employee() {
          
          
       }
    }
    
  • Preparar datos de simulación.

    package com.atguigu.mvc.dao;
    
    import java.util.Collection;
    import java.util.HashMap;
    import java.util.Map;
    
    import com.atguigu.mvc.bean.Employee;
    import org.springframework.stereotype.Repository;
    
    
    @Repository
    public class EmployeeDao {
          
          
    
       private static Map<Integer, Employee> employees = null;
       
       static{
          
          
          employees = new HashMap<Integer, Employee>();
    
          employees.put(1001, new Employee(1001, "E-AA", "[email protected]", 1));
          employees.put(1002, new Employee(1002, "E-BB", "[email protected]", 1));
          employees.put(1003, new Employee(1003, "E-CC", "[email protected]", 0));
          employees.put(1004, new Employee(1004, "E-DD", "[email protected]", 0));
          employees.put(1005, new Employee(1005, "E-EE", "[email protected]", 1));
       }
       
       private static Integer initId = 1006;
       
       public void save(Employee employee){
          
          
          if(employee.getId() == null){
          
          
             employee.setId(initId++);
          }
          employees.put(employee.getId(), employee);
       }
       
       public Collection<Employee> getAll(){
          
          
          return employees.values();
       }
       
       public Employee get(Integer id){
          
          
          return employees.get(id);
       }
       
       public void delete(Integer id){
          
          
          employees.remove(id);
       }
    }
    

2. Lista de funciones

Función dirección URL Método de solicitud
Visitar la página de inicio√ / CONSEGUIR
Consultar todos los datos√ /empleado CONSEGUIR
Eliminar √ /empleado/2 BORRAR
Ir a la página para agregar datos√ /agregar CONSEGUIR
Ejecutar guardar√ /empleado CORREO
Saltar a la página de actualización de datos√ /empleado/2 CONSEGUIR
Realizar actualización√ /empleado PONER

3. Funciones específicas: visitar la página de inicio

a>Configurar controlador de vista
<mvc:view-controller path="/" view-name="index"/>
b>Crear página
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8" >
    <title>Title</title>
</head>
<body>
<h1>首页</h1>
<a th:href="@{/employee}">访问员工信息</a>
</body>
</html>

4. Función específica: Consultar todos los datos de los empleados.

a>Método del controlador
@RequestMapping(value = "/employee", method = RequestMethod.GET)
public String getEmployeeList(Model model){
    
    
    Collection<Employee> employeeList = employeeDao.getAll();
    model.addAttribute("employeeList", employeeList);
    return "employee_list";
}
b>Crear lista_empleados.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Employee Info</title>
    <script type="text/javascript" th:src="@{/static/js/vue.js}"></script>
</head>
<body>
    <table border="1" cellpadding="0" cellspacing="0" style="text-align: center;" id="dataTable">
        <tr>
            <th colspan="5">Employee Info</th>
        </tr>
        <tr>
            <th>id</th>
            <th>lastName</th>
            <th>email</th>
            <th>gender</th>
            <th>options(<a th:href="@{/toAdd}">add</a>)</th>
        </tr>
        <tr th:each="employee : ${employeeList}">
            <td th:text="${employee.id}"></td>
            <td th:text="${employee.lastName}"></td>
            <td th:text="${employee.email}"></td>
            <td th:text="${employee.gender}"></td>
            <td>
                <a class="deleteA" @click="deleteEmployee" th:href="@{'/employee/'+${employee.id}}">delete</a>
                <a th:href="@{'/employee/'+${employee.id}}">update</a>
            </td>
        </tr>
    </table>
</body>
</html>

5. Función específica: eliminar

a>Crear un formulario para manejar solicitudes de eliminación
<!-- 作用:通过超链接控制表单的提交,将post请求转换为delete请求 -->
<form id="delete_form" method="post">
    <!-- HiddenHttpMethodFilter要求:必须传输_method请求参数,并且值为最终的请求方式 -->
    <input type="hidden" name="_method" value="delete"/>
</form>
b>Eliminar evento de clic de enlace de hipervínculo

Introducir vue.js

<script type="text/javascript" th:src="@{/static/js/vue.js}"></script>

Eliminar hipervínculo

<a class="deleteA" @click="deleteEmployee" th:href="@{'/employee/'+${employee.id}}">delete</a>

Manejo de eventos de clic a través de vue

<script type="text/javascript">
    var vue = new Vue({
      
      
        el:"#dataTable",
        methods:{
      
      
            //event表示当前事件
            deleteEmployee:function (event) {
      
      
                //通过id获取表单标签
                var delete_form = document.getElementById("delete_form");
                //将触发事件的超链接的href属性为表单的action属性赋值
                delete_form.action = event.target.href;
                //提交表单
                delete_form.submit();
                //阻止超链接的默认跳转行为
                event.preventDefault();
            }
        }
    });
</script>
c>Método del controlador
@RequestMapping(value = "/employee/{id}", method = RequestMethod.DELETE)
public String deleteEmployee(@PathVariable("id") Integer id){
    
    
    employeeDao.delete(id);
    return "redirect:/employee";
}

6. Función específica: saltar a la página de agregar datos

a>Configurar controlador de vista
<mvc:view-controller path="/toAdd" view-name="employee_add"></mvc:view-controller>
b>Crear empleado_add.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Add Employee</title>
</head>
<body>

<form th:action="@{/employee}" method="post">
    lastName:<input type="text" name="lastName"><br>
    email:<input type="text" name="email"><br>
    gender:<input type="radio" name="gender" value="1">male
    <input type="radio" name="gender" value="0">female<br>
    <input type="submit" value="add"><br>
</form>

</body>
</html>

7. Función específica: ejecutar guardar

a>Método del controlador
@RequestMapping(value = "/employee", method = RequestMethod.POST)
public String addEmployee(Employee employee){
    
    
    employeeDao.save(employee);
    return "redirect:/employee";
}

8. Función específica: saltar a la página de actualización de datos

a>Modificar hipervínculo
<a th:href="@{'/employee/'+${employee.id}}">update</a>
b>Método del controlador
@RequestMapping(value = "/employee/{id}", method = RequestMethod.GET)
public String getEmployeeById(@PathVariable("id") Integer id, Model model){
    
    
    Employee employee = employeeDao.get(id);
    model.addAttribute("employee", employee);
    return "employee_update";
}
c>Crear empleado_update.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Update Employee</title>
</head>
<body>

<form th:action="@{/employee}" method="post">
    <input type="hidden" name="_method" value="put">
    <input type="hidden" name="id" th:value="${employee.id}">
    lastName:<input type="text" name="lastName" th:value="${employee.lastName}"><br>
    email:<input type="text" name="email" th:value="${employee.email}"><br>
    <!--
        th:field="${employee.gender}"可用于单选框或复选框的回显
        若单选框的value和employee.gender的值一致,则添加checked="checked"属性
    -->
    gender:<input type="radio" name="gender" value="1" th:field="${employee.gender}">male
    <input type="radio" name="gender" value="0" th:field="${employee.gender}">female<br>
    <input type="submit" value="update"><br>
</form>

</body>
</html>

9. Funciones específicas: realizar actualizaciones

a>Método del controlador
@RequestMapping(value = "/employee", method = RequestMethod.PUT)
public String updateEmployee(Employee employee){
    
    
    employeeDao.save(employee);
    return "redirect:/employee";
}

八、HttpMessageConverter

HttpMessageConverter, conversor de información de mensajes, convierte mensajes de solicitud en objetos Java o convierte objetos Java en mensajes de respuesta

HttpMessageConverter proporciona dos anotaciones y dos tipos: @RequestBody, @ResponseBody, RequestEntity,

Entidad de respuesta

1、@RequestBody

@RequestBody puede obtener el cuerpo de la solicitud. Debe establecer un parámetro formal en el método del controlador y usar @RequestBody para identificarlo. El cuerpo de la solicitud actual asignará un valor al parámetro formal identificado por la anotación actual.

<form th:action="@{/testRequestBody}" method="post">
    用户名:<input type="text" name="username"><br>
    密码:<input type="password" name="password"><br>
    <input type="submit">
</form>
@RequestMapping("/testRequestBody")
public String testRequestBody(@RequestBody String requestBody){
    
    
    System.out.println("requestBody:"+requestBody);
    return "success";
}

Resultado de salida:

cuerpo de solicitud: nombre de usuario = administrador y contraseña = 123456

2、Entidad de solicitud

RequestEntity encapsula un tipo de mensaje de solicitud. Debe establecer el parámetro formal de este tipo en el parámetro formal del método del controlador. El mensaje de solicitud de la solicitud actual se asignará a este parámetro formal. Puede obtener la información del encabezado de la solicitud a través de getHeaders().Obtener información del cuerpo de la solicitud a través de getBody().

@RequestMapping("/testRequestEntity")
public String testRequestEntity(RequestEntity<String> requestEntity){
    
    
    System.out.println("requestHeader:"+requestEntity.getHeaders());
    System.out.println("requestBody:"+requestEntity.getBody());
    return "success";
}

输出结果:
requestHeader:[host:“localhost:8080”, conexión:“keep-alive”, content-length:“27”, cache-control:“max-age=0”, sec-ch-ua:“” Not A;Brand";v=“99”, “Chromium”;v=“90”, “Google Chrome”;v=“90"”, sec-ch-ua-mobile:“?0”, actualización insegura -solicitudes:“1”, origen:“http://localhost:8080”, agente-usuario:“Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, como Gecko) Chrome/90.0.4430.93 Safari/537.36”]
requestBody:nombre de usuario=admin&contraseña=123

3、@ResponseBody

@ResponseBody se utiliza para identificar un método de controlador y el valor de retorno del método se puede responder directamente al navegador como el cuerpo de respuesta del mensaje de respuesta.

@RequestMapping("/testResponseBody")
@ResponseBody
public String testResponseBody(){
    
    
    return "success";
}

Resultado: la página del navegador muestra éxito

4. SpringMVC procesa json

Pasos para que @ResponseBody procese json:

a>Importar dependencias de Jackson

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.12.1</version>
</dependency>

b> Habilite el controlador de anotaciones mvc en el archivo de configuración principal de SpringMVC. En este momento, se ensamblará automáticamente un convertidor de mensajes en HandlerAdaptor: MappingJackson2HttpMessageConverter, que puede convertir el objeto Java respondido al navegador en una cadena en formato Json.

<mvc:annotation-driven />

c>Utilice la anotación @ResponseBody en el método del procesador para identificación

d> Devuelve el objeto Java directamente como valor de retorno del método del controlador y se convertirá automáticamente en una cadena en formato Json.

@RequestMapping("/testResponseUser")
@ResponseBody
public User testResponseUser(){
    
    
    return new User(1001,"admin","123456",23,"男");
}

Los resultados mostrados en la página del navegador:

{“id”:1001,“nombre de usuario”:“admin”,“contraseña”:“123456”,“edad”:23,“sexo”:“男”}

5. SpringMVC maneja ajax

a>Solicitar hipervínculo:

<div id="app">
	<a th:href="@{/testAjax}" @click="testAjax">testAjax</a><br>
</div>

b> Manejar eventos de clic a través de vue y axios:

<script type="text/javascript" th:src="@{/static/js/vue.js}"></script>
<script type="text/javascript" th:src="@{/static/js/axios.min.js}"></script>
<script type="text/javascript">
    var vue = new Vue({
      
      
        el:"#app",
        methods:{
      
      
            testAjax:function (event) {
      
      
                axios({
      
      
                    method:"post",
                    url:event.target.href,
                    params:{
      
      
                        username:"admin",
                        password:"123456"
                    }
                }).then(function (response) {
      
      
                    alert(response.data);
                });
                event.preventDefault();
            }
        }
    });
</script>

c>Método del controlador:

@RequestMapping("/testAjax")
@ResponseBody
public String testAjax(String username, String password){
    
    
    System.out.println("username:"+username+",password:"+password);
    return "hello,ajax";
}

6. Anotación @RestController

La anotación @RestController es una anotación compuesta proporcionada por springMVC y está marcada en la clase del controlador, lo que equivale a agregar la anotación @Controller a la clase y agregar la anotación @ResponseBody a cada método.

7、Entidad de respuesta

ResponseEntity se utiliza como el tipo de valor de retorno del método del controlador, y el valor de retorno del método del controlador es el mensaje de respuesta enviado al navegador.

9. Carga y descarga de archivos

1. Descarga de archivos

Utilice ResponseEntity para implementar la función de descargar archivos

@RequestMapping("/testDown")
public ResponseEntity<byte[]> testResponseEntity(HttpSession session) throws IOException {
    
    
    //获取ServletContext对象
    ServletContext servletContext = session.getServletContext();
    //获取服务器中文件的真实路径
    String realPath = servletContext.getRealPath("/static/img/1.jpg");
    //创建输入流
    InputStream is = new FileInputStream(realPath);
    //创建字节数组
    byte[] bytes = new byte[is.available()];
    //将流读到字节数组中
    is.read(bytes);
    //创建HttpHeaders对象设置响应头信息
    MultiValueMap<String, String> headers = new HttpHeaders();
    //设置要下载方式以及下载文件的名字
    headers.add("Content-Disposition", "attachment;filename=1.jpg");
    //设置响应状态码
    HttpStatus statusCode = HttpStatus.OK;
    //创建ResponseEntity对象
    ResponseEntity<byte[]> responseEntity = new ResponseEntity<>(bytes, headers, statusCode);
    //关闭输入流
    is.close();
    return responseEntity;
}

2. Carga de archivos

La carga de archivos requiere que el método de solicitud del formulario se publique y se agregue el atributo enctype="multipart/form-data".

En SpringMVC, el archivo cargado se encapsula en el objeto MultipartFile y se puede obtener información relacionada con el archivo a través de este objeto.

Pasos para subir:

a>Agregar dependencias:

<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.3.1</version>
</dependency>

b>Agregar configuración en el archivo de configuración SpringMVC:

<!--必须通过文件解析器的解析才能将文件转换为MultipartFile对象-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean>

c>Método del controlador:

@RequestMapping("/testUp")
public String testUp(MultipartFile photo, HttpSession session) throws IOException {
    
    
    //获取上传的文件的文件名
    String fileName = photo.getOriginalFilename();
    //处理文件重名问题
    String hzName = fileName.substring(fileName.lastIndexOf("."));
    fileName = UUID.randomUUID().toString() + hzName;
    //获取服务器中photo目录的路径
    ServletContext servletContext = session.getServletContext();
    String photoPath = servletContext.getRealPath("photo");
    File file = new File(photoPath);
    if(!file.exists()){
    
    
        file.mkdir();
    }
    String finalPath = photoPath + File.separator + fileName;
    //实现上传功能
    photo.transferTo(new File(finalPath));
    return "success";
}

10. interceptor

1. Configuración del interceptor

Los interceptores en SpringMVC se utilizan para interceptar la ejecución de métodos del controlador.

Los interceptores en SpringMVC necesitan implementar HandlerInterceptor

El interceptor de SpringMVC debe configurarse en el archivo de configuración de SpringMVC:

<bean class="com.atguigu.interceptor.FirstInterceptor"></bean>
<ref bean="firstInterceptor"></ref>
<!-- 以上两种配置方式都是对DispatcherServlet所处理的所有的请求进行拦截 -->
<mvc:interceptor>
    <mvc:mapping path="/**"/>
    <mvc:exclude-mapping path="/testRequestEntity"/>
    <ref bean="firstInterceptor"></ref>
</mvc:interceptor>
<!-- 
	以上配置方式可以通过ref或bean标签设置拦截器,通过mvc:mapping设置需要拦截的请求,通过mvc:exclude-mapping设置需要排除的请求,即不需要拦截的请求
-->

2. Tres métodos abstractos de interceptores.

El interceptor en SpringMVC tiene tres métodos abstractos:

preHandle: preHandle() se ejecuta antes de que se ejecute el método del controlador. Su valor de retorno de tipo booleano indica si se intercepta o se libera. Devolver verdadero significa liberar, es decir, llamar al método del controlador; devolver falso significa interceptar, es decir, no llamar al método del controlador.

postHandle: ejecuta postHandle() después de ejecutar el método del controlador

afterComplation: después de procesar la vista y los datos del modelo, ejecute afterComplation() después de representar la vista.

3. Orden de ejecución de múltiples interceptores.

a>Si preHandle() de cada interceptor devuelve verdadero

En este momento, el orden de ejecución de múltiples interceptores está relacionado con el orden de configuración de los interceptores en el archivo de configuración SpringMVC:

preHandle() se ejecutará en el orden configurado, mientras que postHandle() y afterComplation() se ejecutarán en el orden inverso de la configuración.

b>Si preHandle() de un interceptor devuelve falso

Tanto preHandle() devuelve falso como el preHandle() del interceptor antes de que se ejecute, postHandle() no se ejecutará y afterComplation() del interceptor antes de que se ejecute el interceptor que devuelve falso.

11. Manejador de excepciones

1. Manejo de excepciones basado en configuración

SpringMVC proporciona una interfaz para manejar las excepciones que ocurren durante la ejecución de los métodos del controlador: HandlerExceptionResolver

Las clases de implementación de la interfaz HandlerExceptionResolver son: DefaultHandlerExceptionResolver y SimpleMappingExceptionResolver

SpringMVC proporciona un controlador de excepciones personalizado SimpleMappingExceptionResolver. Cómo usarlo:

<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
    <property name="exceptionMappings">
        <props>
        	<!--
        		properties的键表示处理器方法执行过程中出现的异常
        		properties的值表示若出现指定异常时,设置一个新的视图名称,跳转到指定页面
        	-->
            <prop key="java.lang.ArithmeticException">error</prop>
        </props>
    </property>
    <!--
    	exceptionAttribute属性设置一个属性名,将出现的异常信息在请求域中进行共享
    -->
    <property name="exceptionAttribute" value="ex"></property>
</bean>

2. Manejo de excepciones basado en anotaciones

//@ControllerAdvice将当前类标识为异常处理的组件
@ControllerAdvice
public class ExceptionController {
    
    
    //@ExceptionHandler用于设置所标识方法处理的异常
    @ExceptionHandler(ArithmeticException.class)
    //ex表示当前请求处理中出现的异常对象
    public String handleArithmeticException(Exception ex, Model model){
    
    
        model.addAttribute("ex", ex);
        return "error";
    }
}

12. Configuración de anotaciones SpringMVC

Utilice clases de configuración y anotaciones para reemplazar la funcionalidad de los archivos de configuración web.xml y SpringMVC.

1. Cree una clase de inicialización en lugar de web.xml

En el entorno Servlet3.0, el contenedor buscará la clase que implementa la interfaz javax.servlet.ServletContainerInitializer en el classpath y, si la encuentra, la utilizará para configurar el contenedor de Servlet.
Spring proporciona una implementación de esta interfaz, llamada SpringServletContainerInitializer. Esta clase, a su vez, encontrará clases que implementen WebApplicationInitializer y les entregará las tareas de configuración. Spring 3.2 presenta una implementación básica conveniente de WebApplicationInitializer llamada AbstractAnnotationConfigDispatcherServletInitializer. Cuando nuestra clase extiende AbstractAnnotationConfigDispatcherServletInitializer y lo implementa en el contenedor Servlet3.0, el contenedor lo descubrirá automáticamente y lo usará para configurar el contexto de Servlet.

public class WebInit extends AbstractAnnotationConfigDispatcherServletInitializer {
    
    

    /**
     * 指定spring的配置类
     * @return
     */
    @Override
    protected Class<?>[] getRootConfigClasses() {
    
    
        return new Class[]{
    
    SpringConfig.class};
    }

    /**
     * 指定SpringMVC的配置类
     * @return
     */
    @Override
    protected Class<?>[] getServletConfigClasses() {
    
    
        return new Class[]{
    
    WebConfig.class};
    }

    /**
     * 指定DispatcherServlet的映射规则,即url-pattern
     * @return
     */
    @Override
    protected String[] getServletMappings() {
    
    
        return new String[]{
    
    "/"};
    }

    /**
     * 添加过滤器
     * @return
     */
    @Override
    protected Filter[] getServletFilters() {
    
    
        CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter();
        encodingFilter.setEncoding("UTF-8");
        encodingFilter.setForceRequestEncoding(true);
        HiddenHttpMethodFilter hiddenHttpMethodFilter = new HiddenHttpMethodFilter();
        return new Filter[]{
    
    encodingFilter, hiddenHttpMethodFilter};
    }
}

2. Cree la clase de configuración SpringConfig para reemplazar el archivo de configuración de Spring.

@Configuration
public class SpringConfig {
    
    
	//ssm整合之后,spring的配置信息写在此类中
}

3. Cree una clase de configuración WebConfig para reemplazar el archivo de configuración SpringMVC

@Configuration
//扫描组件
@ComponentScan("com.atguigu.mvc.controller")
//开启MVC注解驱动
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
    
    
    //使用默认的servlet处理静态资源
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
    
    
        configurer.enable();
    }

    //配置文件上传解析器
    @Bean
    public CommonsMultipartResolver multipartResolver(){
    
    
        return new CommonsMultipartResolver();
    }

    //配置拦截器
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
    
    
        FirstInterceptor firstInterceptor = new FirstInterceptor();
        registry.addInterceptor(firstInterceptor).addPathPatterns("/**");
    }
    
    //配置视图控制
    
    /*@Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("index");
    }*/
    
    //配置异常映射
    /*@Override
    public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
        SimpleMappingExceptionResolver exceptionResolver = new SimpleMappingExceptionResolver();
        Properties prop = new Properties();
        prop.setProperty("java.lang.ArithmeticException", "error");
        //设置异常映射
        exceptionResolver.setExceptionMappings(prop);
        //设置共享异常信息的键
        exceptionResolver.setExceptionAttribute("ex");
        resolvers.add(exceptionResolver);
    }*/

    //配置生成模板解析器
    @Bean
    public ITemplateResolver templateResolver() {
    
    
        WebApplicationContext webApplicationContext = ContextLoader.getCurrentWebApplicationContext();
        // ServletContextTemplateResolver需要一个ServletContext作为构造参数,可通过WebApplicationContext 的方法获得
        ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(
                webApplicationContext.getServletContext());
        templateResolver.setPrefix("/WEB-INF/templates/");
        templateResolver.setSuffix(".html");
        templateResolver.setCharacterEncoding("UTF-8");
        templateResolver.setTemplateMode(TemplateMode.HTML);
        return templateResolver;
    }

    //生成模板引擎并为模板引擎注入模板解析器
    @Bean
    public SpringTemplateEngine templateEngine(ITemplateResolver templateResolver) {
    
    
        SpringTemplateEngine templateEngine = new SpringTemplateEngine();
        templateEngine.setTemplateResolver(templateResolver);
        return templateEngine;
    }

    //生成视图解析器并未解析器注入模板引擎
    @Bean
    public ViewResolver viewResolver(SpringTemplateEngine templateEngine) {
    
    
        ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
        viewResolver.setCharacterEncoding("UTF-8");
        viewResolver.setTemplateEngine(templateEngine);
        return viewResolver;
    }


}

4. Función de prueba

@RequestMapping("/")
public String index(){
    
    
    return "index";
}

13. Proceso de ejecución de SpringMVC

1. Componentes comunes de SpringMVC

  • DispatcherServlet: controlador front-end , no requiere desarrollo de ingenieros, proporcionado por el marco

Función: procesamiento unificado de solicitudes y respuestas, el centro de todo el control del proceso, que llama a otros componentes para manejar las solicitudes de los usuarios.

  • HandlerMapping: mapeador de procesadores , que no requiere desarrollo de ingenieros y lo proporciona el marco

Función: busque el controlador, es decir, el método del controlador, según la URL solicitada, el método y otra información.

  • Controlador: Procesador , requiere ingenieros para desarrollarlo

Función: bajo el control de DispatcherServlet, Handler procesa solicitudes de usuarios específicas.

  • HandlerAdapter: adaptador de procesador , no requiere desarrollo de ingenieros, proporcionado por el marco

Función: ejecutar el procesador (método del controlador) a través de HandlerAdapter

  • ViewResolver: View resolver , que no requiere que los ingenieros lo desarrollen y lo proporciona el marco

Función: realizar análisis de vista y obtener la vista correspondiente, como: ThymeleafView, InternalResourceView, RedirectView

  • Ver: ver

Función: Mostrar datos del modelo a los usuarios a través de la página.

2. Proceso de inicialización de DispatcherServlet

DispatcherServlet es esencialmente un Servlet, por lo que naturalmente sigue el ciclo de vida del Servlet. Macroscópicamente es el ciclo de vida del Servlet para la programación.

La transferencia de la imagen del enlace externo falló. El sitio de origen puede tener un mecanismo anti-leeching. Se recomienda guardar la imagen y cargarla directamente.

a>Inicializar WebApplicationContext

Clase: org.springframework.web.servlet.FrameworkServlet

protected WebApplicationContext initWebApplicationContext() {
    
    
    WebApplicationContext rootContext =
        WebApplicationContextUtils.getWebApplicationContext(getServletContext());
    WebApplicationContext wac = null;

    if (this.webApplicationContext != null) {
    
    
        // A context instance was injected at construction time -> use it
        wac = this.webApplicationContext;
        if (wac instanceof ConfigurableWebApplicationContext) {
    
    
            ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
            if (!cwac.isActive()) {
    
    
                // The context has not yet been refreshed -> provide services such as
                // setting the parent context, setting the application context id, etc
                if (cwac.getParent() == null) {
    
    
                    // The context instance was injected without an explicit parent -> set
                    // the root application context (if any; may be null) as the parent
                    cwac.setParent(rootContext);
                }
                configureAndRefreshWebApplicationContext(cwac);
            }
        }
    }
    if (wac == null) {
    
    
        // No context instance was injected at construction time -> see if one
        // has been registered in the servlet context. If one exists, it is assumed
        // that the parent context (if any) has already been set and that the
        // user has performed any initialization such as setting the context id
        wac = findWebApplicationContext();
    }
    if (wac == null) {
    
    
        // No context instance is defined for this servlet -> create a local one
        // 创建WebApplicationContext
        wac = createWebApplicationContext(rootContext);
    }

    if (!this.refreshEventReceived) {
    
    
        // Either the context is not a ConfigurableApplicationContext with refresh
        // support or the context injected at construction time had already been
        // refreshed -> trigger initial onRefresh manually here.
        synchronized (this.onRefreshMonitor) {
    
    
            // 刷新WebApplicationContext
            onRefresh(wac);
        }
    }

    if (this.publishContext) {
    
    
        // Publish the context as a servlet context attribute.
        // 将IOC容器在应用域共享
        String attrName = getServletContextAttributeName();
        getServletContext().setAttribute(attrName, wac);
    }

    return wac;
}
b>Crear contexto de aplicación web

Clase: org.springframework.web.servlet.FrameworkServlet

protected WebApplicationContext createWebApplicationContext(@Nullable ApplicationContext parent) {
    
    
    Class<?> contextClass = getContextClass();
    if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
    
    
        throw new ApplicationContextException(
            "Fatal initialization error in servlet with name '" + getServletName() +
            "': custom WebApplicationContext class [" + contextClass.getName() +
            "] is not of type ConfigurableWebApplicationContext");
    }
    // 通过反射创建 IOC 容器对象
    ConfigurableWebApplicationContext wac =
        (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);

    wac.setEnvironment(getEnvironment());
    // 设置父容器
    wac.setParent(parent);
    String configLocation = getContextConfigLocation();
    if (configLocation != null) {
    
    
        wac.setConfigLocation(configLocation);
    }
    configureAndRefreshWebApplicationContext(wac);

    return wac;
}
c> Estrategia de inicialización de DispatcherServlet

Después de que FrameworkServlet crea WebApplicationContext, actualice el contenedor y llame a onRefresh (wac), este método se reescribe en DispatcherServlet y llama al método initStrategies (contexto) para inicializar la estrategia, es decir, inicializar cada componente de DispatcherServlet.

Clase: org.springframework.web.servlet.DispatcherServlet

protected void initStrategies(ApplicationContext context) {
    
    
   initMultipartResolver(context);
   initLocaleResolver(context);
   initThemeResolver(context);
   initHandlerMappings(context);
   initHandlerAdapters(context);
   initHandlerExceptionResolvers(context);
   initRequestToViewNameTranslator(context);
   initViewResolvers(context);
   initFlashMapManager(context);
}

3. DispatcherServlet llama al componente para procesar la solicitud.

a>procesoSolicitud()

FrameworkServlet reescribe service() y doXxx() en HttpServlet, y se llama a ProcessRequest(solicitud, respuesta) en estos métodos.

Clase: org.springframework.web.servlet.FrameworkServlet

protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
    
    

    long startTime = System.currentTimeMillis();
    Throwable failureCause = null;

    LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
    LocaleContext localeContext = buildLocaleContext(request);

    RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
    ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);

    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
    asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());

    initContextHolders(request, localeContext, requestAttributes);

    try {
    
    
		// 执行服务,doService()是一个抽象方法,在DispatcherServlet中进行了重写
        doService(request, response);
    }
    catch (ServletException | IOException ex) {
    
    
        failureCause = ex;
        throw ex;
    }
    catch (Throwable ex) {
    
    
        failureCause = ex;
        throw new NestedServletException("Request processing failed", ex);
    }

    finally {
    
    
        resetContextHolders(request, previousLocaleContext, previousAttributes);
        if (requestAttributes != null) {
    
    
            requestAttributes.requestCompleted();
        }
        logResult(request, response, failureCause, asyncManager);
        publishRequestHandledEvent(request, response, startTime, failureCause);
    }
}
b>hacerServicio()

Clase: org.springframework.web.servlet.DispatcherServlet

@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
    
    
    logRequest(request);

    // Keep a snapshot of the request attributes in case of an include,
    // to be able to restore the original attributes after the include.
    Map<String, Object> attributesSnapshot = null;
    if (WebUtils.isIncludeRequest(request)) {
    
    
        attributesSnapshot = new HashMap<>();
        Enumeration<?> attrNames = request.getAttributeNames();
        while (attrNames.hasMoreElements()) {
    
    
            String attrName = (String) attrNames.nextElement();
            if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {
    
    
                attributesSnapshot.put(attrName, request.getAttribute(attrName));
            }
        }
    }

    // Make framework objects available to handlers and view objects.
    request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
    request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
    request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
    request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());

    if (this.flashMapManager != null) {
    
    
        FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
        if (inputFlashMap != null) {
    
    
            request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
        }
        request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
        request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
    }

    RequestPath requestPath = null;
    if (this.parseRequestPath && !ServletRequestPathUtils.hasParsedRequestPath(request)) {
    
    
        requestPath = ServletRequestPathUtils.parseAndCache(request);
    }

    try {
    
    
        // 处理请求和响应
        doDispatch(request, response);
    }
    finally {
    
    
        if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
    
    
            // Restore the original attribute snapshot, in case of an include.
            if (attributesSnapshot != null) {
    
    
                restoreAttributesAfterInclude(request, attributesSnapshot);
            }
        }
        if (requestPath != null) {
    
    
            ServletRequestPathUtils.clearParsedRequestPath(request);
        }
    }
}
c>hacerDispatch()

Clase: org.springframework.web.servlet.DispatcherServlet

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    
    
    HttpServletRequest processedRequest = request;
    HandlerExecutionChain mappedHandler = null;
    boolean multipartRequestParsed = false;

    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

    try {
    
    
        ModelAndView mv = null;
        Exception dispatchException = null;

        try {
    
    
            processedRequest = checkMultipart(request);
            multipartRequestParsed = (processedRequest != request);

            // Determine handler for the current request.
            /*
            	mappedHandler:调用链
                包含handler、interceptorList、interceptorIndex
            	handler:浏览器发送的请求所匹配的控制器方法
            	interceptorList:处理控制器方法的所有拦截器集合
            	interceptorIndex:拦截器索引,控制拦截器afterCompletion()的执行
            */
            mappedHandler = getHandler(processedRequest);
            if (mappedHandler == null) {
    
    
                noHandlerFound(processedRequest, response);
                return;
            }

            // Determine handler adapter for the current request.
           	// 通过控制器方法创建相应的处理器适配器,调用所对应的控制器方法
            HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

            // Process last-modified header, if supported by the handler.
            String method = request.getMethod();
            boolean isGet = "GET".equals(method);
            if (isGet || "HEAD".equals(method)) {
    
    
                long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
    
    
                    return;
                }
            }
			
            // 调用拦截器的preHandle()
            if (!mappedHandler.applyPreHandle(processedRequest, response)) {
    
    
                return;
            }

            // Actually invoke the handler.
            // 由处理器适配器调用具体的控制器方法,最终获得ModelAndView对象
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

            if (asyncManager.isConcurrentHandlingStarted()) {
    
    
                return;
            }

            applyDefaultViewName(processedRequest, mv);
            // 调用拦截器的postHandle()
            mappedHandler.applyPostHandle(processedRequest, response, mv);
        }
        catch (Exception ex) {
    
    
            dispatchException = ex;
        }
        catch (Throwable err) {
    
    
            // As of 4.3, we're processing Errors thrown from handler methods as well,
            // making them available for @ExceptionHandler methods and other scenarios.
            dispatchException = new NestedServletException("Handler dispatch failed", err);
        }
        // 后续处理:处理模型数据和渲染视图
        processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    }
    catch (Exception ex) {
    
    
        triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
    }
    catch (Throwable err) {
    
    
        triggerAfterCompletion(processedRequest, response, mappedHandler,
                               new NestedServletException("Handler processing failed", err));
    }
    finally {
    
    
        if (asyncManager.isConcurrentHandlingStarted()) {
    
    
            // Instead of postHandle and afterCompletion
            if (mappedHandler != null) {
    
    
                mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
            }
        }
        else {
    
    
            // Clean up any resources used by a multipart request.
            if (multipartRequestParsed) {
    
    
                cleanupMultipart(processedRequest);
            }
        }
    }
}
d>procesoDispatchResult()
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
                                   @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
                                   @Nullable Exception exception) throws Exception {
    
    

    boolean errorView = false;

    if (exception != null) {
    
    
        if (exception instanceof ModelAndViewDefiningException) {
    
    
            logger.debug("ModelAndViewDefiningException encountered", exception);
            mv = ((ModelAndViewDefiningException) exception).getModelAndView();
        }
        else {
    
    
            Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
            mv = processHandlerException(request, response, handler, exception);
            errorView = (mv != null);
        }
    }

    // Did the handler return a view to render?
    if (mv != null && !mv.wasCleared()) {
    
    
        // 处理模型数据和渲染视图
        render(mv, request, response);
        if (errorView) {
    
    
            WebUtils.clearErrorRequestAttributes(request);
        }
    }
    else {
    
    
        if (logger.isTraceEnabled()) {
    
    
            logger.trace("No view rendering, null ModelAndView returned.");
        }
    }

    if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
    
    
        // Concurrent handling started during a forward
        return;
    }

    if (mappedHandler != null) {
    
    
        // Exception (if any) is already handled..
        // 调用拦截器的afterCompletion()
        mappedHandler.triggerAfterCompletion(request, response, null);
    }
}

4. Proceso de ejecución de SpringMVC

  1. El usuario envía una solicitud al servidor y la solicitud es capturada por el controlador front-end SpringMVC DispatcherServlet.

  2. DispatcherServlet analiza la URL de la solicitud, obtiene el identificador de recurso de la solicitud (URI) y determina la asignación correspondiente al URI de la solicitud:

a) no existe

I. Luego determine si mvc:default-servlet-handler está configurado

ii. Si no está configurado, la consola informa que no se puede encontrar la asignación y el cliente muestra un error 404.

La transferencia de la imagen del enlace externo falló. El sitio de origen puede tener un mecanismo anti-leeching. Se recomienda guardar la imagen y cargarla directamente.

La transferencia de la imagen del enlace externo falló. El sitio de origen puede tener un mecanismo anti-leeching. Se recomienda guardar la imagen y cargarla directamente.

iii) Si está configurado, acceda a los recursos de destino (generalmente recursos estáticos, como JS, CSS, HTML) y se mostrará un error 404 si no se puede encontrar el cliente.

La transferencia de la imagen del enlace externo falló. El sitio de origen puede tener un mecanismo anti-leeching. Se recomienda guardar la imagen y cargarla directamente.

La transferencia de la imagen del enlace externo falló. El sitio de origen puede tener un mecanismo anti-leeching. Se recomienda guardar la imagen y cargarla directamente.

b) Si existe ejecutar el siguiente proceso

  1. De acuerdo con el URI, llame a HandlerMapping para obtener todos los objetos relacionados configurados por el Handler (incluido el objeto Handler y el interceptor correspondiente al objeto Handler) y finalmente devuélvalo en forma de un objeto de cadena de ejecución HandlerExecutionChain.

  2. DispatcherServlet selecciona un HandlerAdapter adecuado según el Handler obtenido.

  3. Si el HandlerAdapter se obtiene con éxito, se ejecutará el método preHandler (...) del interceptor [adelante]

  4. Extraiga los datos del modelo en la Solicitud, complete los parámetros de entrada del Controlador y comience a ejecutar el método Controlador (Controlador) para procesar la solicitud. Durante el proceso de completar los parámetros de entrada del Handler, Spring lo ayudará a realizar un trabajo adicional de acuerdo con su configuración:

a) HttpMessageConveter: convierte el mensaje de solicitud (como Json, xml y otros datos) en un objeto y convierte el objeto en la información de respuesta especificada

b) Conversión de datos: realiza la conversión de datos en el mensaje de solicitud. Como cadena convertida a entero, doble, etc.

c) Formato de datos: Formatee los datos del mensaje de solicitud. Como convertir cadenas en números formateados o fechas formateadas, etc.

d) Verificación de datos: verifique la validez de los datos (longitud, formato, etc.) y almacene los resultados de la verificación en BindingResult o Error.

  1. Una vez completada la ejecución del controlador, se devuelve un objeto ModelAndView a DispatcherServlet.

  2. En este punto, el método postHandle(...) [reverso] del interceptor comenzará a ejecutarse.

  3. De acuerdo con el ModelAndView devuelto (en este momento, se juzgará si hay una excepción: si hay una excepción, se ejecuta HandlerExceptionResolver para el manejo de excepciones), seleccione un ViewResolver adecuado para el análisis de la vista y renderice la vista según el Modelo y Vista.

  4. Después de renderizar la vista, ejecute el método afterCompletion(...) del interceptor [reverso].

    }
    }

    // ¿El controlador devolvió una vista para renderizar?
    if (mv != null && !mv.wasCleared()) { // Procesa los datos del modelo y renderiza la vista render(mv, request, Response); if (errorView) { WebUtils . clearErrorRequestAttributes(solicitud); } } else { if (logger.isTraceEnabled()) { logger.trace(“Sin representación de vista, se devolvió ModelAndView nulo.”); } }










    if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) { // El manejo simultáneo comenzó durante un retorno directo; }


    if (mappedHandler != null) { // La excepción (si la hay) ya está manejada... // Llama al afterCompletion() del interceptor mappedHandler.triggerAfterCompletion(solicitud, respuesta, nulo); } }





### 4、SpringMVC的执行流程

1) 用户向服务器发送请求,请求被SpringMVC 前端控制器 DispatcherServlet捕获。

2) DispatcherServlet对请求URL进行解析,得到请求资源标识符(URI),判断请求URI对应的映射:

a) 不存在

i. 再判断是否配置了mvc:default-servlet-handler

ii. 如果没配置,则控制台报映射查找不到,客户端展示404错误

[外链图片转存中...(img-JwWEyby8-1702221928324)]

[外链图片转存中...(img-Eq32mYn2-1702221928326)]

iii. 如果有配置,则访问目标资源(一般为静态资源,如:JS,CSS,HTML),找不到客户端也会展示404错误

[外链图片转存中...(img-aKTxc4DY-1702221928329)]

[外链图片转存中...(img-1JlW7wCV-1702221928331)]

b) 存在则执行下面的流程

3) 根据该URI,调用HandlerMapping获得该Handler配置的所有相关的对象(包括Handler对象以及Handler对象对应的拦截器),最后以HandlerExecutionChain执行链对象的形式返回。

4) DispatcherServlet 根据获得的Handler,选择一个合适的HandlerAdapter。

5) 如果成功获得HandlerAdapter,此时将开始执行拦截器的preHandler(…)方法【正向】

6) 提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)方法,处理请求。在填充Handler的入参过程中,根据你的配置,Spring将帮你做一些额外的工作:

a) HttpMessageConveter: 将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定的响应信息

b) 数据转换:对请求消息进行数据转换。如String转换成Integer、Double等

c) 数据格式化:对请求消息进行数据格式化。 如将字符串转换成格式化数字或格式化日期等

d) 数据验证: 验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中

7) Handler执行完成后,向DispatcherServlet 返回一个ModelAndView对象。

8) 此时将开始执行拦截器的postHandle(...)方法【逆向】。

9) 根据返回的ModelAndView(此时会判断是否存在异常:如果存在异常,则执行HandlerExceptionResolver进行异常处理)选择一个适合的ViewResolver进行视图解析,根据Model和View,来渲染视图。

10) 渲染视图完毕执行拦截器的afterCompletion(…)方法【逆向】。

11) 将渲染结果返回给客户端。

Supongo que te gusta

Origin blog.csdn.net/zhangchen124/article/details/134916791
Recomendado
Clasificación