[华为云在线课程][SpringMVC入门][二][简单应用][学习笔记]

举报
John2021 发表于 2022/07/15 05:32:42 2022/07/15
【摘要】 1.SpringMVC工作流程 2.SpringMVC组件简单介绍 2.1.DispatcherServlet:前端控制器用户请求到达前端控制器,相当于MVC模式中的C,DispatcherServlet是整个流程控制的中心,相当于是SpringMVC的大脑,由它调用其他组件处理用户的请求,DispatcherServlet的存在降低了组件之间的耦合性。 2.2.HandlerMappin...

1.SpringMVC工作流程

2.SpringMVC组件简单介绍

2.1.DispatcherServlet:前端控制器

用户请求到达前端控制器,相当于MVC模式中的C,DispatcherServlet是整个流程控制的中心,相当于是SpringMVC的大脑,由它调用其他组件处理用户的请求,DispatcherServlet的存在降低了组件之间的耦合性。

2.2.HandlerMapping:处理器映射器

HandlerMapping负责根据用户请求找到Handler即处理器(Controller),SpringMVC提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等等。在实际开发中,我们最常用注解方式。

2.3.Handler:处理器

Handler是继DispatcherServlet前端控制器的后端控制器,在DispatcherServlet的控制下Handler对具体的用户请求进行处理。由于Handler涉及到具体的用户业务请求,所以一般情况需要程序员根据业务需求开发Handler。(这里所说的Handler就是指我们的Controller)。

2.4.HandlerAdapter:处理器适配器

通过HandlerAdapter对处理器进行执行,这是适配器模式的应用,通过拓展适配器可以对更多类型的处理器进行执行。

2.5.ViewResolver:视图解析器

ViewResolver负责将处理结果生成View视图,ViewResolver首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成View视图对象,最后对View进行渲染将处理结果通过页面展示给用户。SpringMVC框架提供了很多的View视图类型,包括:jstlView、freemarkerView、pdfView等等。一般情况下需要通过页面标签或页面模板技术将模型数据通过页面展示给用户,需要由程序员根据业务需求开发具体的页面。

3.DispatcherServlet细节

3.1.DispatcherServlet的作用

DispatcherServlet是前端控制器设计模式的实现,提供Spring Web MVC的集中访问点,它负责职责分派,与Spring IoC容器集成,从而可以获取Spring的所有好处。DispatcherServlet主要用于职责调度工作,用于控制流程,主要职责有以下几点:

  1. 文件上传解析,如果请求类型是multipart将通过MultipleResolver进行文件上传解析。
  2. 通过HandlerMapping,将请求映射到处理器(返回一个HandlerExecutionChain,包括一个处理器、多个HandlerInterceptor拦截器)。
  3. 通过HandlerAdapter支持多种类型的处理器(HandlerExecutionChain中的处理器)。
  4. 通过ViewResolver解析逻辑视图名到具体视图实现。
  5. 本地化解析。
  6. 渲染具体的视图等。
  7. 如果执行过程中遇到异常将交给HandlerExceptionResolver来解析。

3.2.DispatcherServlet配置细节

DispatcherServlet配置文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring-servlet.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>
参数 描述
load-on-startup 表示启动容器时初始化该Servlet,当值为0或大于0时,表示容器启动时加载该Servlet,正数值越小优先级越高。如果是负数,容器启动时不会加载该Servlet,只有该Servlet被选择时才会加载。
url-pattern 表示哪些请求交给Spring Web MVC处理,"/"是用来定义默认Servlet映射的。也可以如*.html表示拦截所有以html拓展名的请求。
contextClass 实现WebApplicationContext接口的类,当前的Servlet用它来创建上下文。如果这个参数没有指定,默认使用XmlWebApplicationContext。
contextConfigLocation 表示SpringMVC配置文件的路径,传给上下文实例(由contextClass指定)的字符串,用来指定上下文的位置。这个字符串可以被分成多个字符串(使用逗号作为分隔符)来支持多个上下文(在多上下文的情况下,如果同一个bean被定义两次,后面一个优先)。
namespace WebApplicationContext命名空间。默认值是[server-name]-serlvet。

4.Spring和SpringMVC分开配置

只有SpringMVC,没有Spring,Web项目也可以运行的。但在实际开发中,Spring和SpringMVC是分开配置的,我们在上面的项目中,添加Spring的相关配置。
首先,项目添加一个service包,提供一个HelloService类

package org.example.service;

import org.springframework.stereotype.Service;

@Service
public class HelloService {
    public String hello(String name) {
        return "hello = " + name;
    }
}

假设需要将HelloService注入到Spring容器中使用它,这个是属于Spring层的Bean,所以我们一般将除了Controller之外的所有Bean注册到Spring容器中,而将Controller注册到SpringMVC容器中,现在,在resources目录下添加applicationContext.xml作为Spring的配置:

<?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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd 
        http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
    <context:component-scan base-package="org.example" use-default-filters="true">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>
</beans>

但这个配置文件默认情况下不会自动加载,需要我们在web.xml中进行配置:

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

首先通过context-param指定Spring配置文件的位置,这个配置文件也有一些默认规则,配置文件名字默认就是applicationContext.xml,如果配置文件在WEB-INF目录下,那么就可以不用指定配置文件位置了,指定监听器就行。上面这段配置是Spring集成Web环境的通用配置,一般用于加载除了Web层(spring-servlet.xml)的Bean(如DAO、Service等),以便于与其他Web框架进行集成。

  • contextConfigLocation:表示用于加载Bean的配置文件。
  • contextClass:表示用于加载Bean的ApplicationContext实现类,默认WebApplicationContext。

配置完成之后,还需要修改MyController,在其中注入HelloService:

package org.example.controller;

import org.example.service.HelloService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@org.springframework.stereotype.Controller("/hello")
public class MyController implements Controller {
    @Autowired
    HelloService helloService;

    /**
     * 这就一个请求处理接口
     *
     * @param request  前端发送来的请求
     * @param response 服务端给前端的响应
     * @return 返回一个ModelAndView,Model是数据模型,View是视图
     * @throws Exception
     */
    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
        System.out.println(helloService.hello("hello in MyController"));
        ModelAndView modelAndView = new ModelAndView("hello");
        modelAndView.addObject("name", "helloworld");
        return modelAndView;
    }
}

为了在SpringMVC容器中能够扫描到MyController,这里给MyController添加@Controller注解,同时,由于我们目前采用HandlerMapping是BeanNameUrlHandlerMapping(意味着请求地址就是处理器Bean的名字),所有需要手动指定MyController的名字。
最后,修改SpringMVC配置文件,将Bean配置为扫描形式:

<?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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                        http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="org.example" use-default-filters="false">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

    <!--这个是处理器映射器,请求地址其实就是一个Bean的名字,然后根据这个bean的名字查找对应的处理器-->
    <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" id="handlerMapping">
        <property name="beanName" value="/hello"/>
    </bean>
    <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" id="handlerAdapter"/>
    <!--视图解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="viewResolver">
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
</beans>

配置好后启动项目。Spring容器也会被创建。访问/hello接口,HelloService中的Hello方法会被自动调用。

5.Spring容器和SpringMVC容器

当Spring和SpringMVC同时出现,项目中将会存在两个容器,一个是Spring容器,另一个是SpringMVC容器。
Spring容器通过ContextLoaderListener来加载,SpringMVC容器通过DispatcherServlet来加载。
Spring容器和SpringMVC容器的区别如下图所示:

从图中可以看出:

  1. ContextLoaderListener初始化的上下文加载的Bean是对于整个应用程序共享的,不管是是使用什么表现层技术,一般如DAO层、Service层Bean。
  2. DispatcherServlet初始化的上下文加载的Bean是只对Spring Web MVC有效的Bean,如Controller、HandlerMapping、HandlerAdapter等等,该初始化上下文应该只加载Web相关组件。

问题1:为什么不在Spring容器中扫描所有Bean??
答:这是不可能的。因为请求到达服务端后,找DispatcherServlet去处理,只会去SpringMVC容器中找,这就意味着Controller必须在SpringMVC容器中扫描。
问题2:为什么不在SpringMVC容器中扫描所有Bean??
答:这是可以的,可以在SpringMVC容器中扫描所有Bean。不写在一起有两个原因:1,为了方便配置文件管理。2,在Spring+SpringMVC+Hibernate中,也不支持这种写法。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。