基于Spring的MVC框架设计与实现
说明:这篇博客中并⾮讲SpringMVC,⽽是讲述我曾经实现过的⼀个MVC框架,它利⽤Spring框架作为基础框架,并吸收了部分其它框架中的思想,结合了⾃⼰的⼀些想法。此框架的代码算不上复杂,也不如常⽤MVC框架那么强⼤,它只是作为我重新发明轮⼦的⼀个成果。设计这个框架起源于在⽼师那⾥做过的⼀个项⽬,Turbine的设计给了我很⼤的启发,实现后,给它取了个名叫WebSide,并作为毕业设计中的⼀部分,下⽂是从毕业设计中选出,标题与图表都没有经过修改,且其中⾮常少量内容并⾮原创,请读者原谅。
基本特性
2.1 MVC模式及及WebSide框架基本特性
MVC 是⼀种使⽤ MVC(Model View Controller 模型-视图-控制器)设计创建交互式应⽤程序的模式,MVC模式在GUI程序中有很⼴泛的应⽤:
Model(模型)表⽰应⽤程序核⼼(⽐如数据库记录列表)。是应⽤程序中⽤于处理应⽤程序数据逻辑的部分。通常模型对象负责在数据库中存取数据,程序的业务逻辑等。
View(视图)显⽰数据(数据库记录)。是应⽤程序中处理数据显⽰的部分。通常视图是依据模型数据
创建的。
Controller(控制器)处理输⼊(写⼊数据库记录)。是应⽤程序中处理⽤户交互的部分。通常控制器负责从视图读取数据,控制⽤户输⼊,并向模型发送数据。
MVC 分层同时也简化了分组开发。不同的开发⼈员可同时开发视图、控制器逻辑和业务逻辑。传统MVC模式的⽰意图如图2.1。
在传统MVC模式中,控制器作为⽤户与系统功能之间的桥梁,控制器⽤于处理⽤户输⼊,如键盘,按钮的点击等,⽽模型与视图之间则使⽤了观擦者模式,当模型中的状态发⽣变化时,会通知给所有与模型关联的视图,以修改视图的显⽰。
在Web应⽤中,MVC模式有所变化,由于Web应⽤⽆状态的特点,模型与视图之间不需要使⽤观擦者模式。Web MVC模式的⽰意图如
图2.2所⽰。
FrontController⼜叫中⼼控制器,它的作⽤主要是请求的分发。在Web应⽤中,事件是http请求,⽽不是⽤户的键盘或者⿏标输⼊,应⽤在接收到请求后,中⼼控制器可以做请求的通⽤处理,⽐如做⼀些验证,将参数封装成对象等,然后利⽤⼀定的规则将请求委派
给Controller做进⼀步处理。
Web MVC框架的最核⼼的功能是请求分发,WebSide在实现请求分发功能的同时,实现了以下特性:
1. 对请求的拦截加⼊分⽀与try-catch-finally逻辑,使请求的拦截更灵活;
2. 利⽤Spring的⽗⼦容器功能,让每⼀个模块有⼀个独⽴的依赖注⼊容器,且每个模块的依赖注⼊容器共⽤同⼀个⽗容器,保证各模块之间的独⽴性;
3. 可配置的静态数据,如有些数据可以在整个应⽤中使⽤,有些数据只能在某⼀个模块中使⽤;
4. 视图请求视图,⽽不是直接请求Controller,实现视图与控制器的间接依赖,但也可在控制器中做跳转;
5. 实现多视图的⽀持,⼀个请求可以指定它需要什么样的数据
6. 实现将视图中需要的数据的处理与Action分离,且可能根据请求指定的数据类型⾃动调⽤对应的视图处理⽅法;
7. 对HTTP相关的对象的包装,因为Action是singleton范围,⽽HttpServletRequest是request范围,⽽HttpSession则是sesison范围,对它们进⾏包装后,使request和sesison可以被注⼊到Action中;
8. ⽀持多种使⽤⽅式,多种使⽤⽅式可以同时使⽤。
2.2 WebSide的使⽤⽅式
上⾯说到了WebSide⽀持多种使⽤⽅式,且它们不是互斥的,⽽是可同时使⽤的。
2.2.1 多视图
这是WebSide设计的初衷之⼀,但它是框架的使⽤⽅式中最复杂的⼀种。抛开pipeline的细节,它将Action与Controller当作是从⼀个视图跳到另⼀个视图的过程中的两个不同的,Action与Screen都是可选。且请求需要严格遵守框架的约定。这种请求⽅式如图2.3所⽰。请求所返回的资源与请求的url和event,type等参数相关,event代码了需要执⾏的Action中的⽅式,type与event参数决定了Screen中调⽤的⽅法,⽽type⼜决定了返回的数据的类型以及返回数据所在的⽬录,url的最后⼀级(或者resource参数)表⽰资源
名,resource与event决定了返回给请求者的⽂件名。
2.2.2 使⽤注解简化多视图的使⽤
由于最初设计的多视图渲染的使⽤⽅式过于复杂,对于返回json,xml这样的数据时,有时候可以直接使⽤jackson,xstream等⼯具将对象序列化成为json或者xstream,所以在最初定义的约定的基础上,添加了在Screen中使⽤注解做视图渲染的使⽤⽅式。如图2.4中的代码段所⽰。
当在Screen中的⽅法上加上@Xml或者@Json,并给Screen上的⽅法加上返回值后,不需要再严格按照约定在对应的xml⽬录和json⽬录下存放⼀个资源⽂件。WebSide⽀持⾃定义视图渲染注解,任何时候都可以使⽤⾃定义注解处理Screen返回的数据。这种⽅式与前⼀种⽅式差不多。
2.2.3 只使⽤Screen或者Action
Screen虽然是可选的,但它与请求的资源绑定,如果只使⽤Screen,可以保证在请求某个资源前,需要的逻辑⼀定被执⾏。但只使
⽤Screen在处理请求数据上不太⽅便。Screen主要⽤于视图渲染前的数据处理。
Action也是可选的,但Action的执⾏需要⽤户指定,使⽤Action处理请求与业务逻辑的调⽤⽐使⽤Screen要灵活,在不需要使⽤多视图渲染的情况下可以使⽤。
2.2.4 使⽤注解与Action
在不需要⽀持多视图渲染的情况下,使⽤Action与注解是⽐较简单的⼀种使⽤⽅式。能在Screen上使⽤的注解同样也可以使⽤在Action上。这种情况下,pipeline不会再执⾏Screen中的⽅法。⽬前⽀持的注解有
@ToString、@Json、@Xml、@Forward、@Redirect、@Stream,任何时候都可以很⽅便的给它添加其它注解。
2.3 设计理念
Web MVC框架需要实现的功能主要是请求的分发以及请求在到达Action前在Pipeline中的处理过程。常见的MVC框架Struts2和SpringMVC中,页⾯请求⼀个Action或者Controller,在Action中返回数据来确定跳转在哪⼀个视图。WebSide框架的实现过程中,页⾯请求的不是Action,⽽是⼀个资源或者视图,这⾥的Action与Struts2中的Action有较多的不同,同时,将Struts2中的Action拆分成了两个部
分(Action和Screen,其中Action负责处理请求,调⽤或执⾏业务逻辑,⽽Screen则是与资源绑定,
负责不同的资源类型的渲染前的数据处理,如在Web上,登陆成功后直接返回主页,⽽在移动APP上可能需要返回json或者xml,Screen中通过Action执⾏返回的数据可以在不同的⽅法中分别对json,xml和vm/html/jsp做数据的处理,这⾥的资源表⽰⼀切可返回给客户端的视图),当然,在Action/Screen中也可以做视图的跳转或者重定向。例如功能设置头像,⽤户在上传头像后需要跳转到index.vm这个资源上,如果使⽤Struts2,则处理流程是页⾯先请求头像设置Action,然后Action中处理上传的图⽚⽂件并调⽤业务逻辑完成头像的设置,最后返回⼀个字符串,代表要跳转的资源,最终⽤户将看到index.vm这个资源,如果在开发的过程中,页⾯请求的Action还不存,则在开发前端的时候,点击设置头像后会出错,⽆法看到index.vm,需要将Action正确编写后才能完成index.vm的显⽰。如果页⾯不是直接请求Action,⽽是请求index.vm这个资源,但
将Action作为参数指定,WebSide框架在处理请求分发的时候,如果Action不存在,则不执⾏这个Action,那么只要index.vm这个资源存在,则不管处理头像的后端逻辑是否存在,都可以看到最后的index.vm资源,这样就可以将前端的开发与后端完全分离,相互不受影响。⽽Screen,它作为视图渲染前的处理,⽐如可能需要返回xml和json两种格式的数据,如果使⽤Struts2或者SpringMVC,则需要
在Action或者Controller中做判断,处理xml或者json的⽣成,如果把处理视图相关的代码放在Screen中,不同的视图可以⽤不同的⽅法中做处理,由框架决定Screen的调⽤,避免了在Action中加⼊过多与不同的视图的处理相关的代码。Screen虽然是与资源绑定在⼀起,但也不是必须的,浏览器在请求
⼀个资源时,可以指定⼀个Action,Screen也可以看作是与Action之间的⼀种约定,这⼀点体现在Action中的⽅法在调⽤结束后需要返回⼀个什么样的对象,也就是说Action的执⾏结果,Screen将通过Action的返回对象来决定视图渲染相关的数据。
Pipeline的设计仿照的Turbine,但没有那么复杂,它更像是⼀种变形了的Struts2的栈,只是多了⼀些逻辑判断,可以根据请求的后缀来执⾏不同的⼦管道,拥有try-catch-finally⼦管道等。
WebSide框架中,MVC模式的⽰意图如图2.5.
2.3.1 框架的本质
应⽤框架让⼈联想到建筑的框架。
·建筑框架确定了整个建筑的结构;应⽤框架确定了应⽤的结构。
·建筑框架允许你在不改变结构的基础上,⾃由改变其内容。例如,你可以⽤墙体随意分隔房间。应⽤框架允许你在不改变整体结构的基础上,⾃由扩展功能。
可以这样说,框架的本质就是“扩展”,⼀个软件框架必须符合如下要素():
反转控制(IoC)应⽤的流程不是由应⽤控制的,⽽是由框架控制的
默认⾏为框架会定义⼀系列默认的⾏为
扩展性应⽤可以扩展框架的功能,也可以修改框架的默认⾏为
框架本⾝不可更改框架在被扩展时,⾃⾝的代码⽆须被改变
2.3.2 层次化
设计良好的模块,应该是层次化的。
模块B扩展了模块A,同时被模块C扩展。这样就形成了A、B、C三个层次。
层次之间有如下的关系:
·下层定义规则,上层定义细节;(上层、下层也可称为外层、内层)
·下层是抽象的,上层是具体的
·越下层,越稳定(越少改变);越上层,越易变
·依赖倒转(Dependency Inversion)。上层(具体)依赖下层(抽象),⽽不是下层依赖上层
·上层扩展下层时,不需要修改到下层的任何代码和配置。即符合开闭原则
·每⼀层均可被替换
2.4 层次化的设计
·切分功能。每个组件专⼼做⼀件事。
·分析哪些会改变,哪些不会改变。不变部分固化在组件中,可能会改变的部分抽象成接⼝,以便扩展。
·考虑默认值和默认扩展。默认值和默认扩展应该是最安全、最常⽤的选择。对于默认值和默认扩展,⽤户在使⽤时可使⽤默认配置,不需要额外的配置。
jsp用什么前端框架2.5设计思路
思路
2.5.1 框架中的术语
表2.1 框架中的术语
术语含义是否必须
Action 处理HTTP请求的单元,类似于Struts2中的Action。应⽤中的逻辑应该在Action中执⾏或者调⽤。Action类
需要配置在它所在的模块对应的l⽂件中。
否,⼀次请求
可以没
有Action
Screen 视图渲染器,命名来⾃于Turbine框架,但在程序运⾏时与Turbine中有所不同,⼀个Screen与⼀个资源对
应。Screen⽤于处理与返回数据相关的动作。如果需要返回json,则可在Screen中处理json的⽣成中,如
果需要返回XML,也可在Screen中处理XML的⽣成,如果在其它类型的视图(jsp,模板⽂件等),则可
在Screen中设置视图上需要的变量等。Screen中执⾏的⽅法与返回的数据类型对应,如果请求⼀
个Action可能需要返回多种数据类型,则每种返回类型对应⼀个渲染⽅法,如果没有到返回类型对应的
⽅法,则调⽤默认⽅法(execute)进⾏处理。可以在渲染⽅法中设置数据类型中的变量,将数据模板写
在WebRoot中对应的⽂件⾥,然后可通过模板引擎或者JSP将变量应⽤到视图上。不需要配置,但需要遵
守约定。在调⽤Screen上的⽅法时,先调⽤名为${event}${type}的⽅法,如果该⽅法调⽤失败(⽅法不存
在)则调⽤名为${type}的⽅法,如果调⽤失败则调⽤execute⽅法。
否,⼀次请求
可以没
有Screen
视图返回的结果,如JSP,HTML,VM,JSON,XML等。需要,如果跳转到视图失败,框架则会将控制权返还给Servlet容器,让容器决定请求的资源,以便执
⾏Servlet或者返回其它静态资源。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论