常用MVC框架
J2EE开常用的SSH或SSI框架,对应解决表示层、业务逻辑层、持久化层的问题,其中对表示层的解决方案最多,常见的有Struts1/2,Spring MVC等,实际上都是在最底层的Servlet规范中发展而来的。而不同MVC框架其M(对应JAVA的POJO类)和V(如JSP,HTML等)一般是相同的,最主要的区别在C,它是HTTP处理请求、响应的关键。

我们可以看到,Servlet的基本接口定义中:
参数列表 —— Http请求被封装为一个HttpServletRequest对象(或者ServletRequest对象),而Http响应封装为一个HttpServletResponse对象(或者ServletResponse对象)
返回值 —— 方法不存在返回值(返回值为void)
在这个设计中,HttpServletRequest和HttpServletResponse承担了完整的处理Http请求的任务。而这两个Servlet对象的职责也有所分工:
HttpServletRequest对象 —— 主要用于处理整个Http生命周期中的数据。
HttpServletResponse对象 —— 主要用于处理Http的响应结果。
这里实际上有一点“数据与行为分离”的意味。也就是说,在Servlet处理请求的过程中,其实也是Servlet中响应方法内部的逻辑执行过程中,如果需要处理请求数据或者返回数据,那么我们需要和HttpServletRequest打交道;如果需要处理执行完毕之后的响应结果,那么我们需要和HttpServletResponse打交道。 这样的设计方式,是一种骨架式的设计方式。因为Servlet是我们进行Web开发中最底层的标准,所以我们可以看到接口设计中的返回值对于一个最底层标准而言毫无意义。因为不存在一个更底层的处理程序会对返回值进行进一步的处理,我们不得不在Servlet的过程中自行处理浏览器的行为控制。
【Struts1.X】
Struts1.X是一个较为早期的MVC框架实现,它的历史最早可以追溯到2000年,作为Apache开源组织的一个重要项目,取名为“Struts”,有“基础构建”的含义。在那个程序框架尚处于朦胧阶段的年代,“基础构建”无疑是每个程序员梦寐以求的东西。
对于Struts1.X,我们还是把关注的重点放在Struts中的Controller层的定义上:
- public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response);
如果和之前的Servlet模型加以比较我们就可以发现,Struts1.X对于基本的Servlet模型做了一定的扩展和重构:
- 保留了HttpServletRequest和HttpServletResponse这两大接口作为参数
- 将返回值改为ActionForward,并由Struts1.X框架通过处理ActionForward完成对响应结果的处理
- 增加了ActionMapping和ActionForm两大参数,前者表示Http请求的一个简要概括,后者表示一个数据模型,用以承载整个请求生命周期中的数据
经过一番扩展和重构,我们可以发现Struts1.X相比较于原始的Servlet模型已经有了一定的进步。比如,我们可以不再直接操作HttpServletResponse这样的原生Servlet对象来进行Http返回的处理;再比如,对于一些简单的请求数据读取,我们可以不必直接操作生硬的HttpServletRequest接口,而通过ActionForm来完成。
由于Struts1.X已经不再是一个底层的实现规范,于是响应方法“返回值”被框架引入,加入到了整个处理过程之中。我们可以看到,在这里最大的进步之处就在于:引入了新的编程元素,从而优化整个逻辑处理过程。编程元素的引入非常重要,因为对于一个任何一个程序员而言,充分调用所有可以利用的编程要素是衡量一个程序写得好坏的重要标准。之后,我们还可以看到其他的框架在引入编程元素这个方面所做的努力。
【Webwork2 / Struts2】
Apache社区与Opensymphony开源组织在2005年底宣布未来的Struts项目将与Webwork2项目合并,并联合推出Struts2,通过Apache社区的人气优势与OpenSymphony的技术优势,共同打造下一代的Web层开发框架。这也就是Struts2的由来。 从整个过程中,我们可以发现,Webwork2和Struts2是一脉相承的Web层解决方案。优势突出表现为对Controller的彻底改造:
- public class UserController {
- private User user
- public String execute() {
- // 这里加入业务逻辑代码
- return "success";
- }
- // 这里省略了setter和getter方法
- }
请求映射的配置:
- <action name="register" class="com.demo2do.sandbox.web.UserController" method="register">
- <result name="success">/register-success.jsp</result>
- </action>
从上面的代码中,我们可以看到Webwork2 / Struts2对于Controller最大的改造有两点:
- 在Controller中彻底杜绝引入HttpServletRequest或者HttpServletResponse这样的原生Servlet对象。
- 将请求参数和响应数据都从响应方法中剥离到了Controller中的属性变量。
这两大改造被看作是框架的神来之笔。因为通过这一改造,整个Controller类彻底与Web容器解耦,可以方便地进行单元测试。而摆脱了Servlet束缚的Controller,也为整个编程模型赋予了全新的定义。
当然,这种改造的前提条件在于Webwork2 / Struts2引入了另外一个重要的编程概念:ThreadLocal模式。使得Controller成为一个线程安全的对象被Servlet模型所调用,这也就突破了传统Servlet体系下,Servlet对象并非一个线程安全的对象的限制条件。
从引入新的编程元素的角度来说,Webwork2 / Struts2无疑也是成功的。因为在传统Servlet模式中的禁地Controller中的属性变量被合理利用了起来作为请求处理过程中的数据部分。这样的改造不仅使得表达式引擎能够得到最大限度的发挥,同时使得整个Controller看起来更像是一个POJO。因而,这种表现形态被笔者冠以的名称是:POJO实现模式。
POJO实现模式是一种具有革命性意义的模式,因为它能够把解耦合这样一个观点发挥到极致。从面向对象的角度来看,POJO模式无疑也是所有程序员所追求的一个目标。这也就是Webwork2 / Struts2那么多年来经久不衰的一个重要原因。
【SpringMVC】
相比较Webwork2 / Struts2,SpringMVC走了一条比较温和的改良路线。因为SpringMVC自始至终都没有突破传统Servlet编程模型的限制,而是在这过程中不断改良,不断重构,反而在发展中开拓了一条崭新的道路。
我们可以看看目前最新版本的SpringMVC中对于Controller的定义:
- @Controller
- @RequestMapping
- public class UserController {
- @RequestMapping("/register")
- public ModelAndView register(String email, String password) {
- // 在这里调用具体的业务逻辑代码
- return new ModelAndView("register-success");
- }
- }
我们在这里引用了在之前的讲解中曾经使用过的代码片段。不过这一代码片段刚刚好可以说明SpringMVC在整个Controller改造中所涉及到的一些要点:
1. 使用参数-返回值(Param-Return)实现模式来打造Controller
方法的参数(email和password)被视作是Http请求参数的概括。而在这里,它们已经被SpringMVC的框架有效处理并屏蔽了内在的处理细节,呈现出来的是与请求参数名称一一对应的参数列表。而返回值ModelAndView则表示Http的响应是一个数据与视图的结合体,表示Http的处理结果。
2. 引入Annotation来完成请求-响应的映射关系
引入Annotation来完成请求-响应的映射关系,是SpringMVC的一个重大改造。在早期的SpringMVC以及其他的MVC框架中,通常都是使用XML作为基础配置的。而Annotation的引入将原本分散的关注点合并到了一起,为实现配置简化打下了坚实的基础。
3. 泛化参数和返回值的含义
这是一个蕴含的特点。事实上,SpringMVC在响应方法上,可以支持多种多样不同的参数类型和返回值类型。例如,当参数类型为Model时,SpringMVC将会自动将请求参数封装于Model内部而传入请求方法;当返回值类型是String时,直接表示SpringMVC需要返回的视图类型和视图内容。当然,这些泛化的参数和返回值的内容全部都由SpringMVC在框架内部处理了。
SpringMVC虽然是一个温和的改良派,却是在改良这个领域做得最为出色的。以引入Annotation为例,引入Annotation来完成请求-响应映射,不正是我们反复强调的引入并合理使用新的编程元素来完成处理任务嘛?而泛化后的参数和返回值,则可以让程序员在写Controller的代码时可以随心所欲,不再受到任何契约的束缚,这样一来接口的逻辑语义也就能够更加清晰。
MVC模型的发展轨迹
目前,Struts1.X这一条路被证明已经穷途末路;另外的两条发展轨迹总体来说实力相当,SpringMVC大有赶超之势。
那么,为什么曾经一度占领了大部分市场的Struts2会在近一段时间内被SpringMVC大幅赶超呢?这里面的原因多种多样,有自身架构上的原因,有设计理念上的原因,但是笔者认为,其本质原因还是在于Struts2对于技术革新的力度远不及SpringMVC,后者试用更简单,开发、运行速度更快。
如果我们回顾一下Struts2过去能够独占鳌头的原因就可以发现,Struts2的领先在于编程模型上的领先。其引入的POJO模型几乎是一个杀手级的武器。而基于这一模型上的拦截器、OGNL等技术的支持使得其他的编程模型在短时间很难超越它。 但是随着时代的发展,Struts2在技术革新上的作为似乎步子就迈得比较小。我们可以看到,在JDK1.5普及之后,Annotation作为一种新兴的Java语法,逐渐被大家熟知和应用。这一点上SpringMVC紧跟了时代的潮流,直接用于请求-响应的映射。而Struts2却迟迟无法在单一配置源的问题上形成突破。
常用MVC框架的更多相关文章
- MVC系列——MVC源码学习:打造自己的MVC框架(四:了解神奇的视图引擎)
前言:通过之前的三篇介绍,我们基本上完成了从请求发出到路由匹配.再到控制器的激活,再到Action的执行这些个过程.今天还是趁热打铁,将我们的View也来完善下,也让整个系列相对完整,博主不希望烂尾. ...
- MVC系列——MVC源码学习:打造自己的MVC框架(一:核心原理)
前言:最近一段时间在学习MVC源码,说实话,研读源码真是一个痛苦的过程,好多晦涩的语法搞得人晕晕乎乎.这两天算是理解了一小部分,这里先记录下来,也给需要的园友一个参考,奈何博主技术有限,如有理解不妥之 ...
- .NET平台常用的框架整理
基于.NET平台常用的框架整理 DotNet | 2016-03-31 17:13 (点击上方蓝字,可快速关注我们) 来源:天使不哭 链接:http://www.cnblogs.com/hgmyz/p ...
- 自己动手写一个简单的MVC框架(第二版)
一.ASP.NET MVC核心机制回顾 在ASP.NET MVC中,最核心的当属“路由系统”,而路由系统的核心则源于一个强大的System.Web.Routing.dll组件. 在这个System.W ...
- Asp.net Core基于MVC框架实现PostgreSQL操作
简单介绍 Asp.net Core最大的价值在于跨平台.跨平台.跨平台.重要的事情说三遍.但是目前毕竟是在开发初期,虽然推出了1.0.0 正式版,但是其实好多功能还没有完善.比方说编译时的一些文件编码 ...
- MVC框架三大模块
1.Routing模块 Routing机制与MVC5的URL解析处理流程基本是相同的,很多的接口和类像IRouteHandler.IHttpHandler.IController .RouteBase ...
- .NET轻量级MVC框架:Nancy入门教程(二)——Nancy和MVC的简单对比
在上一篇的.NET轻量级MVC框架:Nancy入门教程(一)——初识Nancy中,简单介绍了Nancy,并写了一个Hello,world.看到大家的评论,都在问Nancy的优势在哪里?和微软的MVC比 ...
- Struts和SpringMVC两种MVC框架比较
基于Web的MVC framework在J2EE的世界内已是空前繁荣.TTS网站上几乎每隔一两个星期就会有新的MVC框架发布.目前比较好的MVC,老牌的有Struts.Webwork.新兴的MVC框架 ...
- 【JavsScript】JavaScript MVC 框架技术选型
你很喜欢Gmail和Trello之类的单页面应用,但是不太确定该从何开始.也许你的JavaScript代码是如此的杂乱无章,以致于你很想在下一个项目上尝试下JavaScript MVC库和框架,却苦于 ...
随机推荐
- 【深入篇】Andorid中常用的控件及属性
TextView android:autoLink 设置是否当文本为URL链接/email/电话号码/map时,文本显示为可点击的链接.可选值(none/web/email/phone/map/al ...
- Model、ModelMap、ModelAndView的作用及区别
Model.ModelMap.ModelAndView的作用及区别 对于MVC框架,控制器controller执行业务逻辑 用于产生模型数据Model 视图view用来渲染模型数据 Model和Mod ...
- cluster discovery概述及FaultDetection分析
elasticsearch cluster实现了自己发现机制zen.Discovery功能主要包括以下几部分内容:master选举,master错误探测,集群中其它节点探测,单播多播ping.本篇会首 ...
- Swagger文档转Word
Swagger文档转Word 文档 GitHub 地址:https://github.com/JMCuixy/SwaggerToWord/tree/developer 原创作品,转载请注明出处:h ...
- 洛谷P1622 释放囚犯
题目描述 Caima王国中有一个奇怪的监狱,这个监狱一共有P个牢房,这些牢房一字排开,第i个紧挨着第i+1个(最后一个除外).现在正好牢房是满的. 上级下发了一个释放名单,要求每天释放名单上的一个人. ...
- IntelliJ IDEA 启动tomcat 报错: idea Unable to open debugger port (127.0.0.1:58233): java.net.SocketException "socket closed"
debug启动项目弹出提示 Error running omp: Unable to open debugger port (127.0.0.1:50812): java.net.SocketExce ...
- Linux shell command学习笔记(二)
<cut> 作用:从输入文件或者命令的输出中析取出各种域 用法:cut –c{字符串范围} –d{字段间分割符} –f{字段索引编号} 举例: (1)查看在线用户:who | cut –c ...
- position(static-relative-absolute-fixed),margin(top-right-bottom-left),top-right-bottom-left
最近写css遇到一些问题,所以准备写下来捋一下思路. 1.position=satic下看margin的使用.(top-right-bottom-left在这种case下无效) 1-1)margin ...
- Angular:内置指令
[ngIf]表达式结果为真,显示元素:表达式结果为假,移除元素. <div *ngIf="a > b"></div> [ngSwitch]对表达式进行 ...
- Vue路由query传参
1.不要进行过深的嵌套 let id = 'uyu' this.$router.push({ path: '/mrp_detail', query: { re_order_id: id, option ...