SpringMVC--MVC设计模式(演⽰4个基于MVC框架的案例)
对于简单的Java Web项⽬,我们的项⽬仅仅包含⼏个jsp页⾯,由于项⽬⽐较⼩,我们通常可以通过链接⽅式进⾏jsp页⾯间的跳转。
但是如果是⼀个中型或者⼤型的项⽬,上⾯那种⽅式就会带来许多维护困难,代码复⽤率低等问题。因此,我们推荐使⽤MVC模式。
⼀ MVC概念
1、什么是MVC
MVC的全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,是⼀种软件设计模式。它是⽤⼀种业务逻辑、数据与界⾯显⽰分离的⽅法来组织代码,将众多的业务逻辑聚集到⼀个部件⾥⾯,在需要改进和个性化定制界⾯及⽤户交互的同时,不需要重新编写业务逻辑,达到减少编码的时间。
MVC开始是存在于桌⾯程序中的,M是指业务模型,V是指⽤户界⾯,C则是控制器。
使⽤的MVC的⽬的:在于将M和V的实现代码分离,从⽽使同⼀个程序可以使⽤不同的表现形式。⽐如
Windows系统资源管理器⽂件夹内容的显⽰⽅式,下⾯两张图中左边为详细信息显⽰⽅式,右边为中等图标显⽰⽅式,⽂件的内容并没有改变,改变的是显⽰的⽅式。不管⽤户使⽤何种类型的显⽰⽅式,⽂件的内容并没有改变,达到M和V分离的⽬的。
在⽹页当中:
V:即View视图是指⽤户看到并与之交互的界⾯。⽐如由html元素组成的⽹页界⾯,或者软件的客户端界⾯。MVC的好处之⼀在于它能为应⽤程序处理很多不同的视图。在视图中其实没有真正的处理发⽣,它只是作为⼀种输出数据并允许⽤户操纵的⽅式;
M:即model模型是指模型表⽰业务规则。在MVC的三个部件中,模型拥有最多的处理任务。被模型
返回的数据是中⽴的,模型与数据格式⽆关,这样⼀个模型能为多个视图提供数据,由于应⽤于模型的代码只需写⼀次就可以被多个视图重⽤,所以减少了代码的重复性;
C:即controller控制器是指控制器接受⽤户的输⼊并调⽤模型和视图去完成⽤户的需求,控制器本⾝不输出任何东西和做任何处理。它只是接收请求并决定调⽤哪个模型构件去处理请求,然后再确定⽤哪个视图来显⽰返回的数据;
下图说明了三者之间的调⽤关系:
⽤户⾸先在界⾯中进⾏⼈机交互,然后请求发送到控制器,控制器根据请求类型和请求的指令发送到相应的模型,模型可以与数据库进⾏交互,进⾏增删改查操作,完成之后,根据业务的逻辑选择相应的视图进⾏显⽰,此时⽤户获得此次交互的反馈信息,⽤户可以进⾏下⼀步交互,如此循环。
常见的服务器端MVC框架有:Struts、Spring MVC、ASP.NET MVC、Zend Framework、JSF;常见前端MVC框架:vue、angularjs、react、backbone;由MVC演化出了另外⼀些模式如:MVP、MVVM。
注意:我们应该避免⽤户通过浏览器直接访问jsp页⾯。
2、MVC举例⼀(jsp+servlet+javabean)
最典型的MVC就是jsp+servlet+javabean模式:
Serlvet作为控制器,⽤来接收⽤户提交的请求,然后获取请求中的数据,将之转换为业务模型需要的数据模型,然后调⽤业务模型相应的业务⽅法进⾏更新(这⼀块也就是Model层所做的事情),同时根据业务执⾏结果来选择要返回的视图;
JavaBean作为模型,既可以作为数据模型来封装业务数据(对应实体类),⼜可以作为业务逻辑模型来包含应⽤的业务操作(对应Action类)。其中,数据模型⽤来存储或传递业务数据,⽽业务逻辑模型接收
到控制器传过来的模型更新请求后,执⾏特定的业务逻辑处理,然后返回相应的执⾏结果;实践中会采⽤⼀个实体类来持有模型状态,并将业务逻辑放到⼀个Action类中。
JSP作为表现层,负责提供页⾯为⽤户展⽰数据,提供相应的表单(Form)来⽤于⽤户的请求,并在适当的时候(点击按钮)向控制器发出请求来请求模型进⾏更新;
每个控制器中可以定义多个请求URL,每个⽤户请求都发送给控制器,请求中的URL标识出对应的Action。Action代表了Web应⽤可以执⾏的⼀个操作。⼀个提供了Action的Java对象称为Action对象。⼀个Action类型可以⽀持多个Action(在Spring MVC以及Struts2中),或⼀个Action(在struts1中)。
注意:Struts1、Spring MVC和JavaServer Fces使⽤Servlet作为控制器,⽽Struts2使⽤Filter作为控制器。
3、MVC举例⼆(Struts2框架)
Struts2框架:Struts2是基于MVC的轻量级的web应⽤框架。Struts2的应⽤范围是Web应⽤,注重将Web应⽤领域的⽇常⼯作和常见问题抽象化,提供⼀个平台帮助快速的完成Web应⽤开发。基于Struts2开发的Web应⽤⾃然就能实现MVC,Struts2着⼒于在MVC的各个部分为开发提供相应帮助。
下⾯通过代码来简单解释⼀下(这⾥只是简单使⽤):
Login.html(位于WebContent下)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<form id="form1" name="form1" action="/action/Login.action" method="post">
登录<br>
⽤户名:<input name="username" type="text"><br>
密码:<input name="password" type="password"><br>
<input type="submit" value="登录">
</form>
</body>
</html>
LoginAction.Java(位于包com.dc365.s2下)
if(username.equals("1") && password.equals("1")) {
return "Success";
}
return "Error";
<struts>
<package name="default" namespcase="/action" extends="struts-default">
<action name="Login" class="com.dc365.s2.LoginAction">
<result name="Success">Success.jsp</result>
<result name="Error">Error.jsp</result>
</action>
</package>
</struts>
注意:除了上⾯代码,还需要在l⾥⾯配置前端过滤器FilterDispatcher。
⽤户⾸先在Login.html中输⼊⽤户名和密码,点击登陆,⽤户请求(请求路径为/action/Login.action)⾸
先到达前端控制器FilterDispatcher,FilterDispatcher 根据⽤户请求的URL和配置在l到对应的Login,然后根据对应的class的路径进⼊相应的login.Java,在这⾥判断之后,返回success或error,然后根据l中的result值,指向相应的jsp页⾯。
控制器——filterdispatcher:从上⾯这张图来看,⽤户请求⾸先到达前端控制器FilterDispatcher。FilterDispatcher负责根据⽤户提交的URL和l中的配置,来选择合适的动作(Action),让这个Action来处理⽤户的请求。FilterDispatcher其实是⼀个过滤器(Filter,servlet规范中的⼀种web组件),它是Struts2核⼼包⾥已经做好的类,不需要我们去开发,只是要在项⽬的l中配置⼀下即可。FilterDispatcher体现了J2EE核⼼设计模式中的前端控制器模式。
动作——Action:在⽤户请求经过FilterDispatcher之后,被分发到了合适的动作Action对象。Action负责把⽤户请求中的参数组装成合适的数据模型,并调⽤相应的业务逻辑进⾏真正的功能处理,获取下⼀个视图展⽰所需要的数据。Struts2的Action,相⽐于别的web框架的动作处理,它实现了
与Servlet API的解耦,使得Action⾥⾯不需要再直接去引⽤和使⽤HttpServletRequest与HttpServletResponse等接⼝。因⽽使得Action的单元测试更加简单,⽽且强⼤的类型转换也使得我们少做了很多重复的⼯作。
视图——Result:视图结果⽤来把动作中获取到的数据展现给⽤户。在Struts2中有多种优秀的结果展⽰⽅式,常规的jsp,模板freemarker、velocity,还有各种其它专业的展⽰⽅式,如图表jfreechart、报表JasperReports、将XML转化为HTML的XSLT等等。⽽且各种视图结果在同⼀个⼯程⾥⾯可以混合出现。
4、MVC优点
耦合性低:视图层和业务层分离,这样就允许更改视图层代码⽽不⽤重新编译模型和控制器代码,同样,⼀个应⽤的业务流程或者业务规则的改变只需要改动MVC的模型层即可。因为模型与控制器和视图相分离,所以很容易改变应⽤程序的数据层和业务规则;
重⽤性⾼:MVC模式允许使⽤各种不同样式的视图来访问同⼀个服务器端的代码,因为多个视图能共享⼀个模型,它包括任何WEB(HTTP)浏览器或者⽆线浏览器(wap),⽐如,⽤户可以通过电脑也可通过⼿机来订购某样产品,虽然订购的⽅式不⼀样,但处理订购产品的⽅式是⼀样的。由于模型返回的数据没有进⾏格式化,所以同样的构件能被不同的界⾯使⽤;
部署快,⽣命周期成本低:MVC使开发和维护⽤户接⼝的技术含量降低。使⽤MVC模式使开发时间得到相当⼤的缩减,它使程序员(Java开发⼈员)集中精⼒于业务逻辑,界⾯程序员(HTML和JSP开发⼈员)集中精⼒于表现形式上;
可维护性⾼:分离视图层和业务逻辑层也使得WEB应⽤更易于维护和修改;
5、MVC缺点
完全理解MVC⽐较复杂:由于MVC模式提出的时间不长,加上同学们的实践经验不⾜,所以完全理解并掌握MVC不是⼀个很容易的过程;
调试困难:因为模型和视图要严格的分离,这样也给调试应⽤程序带来了⼀定的困难,每个构件在使⽤之前都需要经过彻底的测试;
不适合⼩型,中等规模的应⽤程序:在⼀个中⼩型的应⽤程序中,强制性的使⽤MVC进⾏开发,往往
会花费⼤量时间,并且不能体现MVC的优势,同时会使开发变得繁琐;
增加系统结构和实现的复杂性:对于简单的界⾯,严格遵循MVC,使模型、视图与控制器分离,会增加结构的复杂性,并可能产⽣过多的更新操作,降低运⾏效率;
视图与控制器间的过于紧密的连接并且降低了视图对模型数据的访问:视图与控制器是相互分离,但却是联系紧密的部件,视图没有控制器的存在,其应⽤是很有限的,反之亦然,这样就妨碍了他们的独⽴重⽤;依据模型操作接⼝的不同,视图可能需要多次调⽤才能获得⾜够的显⽰数据。对未变化数据的不必要的频繁访问,也将损害操作性能;
6、具体案例
接下来我们将会演⽰基于MVC框架的4个不同的⽰例:
第⼀个采⽤Servlet作为控制器;
第⼆个采⽤Filter作为控制器;
第三个引⼊校验器组件来校验⽤户输⼊数据的合法性;
第四个采⽤了⼀个⾃制的依赖注⼊器。在实际的应⽤中,我们应该使⽤Spring。
⼆ MVC案例(Serlvet作为控制器)
创建⼀个名为appdesign1的Dynamic Web Project项⽬,Servlet版本选择3.0,其功能设定为输⼊⼀个产品信息。具体为:
⽤户填写产品表单并提交;
保存产品并展⽰⼀个完成页⾯,显⽰已经保存的产品信息;
⽰例应⽤⽀持如下两个action(每个action对应⼀个URL):
展⽰”添加产品“表单,其对应的URL包含字符串input-product;
保存产品并返回完成界⾯,对应的URL包含字符串save-product;
⽰例应⽤由如下组件组成:
⼀个Product类,作为product的领域对象;
⼀个ProductForm类,封装了HTML表单的输⼊项;
⼀个ControllerServlet,本⽰例应⽤的控制器;
⼀个SaveProdtcuAction类;
两个jsp页⾯(ProductForm.jsp和ProductDetails.jsp)作为视图;
⼀个CSS⽂件,定义了两个jsp页⾯的显⽰风格。
⽰例应⽤⽬录结构如下:
注意:由于我们采⽤的是Servlet3.0版本,l可以不需要,具体可以参考博客。
项⽬右键属性、部署路径设置如下:
1、Product类
Product类是⼀个封装了产品信息的JavaBean。Product类包含三个属性:name,description和price:del;
import java.io.Serializable;
import java.math.BigDecimal;
public class Product implements Serializable {
private static final long serialVersionUID = 748392348L;
private String name;
private String description;
private BigDecimal price;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public BigDecimal getPrice() {
return price;
}
public void setPrice(BigDecimal price) {
this.price = price;
}
}
Product类实现了java.io.Serializable接⼝,其实例可以安全地将数据保存到HttpSession中。根据Serializable的要求,Product类实现了⼀个serialVersionUID 属性。
2、ProductForm表单类
表单类与HTML表单相对应,是后者在服务器的代表。ProductForm类看上去同Product类相似,这就引出⼀个问题:ProductForm类是否有存在的必要:
package appdesign1.form;
public class ProductForm {
private String name;
private String description;
private String price;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getPrice() {
return price;
}
public void setPrice(String price) {
this.price = price;
}
}
实际上,通过表单对象可以将ServletRequest中的表单信息传递给其它组件,⽐如校验器Validator(后⾯会介绍,主要⽤于检查表单输⼊数据是否合法)。如果不使⽤表单对象,则应将ServletRequest传递给其它组件,然⽽ServletRequest是⼀个Servlet层的对象,是不应当暴露给应⽤的其它层。
另⼀个原因是,当数据校验失败时,表单对象将⽤于保存和显⽰⽤户在原始表单上的输⼊。
注意:⼤部分情况下,⼀个表单类不需要事先Serializable接⼝,因为表单对象很少保存在HttpSession中。
3、ControllerServlet类
ContrlooerServlet类继承⾃javax.servlet.http.HttpServlet类。其doGet()和doPost()⽅法最终调⽤process()⽅法,该⽅法是整个Servlet控制器的核⼼。
可能有⼈好奇,为何Servlet控制器命名为ControllerServlet,实际上,这⾥遵从了⼀个约定:所有Servlet的类名称都带有Servlet后缀。
ller;
import java.io.IOException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
jsp用什么前端框架import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import appdesign1.action.SaveProductAction;
import appdesign1.form.ProductForm;
del.Product;
import java.math.BigDecimal;
//Servlet3.0使⽤注解指定访问Servlet的URL
@WebServlet(name = "ControllerServlet", urlPatterns = {
"/input-product", "/save-product" })
public class ControllerServlet extends HttpServlet {
private static final long serialVersionUID = 1579L;
@Override
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
process(request, response);
}
@Override
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
process(request, response);
}
private void process(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。