基于最新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,https://github.com/spring-projects/spring-framework/tree/master/spring-webmvc)的名称,但它更通常被称简称为"Spring MVC"。
也就是说,Spring MVC框架本身就是基于Servlet规范的,但是它对原始的Servlet API进行了封装,屏蔽了底层原始的Servlet方法,提供了更加高级的开发模式和注解的支持,用于方便开发者快速开发基于Servlet API并部署到Servlet容器的Web应用程序。
下面我们学习Spring MVC,和Spring的学习时一样,我们从基于XML的配置入手,逐渐过渡到基于JavaCofig的配置,从而去除XML文件,在此后我们还会学习Spring Boot,那时候使用Spring MVC就更加简单了。
文章目录
- Spring MVC学习 系列文章
- 1 MVC和三层架构
- 2 Spring MVC的入门案例
- 2.1 项目搭建
- 2.2 maven依赖
- 2.3 添加Spring MVC配置文件
- 2.4 编写view视图文件
- 2.5 配置DispatcherServlet
- 2.6 编写Controller控制器
- 2.7 启动测试
- 2.8 简单的执行流程
- 2.9 基于JavaConfig的配置
1 MVC和三层架构
Spring MVC基于MVC设计模式。在B/S架构中,系统标准的三层架构包括:表现层、业务层、持久层。三层架构在我们的实际开发中使用的非常多,属于宏观的解决方案。而MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,是一种用于设计创建 Web 应用程序表现层的模式:
- 表现层,框架有比如SpringMVC和struts2。
- 也就是我们常说的web层。它负责接收客户端请求,向客户端响应结果,通常客户端使用HTTP协议请求web层,web需要接收HTTP请求,完成HTTP响应。表现层依赖业务层,接收到客户端请求一般会调用业务层进行业务处理,并将业务层返回的处理结果响应给客户端。
- 表现层的设计一般都使用
MVC模型
。(MVC是表现层的设计模型,和其他层没有关系):
-
V即View视图
,是指用户看到并与之交互的界面。比如由html元素组成的网页界面,或者软件的客户端界面。视图层仅仅是展示数据,并且提供给用户的对应的操作界面。位于最上层。 -
C即Controller控制器
,是指控制器接受用户的输入并调用模型和视图去完成用户的需求,控制器本身不输出任何东西和做任何处理。它只是接收请求并决定调用哪个model模型构件去处理请求,然后再确定用哪个视图来显示返回的数据。简单的说,Controller负责转发请求和响应,它将View和Model联系起来。Controller位于第二层。 -
M即Model模型
,包括业务功能编写(例如算法实现)、数据库设计以及数据存取操作实现。在MVC的三个部件中,模型拥有最多的处理任务,Model位于最下层。
-
表现层也被成为Controller层
,因为在前后端分离开发之后流行,后端一般不需要返回HTML页面了,而是直接返回JSON数据给前端即可,数据的解析和页面展示展示由前端框架负责。而在基于三层架构的Web应用中,Model也可以指全部的单纯的数据模型,也就是JavaBean对象,而业务功能由业务层承担了。也就是说MVC中的,View和Model要么很少使用了,要么有了新的意义。
- 业务层,业务层一般不需要框架,因为它主要是一些业务逻辑代码。
- 也就是我们常说的
service层
。它负责业务逻辑处理,和我们开发项目的需求息息相关。web层依赖业务层,但是业务层不依赖web层。 - 业务层在业务处理时可能会依赖持久层,比如操作数据库数据。
- 持久层,框架有比如mybatis和hibernate。
- 也就是我们是常说的
dao层或者mapper层
。负责对于数据的访问和操作,以及数据持久化,数据库是对数据进行持久化的载体,持久层是业务层和数据库进行交互的接口,业务层需要通过持久层来访问和操作数据库数。通俗的讲,持久层就是和数据库交互,对数据库表进行曾删改查的。
总的来说,MVC模式与三层架构结合使用时的关系(采用SSM框架,未实现前后端分离):
如果是基于前后端分离的项目,所有请求都是返回JSON字符串给前端,那么由于项目不再需要JSP、freemarker等技术以及前端资源,不再需要响应HTML页面,因此对应的View视图层或许也可以不需要了,或者说View的工作由前端框架来实现了。
一个具体的例子,项目中的资源以及对应的位置:
- users.jsp (View)
- UserController.java (Controller)
- UserVO.java、UserDTO.java、UserDO.java (Model)
- UserService.java、UserServiceImpl.java (Service层)
- 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的执行流程,注意这里的流程非常简单,我们后面会讲解详细的流程!
- tomcat服务器启动,应用被加载,读取到web.xml中的配置,在创建servlet的同时加载了spring-config.xml配置文件,即创建spring容器并且初始化容器中的对象,从入门案例中可以看到的是HelloController,但是我们知道Spring容器启动的时候远远不止加载这些类。实际上它会创建两个容器,一个是SpringMVC的容器,另一个是Spring父容器,这个我们后面学习源码时就知道了。
- 浏览器发送请求,被DispatherServlet捕获(其路径是“/”表示所有请求都要经过该Servlet)。但是该Servlet并不处理请求,而是把请求转发出去,此时控制台打印。转发的路径是根据请求URL,匹配@RequestMapping中的内容。
- 匹配到了后,找到方法并执行对应方法,该方法有一个返回值。
- 根据方法的返回值,借助InternalResourceViewResolver(视图解析器,虽然我们没有配置,但是Spring mVC会自动配置)找到对应的结果视图,也就是success.jsp。
- 渲染结果视图为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的方式进行配置更多的配置!