Spring MVC学习(1)—MVC的介绍以及Spring MVC的入门案例

433 阅读11分钟

「这是我参与2022首次更文挑战的第13天,活动详情查看:2022首次更文挑战」。

基于最新Spring 5.x,详细介绍了MVC架构以及Spring MVC入门案例的搭建。

此前,我们已经学习过了传统Servlet编程,现在我们来学习基于Servlet的更加上层的Spring MVC编程。

Spring Web MVC是构建在原始的Servlet API 上的Web 框架,并且从一开始就包含在 Spring Framework中,是Spring的核心组件。它正式名称"Spring Web MVC"是来自Spring的源码模块(spring-webmvc,github.com/spring-proj… MVC"。

也就是说,Spring MVC框架本身就是基于Servlet规范的,但是它对原始的Servlet API进行了封装,屏蔽了底层原始的Servlet方法,提供了更加高级的开发模式和注解的支持,用于方便开发者快速开发基于Servlet API并部署到Servlet容器的Web应用程序。

下面我们学习Spring MVC,和Spring的学习时一样,我们从基于XML的配置入手,逐渐过渡到基于JavaCofig的配置,从而去除XML文件,在此后我们还会学习Spring Boot,那时候使用Spring MVC就更加简单了。

想要学会Spring MVC,我们必须先学会Spring IOC以及AOP的基本使用。Spring IOC和AOP的知识我们在此前就讲过了。

Spring MVC学习 系列文章

Spring MVC学习(1)—MVC的介绍以及Spring MVC的入门案例

Spring MVC学习(2)—Spring MVC中容器的层次结构以及父子容器的概念

Spring MVC学习(3)—Spring MVC中的核心组件以及请求的执行流程

Spring MVC学习(4)—ViewSolvsolver视图解析器的详细介绍与使用案例

Spring MVC学习(5)—基于注解的Controller控制器的配置全解【一万字】

Spring MVC学习(6)—Spring数据类型转换机制全解【一万字】

Spring MVC学习(7)—Validation基于注解的声明式数据校验机制全解【一万字】

Spring MVC学习(8)—HandlerInterceptor处理器拦截器机制全解

Spring MVC学习(9)—项目统一异常处理机制详解与使用案例

Spring MVC学习(10)—文件上传配置、DispatcherServlet的路径配置、请求和响应内容编码

Spring MVC学习(11)—跨域的介绍以及使用CORS解决跨域问题

@[toc]

1 MVC和三层架构

Spring MVC基于MVC设计模式。在B/S架构中,系统标准的三层架构包括:表现层、业务层、持久层。三层架构在我们的实际开发中使用的非常多,属于宏观的解决方案。而MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,是一种用于设计创建 Web 应用程序表现层的模式:

  1. 表现层,框架有比如SpringMVC和struts2。
    1. 也就是我们常说的web层。它负责接收客户端请求,向客户端响应结果,通常客户端使用HTTP协议请求web层,web需要接收HTTP请求,完成HTTP响应。表现层依赖业务层,接收到客户端请求一般会调用业务层进行业务处理,并将业务层返回的处理结果响应给客户端。
    2. 表现层的设计一般都使用MVC模型。(MVC是表现层的设计模型,和其他层没有关系):
      1. V即View视图,是指用户看到并与之交互的界面。比如由html元素组成的网页界面,或者软件的客户端界面。视图层仅仅是展示数据,并且提供给用户的对应的操作界面。位于最上层。
      2. C即Controller控制器,是指控制器接受用户的输入并调用模型和视图去完成用户的需求,控制器本身不输出任何东西和做任何处理。它只是接收请求并决定调用哪个model模型构件去处理请求,然后再确定用哪个视图来显示返回的数据。简单的说,Controller负责转发请求和响应,它将View和Model联系起来。Controller位于第二层。
      3. M即Model模型,包括业务功能编写(例如算法实现)、数据库设计以及数据存取操作实现。在MVC的三个部件中,模型拥有最多的处理任务,Model位于最下层。
    3. 表现层也被成为Controller层,因为在前后端分离开发之后流行,后端一般不需要返回HTML页面了,而是直接返回JSON数据给前端即可,数据的解析和页面展示展示由前端框架负责。而在基于三层架构的Web应用中,Model也可以指全部的单纯的数据模型,也就是JavaBean对象,而业务功能由业务层承担了。也就是说MVC中的,View和Model要么很少使用了,要么有了新的意义。
  2. 业务层,业务层一般不需要框架,因为它主要是一些业务逻辑代码。
    1. 也就是我们常说的service层。它负责业务逻辑处理,和我们开发项目的需求息息相关。web层依赖业务层,但是业务层不依赖web层。
    2. 业务层在业务处理时可能会依赖持久层,比如操作数据库数据。
  3. 持久层,框架有比如mybatis和hibernate。
    1. 也就是我们是常说的dao层或者mapper层。负责对于数据的访问和操作,以及数据持久化,数据库是对数据进行持久化的载体,持久层是业务层和数据库进行交互的接口,业务层需要通过持久层来访问和操作数据库数。通俗的讲,持久层就是和数据库交互,对数据库表进行曾删改查的。

总的来说,MVC模式与三层架构结合使用时的关系(采用SSM框架,未实现前后端分离):

在这里插入图片描述

如果是基于前后端分离的项目,所有请求都是返回JSON字符串给前端,那么由于项目不再需要JSP、freemarker等技术以及前端资源,不再需要响应HTML页面,因此对应的View视图层或许也可以不需要了,或者说View的工作由前端框架来实现了。

一个具体的例子,项目中的资源以及对应的位置:

  1. users.jsp (View)
  2. UserController.java (Controller)
  3. UserVO.java、UserDTO.java、UserDO.java (Model)
  4. UserService.java、UserServiceImpl.java (Service层)
  5. UserDao.java、UserMapper.java (DAO层)

2 Spring MVC的入门案例

我们基于maven和XML配置来构建最简单的Spring MVC入门案例!

2.1 项目搭建

首先创建一个传统的maven Java Web项目:

在这里插入图片描述

创建成功之后结构如下:

在这里插入图片描述

接下来我们开始改造为Spring MVC项目!

在main目录下新增目录:

在这里插入图片描述

我们要添加的就是java目录和resources目录,在高版本Idea中有智能提示:

在这里插入图片描述

没有提示也没关系,手动创建这两个名字的目录,然后分别选中两个目录,右键单击,将java目录设置为Sources Root,表示这是一个源码目录,用于存放Java源码,将resources目录设置为Resources Root,表示这是一个资源目录,用于存放配置文件。

在这里插入图片描述

对于一个完整的Web项目,应该还要有测试目录!我们选中src目录,创建目录:

在这里插入图片描述

在src下面就可以创建测试代码目录和测试资源目录:

在这里插入图片描述

完整的项目结构如下:

在这里插入图片描述

2.2 maven依赖

接下来我们添加依赖。

我们只需要添加一个spring-webmvc依赖,即可实现最简单的Spring MVC项目的测试,spring-webmvc依赖包含了spring-web依赖以及Spring框架的核心依赖,比如spring-core、spring-context等等。

同时,我们采用maven tomcat7插件的形式直接启动项目,方便快捷!

<properties>
    <maven.compiler.target>1.8</maven.compiler.target>
    <maven.compiler.source>1.8</maven.compiler.source>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <spring-framework.version>5.2.8.RELEASE</spring-framework.version>
</properties>

<dependencies>
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>${spring-framework.version}</version>
    </dependency>
</dependencies>

<build>
    <pluginManagement>
        <plugins>
            <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <version>2.2</version>
            </plugin>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
            </plugin>
        </plugins>
    </pluginManagement>
    <!--打包名-->
    <finalName>mvc</finalName>
    <plugins>
        <!-- tomcat插件控制 -->
        <plugin>
            <groupId>org.apache.tomcat.maven</groupId>
            <artifactId>tomcat7-maven-plugin</artifactId>
            <configuration>
                <!--端口控制-->
                <port>8081</port>
                <!--项目路径控制意味着http://localhost:8081/mvc-->
                <path>/mvc</path>
                <!--tomcat的url编码  达到和修改server.xml文件一样的功能-->
                <uriEncoding>UTF-8</uriEncoding>
            </configuration>
        </plugin>

        <!-- maven插件控制 -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
                <source>${maven.compiler.source}</source>
                <target>${maven.compiler.target}</target>
                <encoding>${project.build.sourceEncoding}</encoding>
            </configuration>
        </plugin>
    </plugins>
</build>

2.3 添加Spring MVC配置文件

我们在resources目录下添加一个专门Spring MVC的配置文件! 可以叫dispatcher-servlet.xml或者spring-mvc-config.xml等等(名字自取),如果一个项目的组件非常多,那么通常一个组件都有一个单独的配置文件,Spring MVC也不例外!

如下文件,我们最简单的案例仅仅需要配置一个扫描注解的包路径,并且这是属于Spring支持的最基本配置,而不是Spring MVC特有的。

<?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="com.spring.mvc.controller"/>
</beans>

2.4 编写view视图文件

我们在webapps下新建一个success.jsp文件,简单的内容如下:

<html>
<body>
<h2>Hello Spring MVC!</h2>
</body>
</html>

最终配置如下:

在这里插入图片描述

2.5 配置DispatcherServlet

DispatcherServlet是一个特殊的Servlet,是Spring MVC中非常核心的一个前端控制器,用于处理、分发所有的请求!在web.xml中配置这一个Servlet就行了。

我们需要将spring-mvc-config.xml配置到contextConfigLocation参数中用于Servlet WebApplicationContext容器加载配置,后面我们会讲Spring MVC的容器关系!

设置load-on-startup为非负数,实际上不设置或者设置为负数也没关系,但是DispatcherServlet将会在请求到达的时候才会加载各种配置信息,因此如果配置有什么异常的话将不能在项目启动时被及时发现!

<!DOCTYPE web-app PUBLIC
        "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
        "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
    <display-name>Archetype Created Web Application</display-name>
    <!-- 配置spring mvc的前端核心控制器 -->
    <servlet>
        <servlet-name>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet
        </servlet-class>
        <!-- 配置初始化参数,用于读取SpringMVC的配置文件并加载 -->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring-mvc-config.xml</param-value>
        </init-param>
        <!-- 配置Servlet的对象的创建时间点:取值如果为非负整数,表示应用加载时创建,值越小,servlet的优先级越高,就越先被加载,如果取值为负数,表示在第一次使用时才加载 -->
        <load-on-startup>1</load-on-startup>
    </servlet>
    <!--配置映射路径,/表示将会处理所有的请求,并且自动分发-->
    <servlet-mapping>
        <servlet-name>dispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

2.6 编写Controller控制器

编写第一个控制器类com.spring.mvc.controller.HelloController。sayHello方法表示来自/hello的请求将会访问success.jsp资源!

/**
 1. 第一个控制器类
 2.  3. @author lx
 */
@Controller
public class HelloController {

    /**
     * 请求路径映射到某个方法
     * /hello路径映射到sayHello()方法
     */
    @RequestMapping(path = "/hello")
    public String sayHello() {
        System.out.println("Hello SpringMVC");
        //转发到success.jsp的视图
        return "success.jsp";
    }
}

2.7 启动测试

我们启动maven tomcat 插件进行测试,有两种方法。

一种是在右侧maven栏中,找到Plugins下的tomcat7插件,双击tomcat7:run即可启动项目!

在这里插入图片描述

第二种是配置maven启动项!

我们选择Edit Configurations并点击

在这里插入图片描述

选择+,选择maven:

在这里插入图片描述

找到我们的项目,并配置tomcat7:run参数,点击Apply之后即可正常点击右侧的按钮运行!

在这里插入图片描述

启动之后将自动输出日志信息,可以看到我们项目的主路径,以及dispatcherServlet被初始化的信息!

在这里插入图片描述

我们尝试访问http://localhost:8081/mvc/hello,成功获取到HTML视图信息,第一例到此结束!

在这里插入图片描述

2.8 简单的执行流程

我们简单的介绍Spring MVC的执行流程,注意这里的流程非常简单,我们后面会讲解详细的流程!

在这里插入图片描述

  1. tomcat服务器启动,应用被加载,读取到web.xml中的配置,在创建servlet的同时加载了spring-config.xml配置文件,即创建spring容器并且初始化容器中的对象,从入门案例中可以看到的是HelloController,但是我们知道Spring容器启动的时候远远不止加载这些类。实际上它会创建两个容器,一个是SpringMVC的容器,另一个是Spring父容器,这个我们后面学习源码时就知道了。
  2. 浏览器发送请求,被DispatherServlet捕获(其路径是“/”表示所有请求都要经过该Servlet)。但是该Servlet并不处理请求,而是把请求转发出去,此时控制台打印。转发的路径是根据请求URL,匹配@RequestMapping中的内容。
  3. 匹配到了后,找到方法并执行对应方法,该方法有一个返回值。
  4. 根据方法的返回值,借助InternalResourceViewResolver(视图解析器,虽然我们没有配置,但是Spring mVC会自动配置)找到对应的结果视图,也就是success.jsp。
  5. 渲染结果视图为html文本,响应给浏览器,浏览器渲染页面。

2.9 基于JavaConfig的配置

基于JavaConfig的配置则可以通过Spring 提供的WebApplicationInitializer抽象类来配置。使用该配置我们必须引入Servlet的依赖,同时配置中的AppConfig类作为一个主配置类,其内部通过JavaConfig的方式(比如@Bean方法)配置各种bean!

<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>4.0.1</version>
    <scope>provided</scope>
</dependency>

public class MyWebApplicationInitializer implements 
WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext servletCxt) {

        /*
         * 创建一个Spring web应用容器,加载AppConfig配置类
         */
        AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext();
        ac.register(AppConfig.class);
        ac.refresh();

        /*
         * 创建并注册DispatcherServlet,关联上的容器
         */
        DispatcherServlet servlet = new DispatcherServlet(ac);
        //命名并注册
        ServletRegistration.Dynamic registration = servletCxt.addServlet("dispatcherServlet", servlet);
        registration.setLoadOnStartup(1);
        registration.addMapping("/");
    }
}
@ComponentScan("com.spring.mvc")
@Configuration
public class AppConfig { }

如果采用基于JavaConfig的配置,那么web.xml中可以不提供任何配置,其他的xml配置文件也都应该改为JavaCOnfig的形式!

最终项目图如下:

在这里插入图片描述

启动项目即可测试成功!如果你仍然需要基于XML文件,那么你可以换一个WebApplicationContext的实现,比如:

public class MyXmlWebApplicationInitializer implements 
WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext servletCxt) {

        /*
         * 创建Spring web应用容器,加载AppConfig配置类
         */
        XmlWebApplicationContext ac = new XmlWebApplicationContext();
        ac.setConfigLocation("classpath:spring-mvc-config.xml");
        /*
         * 创建并注册DispatcherServlet
         */
        DispatcherServlet servlet = new DispatcherServlet(ac);
        //命名并注册
        ServletRegistration.Dynamic registration = servletCxt.addServlet("dispatcherServlet", servlet);
        registration.setLoadOnStartup(1);
        registration.addMapping("/");
    }
}

另外,还可以使用继承AbstractAnnotationConfigDispatcherServletInitializer的方式进行配置更多的配置!

相关文章:

  1. spring.io/
  2. Spring Framework 5.x 学习
  3. Spring Framework 5.x 源码

如有需要交流,或者文章有误,请直接留言。另外希望点赞、收藏、关注,我将不间断更新各种Java学习博客!