阿里P7浅谈SpringMVC
一、前言
既然是浅谈 SpringMVC,那么我们就先从基础说起,本章节主要讲解以下内容:
1、三层结构介绍
2、MVC 设计模式介绍
3、SpringMVC 介绍
4、入门程序的实现
注:介绍方面的内容大多数摘录自互联网,找了一些说法比较严谨、明确的介绍内容进行整理。
二、三层结构介绍
我们的开发架构一般都是基于两种形式,一种是 C/S 架构,也就是客户端/服务器,另一种是 B/S 架构,也就是浏览器服务器。在 JavaEE 开发中,几乎全都是基于 B/S 架构的开发。那么在 B/S 架构中,系统标准的三层架构包括:表现层、业务层、持久层。三层架构在我们的实际开发中使用的非常多,所以我们课程中的案例也都是基于三层架构设计的。
1、表现层
1)也就是我们常说的web 层。它负责接收客户端请求,向客户端响应结果,通常客户端使用http 协议请求web 层,web 需要接收 http 请求,完成 http 响应。
2)表现层包括展示层和控制层:控制层负责接收请求,展示层负责结果的展示。
3)表现层依赖业务层,接收到客户端请求一般会调用业务层进行业务处理,并将处理结果响应给客户端。
4)表现层的设计一般都使用 MVC 模型。(MVC 是表现层的设计模型,和其他层没有关系)
2、业务层
1)也就是我们常说的 service 层。它负责业务逻辑处理,和我们开发项目的需求息息相关。web 层依赖业务层,但是业务层不依赖 web 层。
2)业务层在业务处理时可能会依赖持久层,如果要对数据持久化需要保证事务一致性。(也就是我们说的, 事务应该放到业务层来控制)
3、持久层
1)也就是我们是常说的 dao 层。负责数据持久化,包括数据层即数据库和数据访问层,数据库是对数据进行持久化的载体,数据访问层是业务层和持久层交互的接口,业务层需要通过数据访问层将数据持久化到数据库中。通俗的讲,持久层就是和数据库交互,对数据库表进行增删改查的。
三、MVC 设计模式介绍
MVC 全名是 Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写, 是一种用于设计创建 Web 应用程序表现层的模式。MVC 中每个部分各司其职:
1、Model(模型)
1)模型包含业务模型和数据模型,数据模型用于封装数据,业务模型用于处理业务。
2、View(视图)
1)通常指的就是我们的 jsp 或者 html,作用一般就是展示数据的。
2)通常视图是依据模型数据创建的。
3、Controller(控制器)
1)是应用程序中处理用户交互的部分。作用一般就是处理程序逻辑的。
四、SpringMVC 介绍
1、Spring MVC是什么?
1)SpringMVC 是一种基于 Java 的实现 MVC 设计模型的请求驱动类型的轻量级 Web 框架,属于 SpringFrameWork 的后续产品,已经融合在 Spring Web Flow 里面。Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块。使用 Spring 可插入的 MVC 架构,从而在使用 Spring 进行 WEB 开发时,可以选择使用 Spring 的 SpringMVC 框架或集成其他 MVC 开发框架,如 Struts1(现在一般不用),Struts2 等。
2)它通过一套注解,让一个简单的 Java 类成为处理请求的控制器,而无须实现任何接口。同时它还支持RESTful 编程风格的请求。
3)SpringMVC 和 Struts2 一样,都是为了解决表现层问题的web框架,它们都是基于MCC设计模式的。而这些表现层框架的主要职责就是处理前端HTTP请求。
2、SpringMVC 如何处理请求?
SpringMVC 是基于 MVC 设计模式的,MVC 模式指的就是Model(业务模型)、View(视图)、Controller(控制器)。SpringMVC 处理请求就是通过 MVC 这三种角色来实现的。
不过千万不要把 MVC 设计模式和工程的三层结构混淆,三层结构指的是表现层、业务层、数据持久层。而 MVC 只针对表现层进行设计。
下面根据一张图来看一下 SpringMVC 具体的处理流程:
这张图只是把 SpringMVC 的基本执行流程,详细流程在后续章节中会进行分析。
五、入门程序的实现
1、如何配置前端控制器?
从上面的图可知,我们需要配置一个前端控制器,下面我们会在 web.xml 中进行配置。还有一点就是处理器的开发形式有很多种,有注解方式、实现HttpRequestHandler 接口和实现 Controller 接口,这里我们只讲解注解方式,其他两种方式使用的已经很少了,如果有想要了解的小伙伴,可以自行百度一下。
2、开发步骤
1)创建一个 web 工程,这里一定要注意是 web 工程,和前面的项目有所区别,因为要使用到 web.xml,需要使用 tomcat 进行启动。
2)编写POM文件,添加依赖
<dependencies> <!-- spring ioc组件需要的依赖包 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>5.0.7.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>5.0.7.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.7.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-expression</artifactId> <version>5.0.7.RELEASE</version> </dependency> <!-- 基于AspectJ的aop依赖 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>5.0.7.RELEASE</version> </dependency> <dependency> <groupId>aopalliance</groupId> <artifactId>aopalliance</artifactId> <version>1.0</version> </dependency> <!-- spring 事务管理和JDBC依赖包 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>5.0.7.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.0.7.RELEASE</version> </dependency> <!-- mysql数据库驱动包 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.35</version> </dependency> <!-- dbcp连接池的依赖包 --> <dependency> <groupId>commons-dbcp</groupId> <artifactId>commons-dbcp</artifactId> <version>1.4</version> </dependency> <!-- mybatis依赖 --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.5</version> </dependency> <!-- mybatis和spring的整合依赖 --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.3.1</version> </dependency> <!-- SpringMVC 相关包 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>4.3.13.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>4.3.13.RELEASE</version> </dependency> <!-- jstl --> <dependency> <groupId>jstl</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <!-- servlet --> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> </dependency></dependencies>
这里代码直接给出了,多添加了 SpringMVC 的依赖包,因为会用到 jsp 页面,最后还添加了 jstl 和 servlet-api 的依赖包。
3)配置前端控制器
在web.xml中添加DispatcherServlet的配置。
<?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"> <!-- 配置前端控制器 --> <servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- 设置spring配置文件路径 --> <!-- 如果不设置初始化参数,那么DispatcherServlet会读取默认路径下的配置文件,默认配置文件路径:/WEB-INF/springmvc-servlet.xml --> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc.xml</param-value> </init-param> <!-- 指定初始化时机,设置为2,表示Tomcat启动时,DispatcherServlet会跟随着初始化 --> <!-- 如果不指定初始化时机,DispatcherServlet就会在第一次被请求的时候,才会初始化 --> <load-on-startup>2</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springmvc</servlet-name> <!-- 为什么url-pattern配置/*会报错?原因是它拦截了jsp请求,但是却不能处理jsp请求,详见图解 --> <url-pattern>/</url-pattern> </servlet-mapping></web-app>
这个地方有几个点需要说明:
(1)web.xml 中配置内容的加载顺序
这个并不属于 SpringMVC 的知识,但是这个地方用到了,就用上面这张图讲解一下。load-on-startup 的配置需要额外注意,配置与不配置的区别很重要,面试经常问道。这里说明一下,它的值需要是大于0的整数,值越小,加载越早,那么为什么我们这里设置了2呢,为什么不设置成1呢?其实设置成1也是完全可以的,但是1是有冲突的,我们可以打开 tomcat 中的 web.xml 看一下就明白了。这是我的个人习惯,这个值已经被占用了,所以就设置为2了。
(2)url-pattern 匹配 URL 详解
在代码中我们可以看到 url-pattern 配置的是 /,这里我们用一张图来看一看为什么这样配置。
这里有一个很经典的问题,为什么 url-pattern 配置 /* 会报错?从图中可以知道 url-pattern 的匹配顺序,如果配置的是 /*,tomcat 本身的配置(*.jsp(就是*.do),/)优先级都小于 /*,就会跳过 tomcat 自身的配置,直接匹配 /*,这样的话,它会接收 jsp 的请求,但是无法处理 jsp 的请求,导致页面访问出错。如果配置为 /,/ 的优先级小于 *.do,jsp 会优先被 tomcat 自身的 *.jsp 处理,这样就没有问题了。
4)创建 springmvc.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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="top.alanshelby.controller"></context:component-scan></beans>
5)编写处理器
(1)注解方式使用到的注解主要有以下两个:
@Controller 注解:在类上添加该注解,指定该类为一个请求处理器,不需要实现任何接口或者继承任何类。
@RequestMapping 注解:在方法上添加该注解,指定请求的 url 由该方法处理。
处理器的返回值是ModelAndView对象,该对象的具体理解如下:
ModelAndView:方法返回值对象,该对象包含两个功能:一个是将数据存储到 Request 域中,一个是设置响应视图,比如将视图设置为"/WEB-INF/jsp/goodsList.jsp"。
@Controllerpublic class GoodsController { @RequestMapping(value = "queryGoods") public ModelAndView queryGoods() { ModelAndView modelAndView = new ModelAndView(); // 构造演示数据 List<Goods> goodsList = new ArrayList<>(); Goods goods1 = new Goods(); goods1.setName("小米8SE"); goods1.setPrice(1999f); goods1.setDetail("全面屏智能手机 6GB+64GB 灰色 全网通4G 双卡双待"); Goods goods2 = new Goods(); goods2.setName("Apple iPad"); goods2.setPrice(3359f); goods2.setDetail("平板电脑 2018年新款9.7英寸(128G WLAN版/A10 芯片/Retina显示屏/Touch ID MRJP2CH/A)金色"); goodsList.add(goods1); goodsList.add(goods2); // 设置数据和视图 modelAndView.addObject("goodsList", goodsList); modelAndView.setViewName("/WEB-INF/jsp/goodsList.jsp"); return modelAndView; }}
(2)这里直接把实体类和 jsp 页面给出:
Goods.javapublic class Goods { private String name; private double price; private String Detail; // 省略 setter 和 getter 方法}
goodsList.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %><%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %><%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><body><h2>商品列表</h2></body><hr><div> <table width="100%" border=1> <tr> <td>商品名称</td> <td>商品价格</td> <td>商品描述</td> </tr> <c:forEach items="${goodsList}" var="item"> <tr> <td>${item.name}</td> <td>${item.price}</td> <td>${item.detail}</td> </tr> </c:forEach> </table></div></html>
六、小结
本章节主要是对 SpringMVC 进行了初步的讲解,让读者能够了解到什么是 MVC 模式、什么事 SpringMVC、SpringMVC 需要如何配置以及它具体的执行流程,目的在于让读者熟悉 SpringMVC,为后面的文章打好基础,后面的章节会更为深入的讲解 SpringMVC。
写在最后:欢迎留言讨论,加关注,持续更新!!!