从 SpringBoot 到 SpringMVC
概述
用久了 SpringBoot,深受其约定大于配置的便利性毒害之后,我想回归到 SpringMVC 时代,看看 SpringMVC 开发模式中用户是如何参与的。本文就来体验一下 SpringMVC 时代开发的流程。
SpringMVC 架构模式
一个典型的 SpringMVC 请求流程如图所示,详细分为 12 个步骤:
- 用户发起请求,由前端控制器 DispatcherServlet 处理
- 前端控制器通过处理器映射器查找 hander,可以根据 XML 或者注解去找
- 处理器映射器返回执行链
- 前端控制器请求处理器适配器来执行 hander
- 处理器适配器来执行 handler
- 处理业务完成后,会给处理器适配器返回 ModeAndView 对象,其中有视图名称,模型数据
- 处理器适配器将视图名称和模型数据返回到前端控制器
- 前端控制器通过视图解析器来对视图进行解析
- 视图解析器返回真正的视图给前端控制器
- 前端控制器通过返回的视图和数据进行渲染
- 返回渲染完成的视图
- 将最终的视图返回给用户,产生响应
整个过程清晰明了,下面我们将结合实际实验来理解这整个过程。
SpringMVC 项目搭建
实验环境如下:
- IntelliJ IDEA 2018.1 (Ultimate Edition)
- SpringMVC 4.3.9.RELEASE
- Maven 3.3.9
这里我是用 IDEA 来搭建的基于 Maven 的 SpringMVC 项目,搭建过程不再赘述,各种点击并且下一步,最终创建好的项目架构如下:
添加前端控制器配置
使用了 SpringMVC,则所有的请求都应该交由 SpingMVC 来管理,即要将所有符合条件的请求拦截到 SpringMVC 的专有 Servlet 上。
为此我们需要在 web.xml
中添加 SpringMVC 的前端控制器 DispatcherServlet:
<!--springmvc 前端控制器--
<servlet
<servlet-name mvc-dispatcher</servlet-name
<servlet-class org.springframework.web.servlet.DispatcherServlet</servlet-class
<init-param
<param-name contextConfigLocation</param-name
<param-value classpath:mvc-dispatcher.xml</param-value
</init-param
</servlet
<servlet-mapping
<servlet-name mvc-dispatcher</servlet-name
<url-pattern *.action</url-pattern
</servlet-mapping
该配置说明所有符合.action 的 url,都交由 mvc-dispatcher 这个 Servlet 来进行处理
编写 SpringMVC 核心 XML 配置文件
从上一步的配置可以看到,我们定义的 mvc-dispatcher Servlet 依赖于配置文件 mvc-dispatcher.xml
,在本步骤中我们需要在其中添加三个方面的配置
- 0x01. 添加处理器映射器
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" /
SpringMVC 的处理器映射器有多种,这里的使用的 BeanNameUrlHandlerMapping 其映射规则是将 bean 的 name 作为 url 进行处理
- 0x02. 添加处理器适配器
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" /
SpringMVC 的处理器适配器也有多种,这里的使用的 SimpleControllerHandlerAdapter 是 Controller 实现类的适配器类,其本质是执行 Controller 中的 handleRequest 方法。
- 0x03. 添加试图解析器
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" /
这里配置了 InternalResourceViewResolver 视图解析器后,其会根据 controller 方法执行之后返回的 ModelAndView 中的视图的具体位置,来加载对应的界面并绑定数据
编写控制器
这里模拟的是一个打印学生名单的 Service,我们编写的控制器需要将查询到的学生名单数据通过 ModelAndView 渲染到指定的 JSP 页面中
public class TestController implements Controller {
private StudentService studentService = new StudentService();
@Override
public ModelAndView handleRequest( HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
List<Student studentList = studentService.queryStudents();
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("studentList",studentList);
modelAndView.setViewName("/WEB-INF/views/studentList.jsp");
return modelAndView;
}
}
class StudentService {
public List<Student queryStudents() {
List<Student studentList = new ArrayList<Student ();
Student hansonwang = new Student();
hansonwang.setName("hansonwang99");
hansonwang.setID("123456");
Student codesheep = new Student();
codesheep.setName("codesheep");
codesheep.setID("654321");
studentList.add(hansonwang);
studentList.add(codesheep);
return studentList;
}
}
编写视图文件
这里的视图文件是一个 jsp 文件,路径为:/WEB-INF/views/studentList.
js
p
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %
<html
<head
<title 学生名单</title
</head
<body
<h3 学生列表</h3
<table width="300px;" border=1
<tr
<td 姓名</td
<td 学号</td
</tr
<c:forEach items="${studentList}" var="student"
<tr
<td ${student.name}</td
<td ${student.ID}</td
</tr
</c:forEach
</table
</body
</html
结合本步骤和上一步骤,视图和控制器都已编写完成,由于我们之前配置的处理器映射器为:BeanNameUrlHandlerMapping,因此接下来我们还需要在 mvc-dispatcher.xml 文件中配置一个可被 url 映射的 controller 的 bean,供处理器映射器 BeanNameUrlHandlerMapping 查找:
<bean name="/test.action" class="cn.codesheep.controller.TestController" /
实验测试
http://localhost:8080/test.action
数据渲染 OK。
备注:当然本文所使用的全是非注解的配置方法,即需要在 XML 中进行配置并且需要遵循各种实现原则。而更加通用、主流的基于注解的配置方法将在后续文章中详述。
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- 使用PHP反射机制来构造"CREATE TABLE"的sql语句
- PHP PDOStatement::fetch讲解
- 解决Pytorch自定义层出现多Variable共享内存错误问题
- PHP观察者模式定义与用法实例分析
- ThinkPHP5.1表单令牌Token失效问题的解决
- PHP设计模式之工厂模式(Factory Pattern)的讲解
- keras K.function获取某层的输出操作
- 浅谈sklearn中predict与predict_proba区别
- 解决Keras中循环使用K.ctc_decode内存不释放的问题
- PDO::getAvailableDrivers讲解
- PDO::_construct讲解
- Yii2.0实现的批量更新及批量插入功能示例
- PDO::inTransaction讲解
- 小程序前后端交互使用JWT
- python文件操作seek()偏移量,读取指正到指定位置操作