用Struts开拓基于MVC的Web应用
副标题#e#
MVC先容
MVC模式是一种很是抱负化的设计模式,应用MVC模式完成两个以上项目标人都有同样的体会,他们已经对以前的事情要领举办了彻底的改革。事情模式的改变要支付疾苦的价钱,但此刻你有现成的技能架构可以回收,制止在项目中本身开拓、探索。它就是开源Apache Struts framework,它提供了实现MVC设计模式最好的实现东西。
在本文中,我们将简朴相识、体会一下模子-视图-节制器(MVC)设计模式,出格地,我们来看看如何用Struts架构来完美地实现MVC模式。我们先从理论上简朴地描写MVC模式,然后用我们一个简朴的例子来实现我们本身的MVC架构。在对MVC模式有了相识后,我们用Struts来看这个新技能是如何辅佐我们迅速、简朴地建设基于MVC的Web应用。
模子-视图-节制器(Model-View-Controller)模式
MVC模式最早是在Smalltalk(一种面向工具的语言)这种措施语言设计中被提出来的。我们临时先忽略它的汗青,会合留意力在存眷它奈何被应用在Web应用开拓中。
当Java的Servlets技能最开始呈现的时候,措施员们立决心识到这是一项极其有用的技能。与同时代的CGI Web开拓技能对比,Servlets更快,更机动,更靠得住,更强大。然而,开拓基于Servlets技能的Web应用有一个庞大的缺陷–需要利用譬喻out.println之类的语句来输出欣赏器识此外HTML。频繁利用这个要领是个错误的倾向,开拓极其挥霍时间(措施员需要常常退出所有应用措施举办从头编译)。而且这也使修改Web页面的事情也变得很坚苦,因为Web的表示和逻辑在一堆令人惊骇的代码中掺乎在一起。
于是作为办理要领的JavaServer Pages(JSP)呈现了,它们将Servlets酿成它们运行的功效。应用JSP技能,我们将业务逻辑用一系列混合在HTML中的<%>标识来表达。以开拓JSP为焦点的应用尽量比以Servlet为焦点的应用有进步,但看起来仍然是混乱无章的,仍然需要用特另外代码来节制应用页面的流转。在布满名目化代码的JSP页面上,没有处所来增加这样特另外节制代码。显然需要寻找此外出路。
不久人们认识到同时应用JSP和Servlets两种技能开拓Web应用是一种不错的选择。究竟,Servlets擅优点理业务逻辑的编程,处理惩罚请求,节制成果页面的流转,而JSP则是名目化请求处理惩罚功效,通过欣赏器得到用户输入。这种事情机制厥后酿成了人们长说的Model2(用JSP或Servlets中单独的一种实现web应用被称做Model 1).
Model 2不是一项革命性的新模式,其实它是来自于Smalltalk语言研发进程中呈现的MVC模式。大大都环境下,Java措施员趋向于可完全交流地利用这两个名词。
#p#副标题#e#
什么是MVC模式?
此前我们已对MVC在开拓基于Java技能Web应用中的利用汗青有了劈头的相识,此刻让我们来看看这种模式的细节。本节中,我们来精确地相识一下Models、Views、Controllers简直切寄义,它们实现的任务,以及如何操作它们实现一个简朴的MVC框架。我们先来看看Model、View、Controller是如何交互事情的。
图SM01
Figure 1 : Model 2/MVC架构
如上图所示,用户通过提交requests与Controller组件(凡是表示为Servlets)交互。接着Controller组件实例化Model组件(凡是表示为JavaBeans可能雷同技能),而且按照应用的逻辑哄骗它们。一旦Model被建设,Controller抉择下一个为用户显示的View(经常表示为JSP),同时View与Model交互操纵,得到并为用户显示相关数据。在它被提交到Controller从头开始此操纵之前,View可以修改Model的状态。
为了更全面得领略组件之间的交互,我们来看一个应用这种框架实现的简朴例子。这是一个完成提交、记任命户登岸信息的简朴应用。
View
本例的View由两个简朴的JSP页面构成。请参考代码 (login.jsp、welcome.jsp)。
1>login.jsp只是简朴地提供了用户输入姓名和口令的操纵界面。输入完成后,登岸页提交输入到controller Servlet(代码如后Controller部门说明),汇报它需要挪用"登岸操纵(login action)"(操纵参数通过form来通报);
2>welcome.jsp页面操浸染户前页提供的用户姓名显示一个接待信息。这里只是简朴地挪用了session中的JavaBean(从userBean的tag标识可以看到)。这个Bean是被Controller置于session中,我们接下来可以看到。
Controller
样例中的controller由一个Servlet组成,代码拜见(Controller.class)。实现了我们应用中的Controller。
这是个简朴的controller,仅仅按照一个request参数(action)抉择挪用哪一个action。本例中,页面将login action作为参数通报进来,所以LoginAction被挪用。该action实现了一个尺度接口(Action),界说了将Request和Response工具作为参数的execute要领。这个action类返回被挪用的下一页的路径,于是用户重定向到此页面。
#p#分页标题#e#
LoginAction类从request中得到username参数,建设一个新的model工具(UserBean),并将其传至Session,并返回"/welcome.jsp"标识流转的下一页面是welcome.jsp.
Model.
我们示例中的model也很简朴,仅由一个JavaBean组成。代码参考UserBean.class。
Action的扩展应用
如你所示,这是一个很简朴的Model 2应用,但它可以被在更洪流平扩展。好比,我们可以动态设置映射request参数的action,我们也可以详细化controler的流转节制(好比action可以通过一个设置打点器(configuration manager)来动态得到需要返回的页面,而不是象此刻这样写死在措施里)。
然而,事实上有一个现成的框架提供所有这些节制、MVC组装相关的可设置项,甚至更多。
这个现成的框架就是Struts。
Struts先容
Struts项目作为一个设想是Craig McClanahan2000年提出的,方针是为操作Java技能开拓基于MVC模式的Web应用提供一个尺度模式。Struts 1.0在2001年中期被最终宣布,此刻成为Apache Foundation的Jakarta项目标一部门。Structs应用范畴极广,可以用在差异的项目,差异的行业(我所见到的从电信到电子商务都有应用实例)。
Struts是一个高度可设置、高度扩展性的MVC框架,我们险些可以用它开拓任何能想到的用Java技能的Web应用。MVC模式的每一部门在Structs中都有相关对应部门。
Struts的安装
可以在http://apache.get-software.com/jakarta/struts/binaries/jakarta-struts-1.1.zip下载得到Struts的最新版本(今朝是1.1)。下载后解压zip文件。宣布包中包括了所有开拓Struts应用所需的类库。宣布包的Webapps目次下有一个空缺的Struts Web应用(struts-blank.war),它已经包括了一个Web应用的骨架,很是有用,在这个基本上成立本身的应用显然对初学者能很快获得成绩感。
本身的代码放在WEB-INF/classes 目次下,按照本身的需要修改设置文件WEB-INF/struts-config.xml,做到这步,Struts的设置就完成了。此刻就拥有了一个完全有效的Struts应用了。
让我们来看看Struts提供的组件
View层
大大都Struts应用的view层是由JSP构成的。为了使view的开拓越发容易,Struts提供了一整套JSP自界说的tag库。这些tag库使我们能很容易地提供完全国际化的用户界面,这些界面凡是是与Struts应用中的Model组件交互。
凡是Web应用的动态前端都是基于HTML表单的,这些应用的用户需要应用的靠得住性获得担保,这样就需要表单校验。假如用尺度的JSP,记录表单的内容和从一个JavaBean得到表单内容简朴乏味并且容易堕落。Structs应用FormBean使表单处理惩罚和校验变得容易。FormBean与Struts的tag库团结,使带form的View开拓变得容易而自然。
下面是一个Struts的JSP页面样例。
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<html:html>
<head></head>
<body bgcolor="white">
<html:errors/>
<html:form action="/logon">
<table border="0" width="100%">
<tr>
<td>
Username:
</td>
<td>
<html:text property="username"/>
</td>
</tr>
<tr>
<td>
Password:
</td>
<td>
<html:password property="password"/>
</td>
</tr>
<tr>
<td>
<html:submit/>
</td>
<td>
 
</td>
</tr>
</table>
</html:form>
</body>
</html:html>
从以上JSP样例可以看出,这与尺度的HTML 表单差异。页面中没有混乱无章的JSP<%>代码,然而它却能完成更多的成果。此JSP引入了Struts的HTML tag 库,它增加了可以或许完成收集提供了校验、错误处理惩罚、model交互成果的表单。留意<html:errors> tag,它可以显示model可能controller已经注册的错误。<html:form> tag则建设了一个基于ActionForm工具的HTML表单。上例中表单的action被置于 /login,我们用这个值到设置文件(示譬喻后)中去找对应的ActionForm。这种映射干系由表单工具的名字和它被存储的范畴(session,页面,应用等等)构成。工具的属性用<html:text> 、<html:password> tag来暗示,组成表单。值得夸耀的长处是,ActionForm被提交时可以自动拾获对应的表单数据,无须我们劳神。
#p#分页标题#e#
从前面我们提到的ActionForm的用处来看,它好像应该被视为应用的Model,然而事实上他们该当被看成应用中controller的一部门。ActionForm bean中显示了model的属性,但它们不包括任何一连性逻辑可能业务逻辑。ActionForm只是用来在Model、View之间通报Model信息。
因为ActionForm属于controller中的一部门,我们将在后头controller的部门来详细相识它。
Model层
Struts应用中的model层可以应用任何基于Java的技能实现,好比EJB,Hibernate,可能JDO。凡是,model是作为包括数据和业务逻辑的简朴JavaBean呈现的。如前所述ActionForm工具不是真正model层的浮现,同时Model层该当独立于HTML的表单工具。假如大概的话,model工具的开拓该当是与利用的开拓技能和开拓情况(Struts可能其他)无关的,这样我们就可以在差异的情况和应用中很容易地重用它们。
为了演示,我们开拓了一个简朴的基于JavaBean的model层工具,它不包括一连性逻辑。这个工具与我们的ActionForm工具映射,将来利用model层工具时,我们只需用更巨大的逻辑来取代它。
Controller层
Struts内置一个实现了controller主要成果的Servlet,它提供将需要挪用的URL与一个action工具对应起来的成果。这个Servlet被称作ActionServlet,完成下列成果:
1>按照用户要求抉择需要的action;
2>为View提供View需要的数据;
3>抉择要显示的下一个View。
ActionServlet(强调:该Servlet已由Struts实现,是Struts架构的焦点地址,开拓者无须体贴)的重头事情是挪用一系列简朴的Action类。Struts开拓人员的事情主要是提供这些actions来实现应用的逻辑。建设action必需实现action接口。此接口包括以下要领:
public ActionForward execute(ActionMapping mapping,
ActionForm form,HttpServletRequest request,HttpServletResponse response)
throws Exception;
如上所示,该要领将ActionForm作为它的一个参数。上面提到的ActionServlet担保了正确的form通报给这个要领。在View层我们说过,ActionForms在Model层和View之间通报数据。
ActionForms是一个很是简朴的工具;以下代码显示了我们将在一个简朴的HTML表单顶用到的ActionForms:
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;
public class Login extends ActionForm {
protected String username;
protected String password;
public void setUsername(String username) {
this.username = username;
}
public String getUsername() {
return username;
}
public void setPassword(String password) {
this.password=password;
}
public String getPassword() {
return password;
}
}
Action还包括一个ActionMapping工具。它被ActionServlet自动处理惩罚,浮现应用的设置。详细设置可以从一个XML文件得到,凡是就是struts-config.xml文件,下面将会提到。
action运行要领将尺度的request 、response作为参数,应用可以操作这些挪用参数。action类处理惩罚完毕后,将ActionMapping所映射的要挪用的下一个页面作为参数返回给ControllerServlet(Struts内置)。
集成Struts组件
我们来看Struts是如何将这三层的组件组合在一起组成完整的应用。Struts应用用struts-config.xml来完成设置。这个设置文件包括了应用的所有可设置信息,包罗:
1>要用到的controller
2>ActionForms和他们对应的HTML forms
3>Actions
4>ActionMappings,它节制应用的整个成果流转
struts-config.xml的重要设置元素都包括在<struts-config>标识下。<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE struts-config PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 1.2//EN"
"http://jakarta.apache.org/struts/dtds/struts-config_1_2.dtd">
<struts-config>
设置ActionForm工具:
<form-beans>
<form-bean
name="logonForm"
type="com.samjdalton.struts.LogonForm"/>
</form-beans>
以上设置声明一个"logonForm"的表单,接着说明需要用com.samjdalton.struts.LogonForm class来完成该表单配置。
下一步,我们声明ActionMappings。
<action-mappings>
<action
path="/Login"
forward="/login.jsp"/>
<action
path="/Welcome"
forward="/welcome.jsp"/>
<action
path="/ProcessLogin"
type="com.samjdalton.struts.LoginAction"
name="logonForm"
scope="request"
validate="true"
input="/Login.do">
<forward
name="success"
path="/Welcome.do"/>
<forward
name="failure"
path="/Logon.do"/>
</action>
</action-mappings>
#p#分页标题#e#
这段设置声明白我们应用中的三个action。前两个(/Login 、/Welcome)很简朴,他们的前向都是JSP页面。第三个巨大一些,它在一个表单提交时被挪用,它建设一个操作logonForm 元素构建的ActionForm,然后挪用LoginAction类来处理惩罚信息。我们可以看到两个<forward>元素,这些界说了应用的成果流转节制。应用参考他们的名字(乐成可能失败),然后节制被交到相关资源。
实例进修Struts
简朴看过了Struts的构成及组装,此刻来实现一个简朴的应用,它实现与本文开头例子中沟通的成果,即用户登岸并显示接待信息。
应用中的view由2个简朴JSP组成,第一个为登岸页,如下:
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<html:html>
<head></head>
<body bgcolor="white">
<html:errors/>
<html:form action="/ProcessLogin">
<table border="0" width="100%">
<tr>
<td>
Username:
</td>
<td>
<html:text property="username"/>
</td>
</tr>
<tr>
<td>
Password:
</td>
<td>
<html:password property="password"/>
</td>
</tr>
<tr>
<td>
<html:submit/>
</td>
<td>
 
</td>
</tr>
</table>
</html:form>
</body>
</html:html>
这个与不消Struts的例子中的页面很是雷同,差异之处仅仅是用Struts <html> tags界说了表单和挪用的Action是设置中界说的"/ProcessLogin"。表单提交后相应的ActionForm将被建设,同时相应的action被挪用处理惩罚该输入。我们还可以看到<html:errors> tag被用到,这个是为了自动显示表单中界说的校验错误信息(下面将提到)。
第二个JSP如下:
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<html:html>
<h1>Welcome <bean:write name="loginForm" property="username" /></h1>
</html:html>
本页简朴地显示了一个定名为"loginForm"的ActionForm bean的一个属性(username).
接着是controller层。controller层由ActionForm、Action两个类实现。ActionForm类很简朴,主要是对应model(本例中是一个简朴的JavaBean工具)。
package com.samjdalton.struts;
import org.apache.struts.action.ActionForm;
public class LoginForm extends ActionForm {
private LoginBean bean;
public LoginForm() {
this.bean=new LoginBean();
}
public LoginForm(LoginBean bean) {
this.bean = bean;
}
public void setUsername(String username) {
bean.setUsername(username);
}
public String getUsername() {
return bean.getUsername();
}
public void setPassword(String password) {
bean.setPassword(password);
}
public String getPassword() {
return bean.getPassword();
}
}
Action类用上面的ActionForm从view得到信息,而且修改model状态。
Action类代码如下:
package com.samjdalton.struts;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionForm;
public class LoginAction extends Action {
public ActionForward execute(ActionMapping actionMapping, ActionForm actionForm, javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse) throws Exception {
// check the username
LoginForm form = (LoginForm) actionForm;
if (form.getUsername().equalsIgnoreCase("sam") && form.getPassword().equals("password")) {
// we are in
return actionMapping.findForward("success");
} else {
// not allowed
return actionMapping.findForward("failure");
}
}
public ActionErrors validate(ActionMapping actionMapping
HttpServletRequest httpServletRequest) {
ActionErrors errors = new ActionErrors();
if ( getUsername() == null || getUsername().length() < 1 ) {
errors.add("name",new ActionError("error.name.required"));
}
if ( getPassword() == null || getPassword().length() < 1 ) {
errors.add("pw",new ActionError("error.pw.required"));
}
return errors;
}
可以看到,action查抄用户在username、password是否输入了"sam"、"password"。假如输入正确,action指明要挪用的下一个view。
#p#分页标题#e#
action类还包括一个要领:validate。本例中,validate要领查抄username 和password的输入,假如输入有误,返回错误信息。这些错误信息包括在一个资源文件(为了支持国际化)中,该文件信息在设置文件中被设置。
应用的model是一个不包括一连逻辑的尺度JavaBean工具,如下所示:
package com.samjdalton.struts;
public class LoginBean {
private String username;
private String password;
public void setUsername(String username) {
this.username=username;
}
public String getUsername() {
return username;
}
public void setPassword(String password) {
this.password = password;
}
public String getPassword() {
return password;
}
}
应用的struts-config.xml设置文件:
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE struts-config PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 1.2//EN"
"http://jakarta.apache.org/struts/dtds/struts-config_1_2.dtd">
<struts-config>
<form-beans>
<form-bean name="loginForm" type="com.samjdalton.struts.LoginForm"/>
</form-beans>
<action-mappings>
<action path="/Login" forward="/login.jsp"/>
<action path="/Welcome" forward="/welcome.jsp" name="loginForm" scope="request"/>
<action path="/ProcessLogin" type="com.samjdalton.struts.LoginAction"
name="loginForm" scope="request" validate="true" input="/Login.do">
<forward name="success" path="/Welcome.do"/>
<forward name="failure" path="/Login.do"/>
</action>
</action-mappings>
<message-resources parameter="ApplicationResources" null="false" />
</struts-config>
大大都文件与上例所示沟通,仅有的区别是<message-resources> tag。此tag答允我们详细化应用代码中的string范例,长处是容易国际化。上例中,资源包括在名字为"ApplicationResources.properties"的文件中,它必需存在于应用的classpath(万无一失的要领是将它设置到你的WEB-INF/classes路径下)。
设置乐成后,IE中输入如下URL(Tomcat):
http://localhost:8080/<war-file-name>/Login.do
应用运行的显示功效如下:
The login page
The welcome page
The error page
小结
本文中,我们先先容了MVC模式,用两种技能完成可一个MVC模式的简朴实现,包罗Struts,这项可以开拓更机动、扩展性更强的基于MVC模式的Web应用。显然这已经远远超出了Struts所包围的。