服务热线:13616026886

技术文档 欢迎使用技术文档,我们为你提供从新手到专业开发者的所有资源,你也可以通过它日益精进

位置:首页 > 技术文档 > JAVA > 新手入门 > 基础入门 > 查看文档

用struts开发基于mvc的web应用


  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程序员趋向于可完全互换地使用这两个名词。
  什么是mvc模式?

  此前我们已对mvc在开发基于java技术web应用中的使用历史有了初步的了解,现在让我们来看看这种模式的细节。本节中,我们来准确地了解一下models、views、controllers的确切含义,它们实现的任务,以及如何利用它们实现一个简单的mvc框架。我们先来看看model、view、controller是如何交互工作的。

图sm01
用struts开发基于mvc的web应用(图一)
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类返回被调用的下一页的路径,于是用户重定向到此页面。

  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被提交时可以自动拾获对应的表单数据,无须我们操心。

  从前面我们提到的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>

  这段配置声明了我们应用中的三个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。

  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

  应用运行的显示结果如下:

用struts开发基于mvc的web应用(图二)
the login page

用struts开发基于mvc的web应用(图三)
the welcome page

用struts开发基于mvc的web应用(图四)
the error page

  小结

  本文中,我们先介绍了mvc模式,用两种技术完成可一个mvc模式的简单实现,包括struts,这项可以开发更灵活、扩展性更强的基于mvc模式的web应用。显然这已经远远超出了struts所覆盖的。

扫描关注微信公众号