从 SpringBoot 到 SpringMVC - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
hansonwang99
V2EX    程序员

从 SpringBoot 到 SpringMVC

  hansonwang99
hansonwang99 2018-06-11 07:09:38 +08:00 7933 次点击
这是一个创建于 2681 天前的主题,其中的信息可能已经有所发展或是发生改变。

V A I O


概述

用久了 SpringBoot,深受其约定大于配置的便利性毒害之后,我想回归到 SpringMVC 时代,看看 SpringMVC 开发模式中用户是如何参与的。本文就来体验一下 SpringMVC 时代开发的流程。


SpringMVC 架构模式

SpringMVC 请求处理流程

一个典型的 SpringMVC 请求流程如图所示,详细分为 12 个步骤:

  1. 用户发起请求,由前端控制器 DispatcherServlet 处理
  2. 前端控制器通过处理器映射器查找 hander,可以根据 XML 或者注解去找
  3. 处理器映射器返回执行链
  4. 前端控制器请求处理器适配器来执行 hander
  5. 处理器适配器来执行 handler
  6. 处理业务完成后,会给处理器适配器返回 ModeAndView 对象,其中有视图名称,模型数据
  7. 处理器适配器将视图名称和模型数据返回到前端控制器
  8. 前端控制器通过视图解析器来对视图进行解析
  9. 视图解析器返回真正的视图给前端控制器
  10. 前端控制器通过返回的视图和数据进行渲染
  11. 返回渲染完成的视图
  12. 将最终的视图返回给用户,产生响应

整个过程清晰明了,下面我们将结合实际实验来理解这整个过程。


SpringMVC 项目搭建

实验环境如下:

  • IntelliJ IDEA 2018.1 (Ultimate Edition)
  • SpringMVC 4.3.9.RELEASE
  • Maven 3.3.9

这里我是用 IDEA 来搭建的基于 Maven 的 SpringMVC 项目,搭建过程不再赘述,各种点击并且下一步,最终创建好的项目架构如下:

基于 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.jsp

<%@ page cOntentType="text/html; charset=" 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" /> 

实验测试

启动 Tomcat 服务器,然后浏览器输入:

http://localhost:8080/test.action 

实验结果

数据渲染 OK。

备注:当然本文所使用的全是非注解的配置方法,即需要在 XML 中进行配置并且需要遵循各种实现原则。而更加通用、主流的基于注解的配置方法将在后续文章中详述。


后记

作者更多的 SpringBt 实践文章在此:


如果有兴趣,也可以抽点时间看看作者一些关于容器化、微服务化方面的文章:


43 条回复    2018-06-13 23:31:39 +08:00
jerrry
    1
jerrry  
   2018-06-11 07:41:00 +08:00 via Android
不错
yushiro
    2
yushiro  
   2018-06-11 08:27:27 +08:00 via iPhone
收藏了慢慢看,正好需要
Jeffrey8888
    3
Jeffrey8888  
   2018-06-11 08:44:49 +08:00
挺好,请楼主多多分享
SKull4
    4
SKull4  
   2018-06-11 08:57:24 +08:00
有些错别字,建议再查一下
jatai
    5
jatai  
   2018-06-11 08:59:09 +08:00
想入门 java 来的,我一个渣渣看不懂,弱弱地问下:现在的趋势不是前后端分离吗,这会不会有点开倒车的?
trys1
    6
trys1  
   2018-06-11 09:03:21 +08:00 via Android
是该前后端分离了呀
KgM4gLtF0shViDH3
    7
KgM4gLtF0shViDH3  
   2018-06-11 09:10:32 +08:00
@jatai #5
@trys1 #6 小公司不需要,大公司也不是所有都分离,前后端分离也不是什么先进的技术。
    8
wly19960911  
   2018-06-11 09:11:54 +08:00
@jatai #5 我认为是该前后端分离,但是有时候这些东西不应该不学,难免会碰到这种场景的需要,毕竟现在还有人用 jsp,freemarker,thymeleaf 这种模板引擎。
zqguo
    9
zqguo  
   2018-06-11 09:13:21 +08:00
落后
sagaxu
    10
sagaxu  
   2018-06-11 09:27:02 +08:00 via Android
倒车请注意!
@bestkayle 我一个人的项目也做前后端分离,仅仅是因为前端 mvvm 写交互界面太方便。
@wly19960911 模板引擎不下十个,用到的时候学一下就行了,半个小时的事情。
KgM4gLtF0shViDH3
    11
KgM4gLtF0shViDH3  
   2018-06-11 09:31:18 +08:00
@sagaxu #10 那是你对前端非常熟的情况下,而且用那些东西对 seo 很不好,搞到最后比不分离还复杂。
grewer
    12
grewer  
   2018-06-11 09:43:32 +08:00
@bestkayle 但是除了 seo 现在的模式完胜以前的模板
maxiujun
    13
maxiujun  
   2018-06-11 09:47:56 +08:00 via iPad
楼主深受框架便利性毒害,应该回归纯 java,最好 servlet 也别用,tomcat 自己写个。
enzohobmg
    14
enzohobmg  
   2018-06-11 09:51:42 +08:00
毒害就过分了 哈哈哈哈 恶心确实有点
liuxey
    15
liuxey  
   2018-06-11 09:53:04 +08:00
可以再回归一下本质,用 ServerSocket 写一个 rest 服务? :doge:
lhx2008
    16
lhx2008  
   2018-06-11 09:54:17 +08:00 via Android
@maxiujun 我也是这么想的,boot 的话也就省几个配置文件而已,毒害真的说不上。如果说了解下 boot 里面的 springmvc 的运行方式也还不错。
littleghosty
    17
littleghosty  
   2018-06-11 10:02:55 +08:00
@bestkayle 小公司的 java 程序员都是前后端一把抓吗?
chinvo
    18
chinvo  
   2018-06-11 10:05:29 +08:00 via iPhone
楼主深受 Java 便利性的毒害,赶紧汇编自己从网卡驱动写一个
KgM4gLtF0shViDH3
    19
KgM4gLtF0shViDH3  
   2018-06-11 10:05:37 +08:00
@littleghosty #17 PHP 基本都是的,如果没有专门的前端或者没有前端服务器不都是一把梭。
hansonwang99
    20
hansonwang99  
OP
   2018-06-11 10:38:59 +08:00 via iPhone
mark
woscaizi
    21
woscaizi  
   2018-06-11 10:41:40 +08:00
@littleghosty #17 是的
littleghosty
    22
littleghosty  
   2018-06-11 10:43:07 +08:00
@bestkayle
@woscaizi
哎,感觉真累啊
codeyung
    23
codeyung  
   2018-06-11 10:44:52 +08:00
sb 也可以 用 mvc 一样的... 感觉重复工作
littleghosty
    24
littleghosty  
   2018-06-11 10:45:20 +08:00
@bestkayle 小公司还用 JSP JSTL EL ?
ljw15011154354
    25
ljw15011154354  
   2018-06-11 10:48:16 +08:00
前后端分类和大公司小公司有什么关系啊???现在是 2018 年不是 2008 年
pynix
    26
pynix  
   2018-06-11 10:48:37 +08:00
有人居然喜欢配置。。。
ming2050
    27
ming2050  
   2018-06-11 10:49:14 +08:00 via iPhone
一本正紧的开倒车
jeffson
    28
jeffson  
   2018-06-11 10:52:05 +08:00
路过
vjnjc
    29
vjnjc  
   2018-06-11 11:29:44 +08:00 via Android
问一下 spring boot 有啥缺点么,我用了半年好像还没遇到。。。
hansonwang99
    30
hansonwang99  
OP
   2018-06-11 13:23:01 +08:00 via iPhone
滴滴滴,倒车请注意
undeflife
    31
undeflife  
   2018-06-11 13:46:53 +08:00
看不懂在做什么
spring boot 里对 http 请求的处理部分不还是 spring-web,spring-webmvc 在处理吗?同样可以用 jsp,ModelAndView
如果你实在喜欢 web.xml 完全可以保留 web.xml 文件
感觉你只是单纯的不喜欢注解,用 spring 1.x 就好了.
misaka19000
    32
misaka19000  
   2018-06-11 13:49:58 +08:00
建议楼主再写一个“从 SpringMVC 到 Servlet ”
VoidChen
    33
VoidChen  
   2018-06-11 17:29:34 +08:00
再倒一车,来个 ssh ( status+spring+hibernate )。。。手动狗头=-=
james2013
    34
james2013  
   2018-06-11 22:00:28 +08:00   2
楼主来到 V2EX 论坛,便排出 9 篇大文,唠叨着深受 SpringBoot 毒害,要回到 SpringMVC 什么的.
众人围着楼主,提问声音不绝于耳,请注意倒车,楼主再写一个“从 SpringMVC 到 Servlet ”,前后端分离很不错,为啥还要用 jsp?
楼主红着脖子喃喃道,你们懂什么?
写了这么多代码和配置文件,你们不知道楼主我有多么努力么?
多么熟悉 SpringMVC 原理,你们会配置 SpringMVC 么?
领导整体听到我的键盘声噼噼啪啪,一直夸我很努力,有上进心,说我每天最晚走,下个月就给我颁发最多加班奖.
JSP 传承这么多年了,不能断送在我们这一代程序员手里.
...
顿时倒车滴滴声响成一片,帖子中充满了欢快的气息.
ren2881971
    35
ren2881971  
   2018-06-11 22:06:48 +08:00
springboot 不好用么。。。
wdlth
    36
wdlth  
   2018-06-11 22:34:53 +08:00
只是倒了一个 JSP 的车……
干脆直接用 maven 建个 webapp 得了,还用啥 spring …… Servlet 一把梭。
ifsoar0712
    37
ifsoar0712  
   2018-06-12 09:29:34 +08:00
@james2013 doge:
MarcoM
    38
MarcoM  
   2018-06-12 11:13:43 +08:00
很好 学习了
fumichael
    39
fumichael  
   2018-06-12 11:46:44 +08:00
我这还在用 struts2 …,诶…
introle
    40
introle  
   2018-06-12 14:00:40 +08:00
收藏了
james2013
    41
james2013  
   2018-06-12 22:19:05 +08:00
@ifsoar0712 哈哈,昨晚那时突然就来灵感了,就写下了
breezeFP
    42
breezeFP  
   2018-06-13 14:40:41 +08:00
“深受其约定大于配置的便利性毒害之后,我想回归到 SpringMVC 时代”,直接用 servlet 得了
jack80342
    43
jack80342  
   2018-06-13 23:31:39 +08:00
嘿嘿嘿翻译了最新的 Spring Boot 2.0 的英文文档,欢迎 Fork,https://www.gitbook.com/book/jack80342/spring-boot/details
关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5578 人在线   最高记录 6679       Select Language
创意工作者们的社区
World is powered by solitude
VERSION: 3.9.8.5 30ms UTC 08:54 PVG 16:54 LAX 01:54 JFK 04:54
Do have faith in what you're doing.
ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86