Análisis profundo de Spring MVC desde la perspectiva del código fuente

Spring MVC tiene una clara división de roles, una división detallada del trabajo y una integración perfecta con el marco Spring. Spring MVC se ha convertido en uno de los marcos actuales más convencionales. Y con el lanzamiento de Spring3.0, superó a Struts2 para convertirse en el mejor marco MVC.

Pero muchos desarrolladores solo saben escribir, pero no saben por qué escriben de esta manera o cómo optimizar, lo cual es muy peligroso. Y según mis muchos años de experiencia, los problemas de Spring MVC son puntos de inspección de alta frecuencia que aparecen durante el proceso de entrevista, y los principales fabricantes prestan más atención al análisis del código fuente de los desarrolladores.

Comparto uno aquí. Hay muchos productos secos, que incluyen explicaciones detalladas sobre jvm, netty, spring, threads, spring cloud, etc., así como diagramas de planificación de estudio detallados, preguntas de entrevista, etc. Siento que la entrevista es muy clara: Obtenga una entrevista Sólo información: Haga clic aquí para recibir !!! Contraseña: CSDNInserte la descripción de la imagen aquí

Muchas grandes empresas preguntarán: ¿Cuánto sabe sobre el código fuente de Spring MVC? ¿Tiene capacidades de análisis de código fuente?
Por ejemplo, los dos contenidos siguientes:
¿Cuál es el flujo de procesamiento de solicitudes de Spring MVC?
Inserte la descripción de la imagen aquí

El método ha.handle en el marco Spring MVC

Entrada
Inserte la descripción de la imagen aquí

Desde la boca hasta el descanso Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
como desarrollador, el marco de origen captar la profundidad de las capacidades de análisis es particularmente importante en la entrevista y el trabajo. Si solo puede usar el marco, solo puede hacer algunos sistemas back-end simples (sistemas de nivel empresarial) y nunca podrá realizar proyectos a nivel de departamento, de empresa o de Apache.

principio de funcionamiento

El usuario envía una solicitud al controlador frontal DispatcherServlet proporcionado por el marco springMVC (los amigos que conocen Struts2 también saben que, de hecho, Struts2 también tiene un controlador frontal, la etiqueta Filter en web.xml)

El controlador frontal irá al procesador al mapeador (HandlerMapping), el mapeador del procesador encuentra el procesador específico de acuerdo con la URL de la solicitud, genera el objeto del procesador y el interceptor de procesamiento (si lo hay) y lo devuelve al DispatcherServlet.

Según el procesador devuelto por el mapeador de procesadores, DispatcherServlet encontrará un adaptador de procesador "adecuado" (HandlerAdapter)

El adaptador de procesador HandlerAdapter ejecutará el procesador (cuando se desarrolle el Handler, se llamará controlador o controlador front-end, y la acción en struts2 también es un controlador back-end) antes de la ejecución, habrá convertidores, enlace de datos, validadores, etc. Espere hasta que se complete lo anterior antes de volver a ejecutar

Manipulador

El controlador de back-end Handler devuelve un objeto ModelAndView después de que se completa la ejecución. El
adaptador de procesador HandlerAdapter devuelve este ModelAndView al controlador de front-end DispatcherServlet. El controlador de front-end le dará el objeto ModelAndView al solucionador de vistas ViewResolver
ViewResolver analiza el objeto ModelAndView y devuelve la lógica Ver. El
controlador frontal DispatcherServlet muestra la vista lógica (completa los datos) y luego devuelve la Vista física real y responde al navegador.
Descripción del componente

DispatcherServlet: controlador frontal

La solicitud del usuario llega al controlador frontal, que es equivalente a C en MVC, y DispatcherServlet es el núcleo de todo el proceso. Llama a otros componentes para procesar las solicitudes del usuario. La existencia del controlador frontal reduce el acoplamiento entre otros componentes.

HandlerMapping: Handler Mapper

Su función es como ir al cine, sosteniendo un boleto de cine para encontrar el asiento en el asiento de acuerdo con el número de asiento en el boleto de cine, donde el asiento es el Manejador, y el boleto de cine y el número de asiento son la URL.

HandlerMapping es responsable de encontrar el Handler que es el procesador de acuerdo a la solicitud del usuario SpringMVC proporciona diferentes mapeadores para implementar diferentes métodos de mapeo, tales como: método de archivo de configuración, método de interfaz de implementación, método de anotación, etc.

Handler: Handler

Handler es un controlador de back-end. El controlador de back-end procesa solicitudes específicas de usuario bajo el control del controlador frontal. Handler implica solicitudes de usuario específicas, por lo que, en general, los programadores deben desarrollarse de acuerdo con su propio negocio.

HandlerAdapter: adaptador de procesador

El procesador se ejecuta a través del HandlerAdapter, que es una aplicación del modo adaptador, y se pueden ejecutar más tipos de procesadores a través del adaptador.

La película que se está reproduciendo es en 3D y no se puede ver con claridad. La sala de cine le indica que debe usar gafas 3D si desea ver la película con claridad, lo que significa que el controlador cumple con ciertos requisitos y se pueden realizar conjeturas.

Configuración de SpringMVC

El controlador frontal debe configurarse en web.xml

<? xml version = "1.0" encoding = "UTF-8"?>

<!-- 配置前端控制器 -->
<servlet>
    <servlet-name>web-dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!--加载前端控制器配置文件 上下文配置位置-->
    <init-param>
        <!-- 备注:
            contextConfigLocation:指定 SpringMVC 配置的加载位置,如果不指定则默认加载
            WEB-INF/[DispatcherServlet 的 Servlet 名字]-servlet.xml
         -->
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring/spring-*.xml</param-value>
    </init-param>
    <!-- 表示随WEB服务器启动 -->
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>web-dispatcher</servlet-name>
    <!-- 备注:可以拦截三种请求
        第一种:拦截固定后缀的url,比如设置为 *.do、*.action, 例如:/user/add.action 此方法最简单,不会导致静态资源(jpg,js,css)被拦截
        第二种:拦截所有,设置为/,例如:/user/add  /user/add.action此方法可以实现REST风格的url,
        很多互联网类型的应用使用这种方式.但是此方法会导致静态文件(jpg,js,css)被拦截后不能正常显示.需要特殊处理
        第三种:拦截所有,设置为/*,此设置方法错误,因为请求到Action,当action转到jsp时再次被拦截,提示不能根据jsp路径mapping成功
       -->
        <!-- 默认匹配所有的请求 -->
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

在spring/spring-web.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.3.xsd
     http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
     http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
    <!-- 配置视图解析器 -->
    <!-- InternalResourceViewResolver:支持JSP视图解析 -->
    <!-- viewClass:JstlView 表示JSP模板页面需要使用JSTL标签库,所以classpath中必须包含jstl的相关jar包; -->
    <!-- prefix 和 suffix:查找视图页面的前缀和后缀,最终视图的址为: -->
    <!-- 前缀+逻辑视图名+后缀,逻辑视图名需要在controller中返回ModelAndView指定,比如逻辑视图名为hello,-->
    <!-- 则最终返回的jsp视图地址 "WEB-INF/jsp/hello.jsp" -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!-- 决定视图类型,如果添加了jstl支持(即有jstl.jar),那么默认就是解析为jstl视图 -->
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
        <!-- 视图前缀 -->
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <!-- 视图后缀 -->
        <property name="suffix" value=".jsp"/>
    </bean>
</beans>
在spring/spring-web.xml的注解模式

<!-- 自动加载RequestMappingHandlerMapping和RequestMappingHandlerAdapter, -->
<!-- 可用在xml配置文件中使用<mvc:annotation-driven>替代注解处理器和适配器的配置。 -->
<mvc:annotation-driven/>
在spring/spring-web.xml 配置扫描web相关的bean

<contexto: componente-scan base-package = "com.controller" />

Anotaciones en springMVC

La anotación @Controller se
usa para identificar que esta clase es un controlador de back-end (similar a las acciones de struts2), la función principal es recibir parámetros de página y reenviar la página

@controlador código fuente:

@Target ({ElementType.TYPE}) // Indica que solo se puede definir en la clase
@Retention (RetentionPolicy.RUNTIME) // La política de retención es RUNTIME. Cuando la JVM carga la clase, la anotación se cargará en la memoria de la JVM (es la única Puede usar la reflexión para leer la estrategia de anotación)
@Documented // @ Documented se usa para describir que otros tipos de anotaciones deben usarse como la API pública de los miembros del programa marcados, para que puedan documentarse con herramientas como javadoc. Documentado es una anotación de marca y no tiene miembros.
@Component // El marco de Spring estipula que esta anotación se puede usar cuando una clase no está bien clasificada (servicio, dao, controlador), lo que muestra que la anotación @Component todavía se usa incluso si está bien clasificada

public @interface Controller {
    
    
    /**
     * The value may indicate a suggestion for a logical component name,
     * to be turned into a Spring bean in case of an autodetected component.
     * @return the suggested component name, if any
     */
    String value() default "";
}
@RequestMapping

La función de esta anotación es diferente de @ Controller. Esta anotación se puede definir en la clase o en el método.

/**
* 1.@RequestMapping:除了修饰方法,还可以修饰类
* 2.类定义处:提供初步的请求信息映射.相对于WEB应用的根目录(窄化请求)
* 3.方法处:提供进一步的细分映射信息。相对于类定义处的URL。
*      若类定义处为标注@RequestMapping,则方法出的URL相对于WEB应用的根目录
*/
@Target({
    
    ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {
    
    
    String[] value() default {
    
    };
    RequestMethod[] method() default {
    
    }; //限制请求方式
    String[] params() default {
    
    }; //要求请求的URL包含指定的参数
}

Ejemplo de código

@Controller
@RequestMapping("/demo")
public class IndexController {
    
    
    @RequestMapping(value = "/test", method = RequestMethod.GET)
    public String index(Model model, HttpServletRequest request) {
    
    
        // 在游览器访问 http://localhost:8080/demo/test 将进入这里
        model.addAttribute("originURL", "");
        model.addAttribute("controllerName", "index");
        return "index";
    }
}
@RequestMapping还支持Ant方格的请求
?:匹配文件中的一个字符
*:匹配文件中任意字符
****匹配多层路径
/user/*/createUser : 匹配 -/user/aa/createUser 或者 -/user/aa/createUser
/user/**/createUser : 匹配 -/user/aa/createUser 或者 -/user/createUser 或者 -/user/aa/cc/createUser
/user/createUser?? : 匹配 -/user/aa/createUseraa
@PathVariable

Esta anotación es compatible con las URL de estilo Restful más populares. Permítanme hablar primero sobre la función de esta anotación. Admite vincular los parámetros del marcador de posición en la URL a los parámetros del método de destino. Esta función también es una medida importante para que springMVC implemente la URL de estilo Restful. .

Código

// http://localhost:8080/demo/sss
@RequestMapping(value = "/{slug:.+}", method = RequestMethod.GET)
    public String index2(@PathVariable("slug") String slug, Model model) {
    
    
    LOG.info("DemoController index2 slug  " + slug);
    // common
    model.addAttribute("originURL", "demo/");
    model.addAttribute("controllerName", "demo");
    model.addAttribute("controllerMethod", "index2");
    model.addAttribute("slug", slug);
    return "demo";
}

//slug = sss

Las solicitudes con las que estamos familiarizados deben ser solicitudes POST y GET. Estas dos solicitudes también son las más utilizadas. De hecho, la solicitud http1.1 sigue siendo put, delete y otros 8 tipos de acciones para solicitar el nombre de la tabla.

Para implementar las solicitudes de colocación y eliminación en springMVC, debe configurar un filtro adicional en web.xml. La función de este filtro es cambiar las solicitudes de publicación en solicitudes de colocación y eliminación.

@RequestParam
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestParam {
    
    
    String value() default "";//值即为请求参数的参数名
    boolean required() default true;//该参数是否是必须。默认值为true
    String defaultValue() default ValueConstants.DEFAULT_NONE;//请求参数的默认值
}
// http://localhost:8080/demo/para?slug=google
@RequestMapping(value = "/para", method = RequestMethod.GET)
public String index3(@RequestParam(value = "slug", defaultValue = "") String slug, Model model) {
    
    
    model.addAttribute("originURL", "demo/");
    model.addAttribute("controllerName", "demo");
    model.addAttribute("controllerMethod", "index3");
    model.addAttribute("slug", slug);
    return "demo";
}
slug = google

Hay otro punto para recordar que el parámetro se puede mapear correctamente sin esta anotación. Esto se debe a que el marco SpringMVC admite el parámetro de solicitud y el parámetro del método de destino para ser coherentes. Esta anotación se puede omitir.

@ResponseBody
/**
 * Annotation that indicates a method return value should be bound to the web
 * response body. Supported for annotated handler methods in Servlet environments.
 * 
 * 这个注解指明一个方法的返回值应该绑定在 web response body 中,在 Servlet 环境中支持注解处理方法
 * 
 * <p>As of version 4.0 this annotation can also be added on the type level in
 * which case it is inherited and does not need to be added on the method level.
 */
@Target({
    
    ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ResponseBody {
    
    
}

Código

// http://localhost:8080/demo/json
@RequestMapping(value = "/json", method = RequestMethod.POST)
public @ResponseBody Domain index7(HttpServletRequest request, Model model) {
    
    

    LOG.info("DemoController demo index7");
    model.addAttribute("originURL", "demo/");
    model.addAttribute("controllerName", "demo");
    model.addAttribute("controllerMethod", "index7");

    Domain domain = new Domain();
    domain.setDomain("gggoogle.com");
    domain.setId(100);
    return domain;
}

/* response body
{
    "id": 100,
    "domain": "gggoogle.com"
}
*/

Supongo que te gusta

Origin blog.csdn.net/weixin_50917449/article/details/109393345
Recomendado
Clasificación