Struts原理与实践(2)

来源:互联网 发布:java post 多文件上传 编辑:程序博客网 时间:2024/06/14 19:56
 
</TD>
</TR>
</TABLE>
</html:form>
</BODY>
</HTML>
 



main.jsp的代码清单如下: 
quote:

<%@ page contentType=/"text/html; charset=UTF-8/" %>
<%@ taglib uri=/"/WEB-INF/struts-bean.tld/" prefix=/"bean/" %>
<%@ taglib uri=/"/WEB-INF/struts-logic.tld/" prefix=/"logic/" %>

<HTML>
<HEAD>
<TITLE><bean:message key=/"main.jsp.title/"/></TITLE>
<html:base/>
</HEAD>
<BODY>
<logic:present name=/"userInfoForm/">
<H3>
  <bean:message key=/"main.jsp.welcome/"/> 
  <bean:write name=/"userInfoForm/" property=/"username/"/>!
</H3>
</logic:present>
</BODY>
</HTML>
 



首先,我们看一下logon.jsp文件,会发现它有这么两个鲜明的特点:一是文件头部有诸如:



这样的指令代码,他们的作用就是指示页面要用到struts的自定义标签,标签库uri是一个逻辑引用,标签库的描述符(tld)的位置在web.xml文件中给出,见上篇文章的配置部分。struts的标签库主要由四组标签组成,它们分别是:

bean标签,作用是在jsp中操纵bean

logic标签,作用是在jsp中进行流程控制

html标签,作用是显示表单等组件

template标签,作用是生成动态模板 

关于每类标签的具体作用及语法,因受篇幅限制,不在这里详细讨论,大家可参考struts手册之类的资料。只是心里要明白所谓标签其后面的东西就是一些类,这点与bean有些相似,它们在后端运行,生成标准的html标签返回给浏览器。 

要使用它们显然要把它们的标签库描述文件引入到我们的系统中,这是些以.tld为扩展名的文件,我们要把它们放在/webapps/mystruts/WEB-INF/目录下。引入struts标签后原来普通的html标签如文本框的标签变成了这样的形式。 

Jsp文件的第二个特点,就是页面上根本没有直接写用于显示的文字如:username,password等东西,而是用这种形式出现。这个特点为国际化编程打下了坚实的基础,关于国际化编程后面的文章还会专门讨论。 

这个简单的应用所用到的ActionForm为UserInfoForm,代码清单如下: 
quote:

package entity;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;
import javax.servlet.http.HttpServletRequest;

public class UserInfoForm extends ActionForm{

  private String username;
  private String password;


  public String getUsername() {
    return (this.username);
  }
  public void setUsername(String username) {
    this.username = username;
  }

  public String getPassword() {
    return (this.password);
  }
  public void setPassword(String password) {
    this.password = password;
  }
}
 



在你的应用程序的WEB-INF目录下再建一个classes目录,在新建的这个classes目录下再建如下几个目录entity(用于存放ActionForm类)、action目录(用于存放Action类)、bussness目录(用于存放作为Model的业务对象类)。Classes目录下的子目录就是所谓的包,以后,还会根据需要增加相应的包。 

现在,将UserInfoForm.java保存到entity目录中。 

把如下代码添加到/webapps/mystruts/WEB-INF/struts-config.xml文件中 
quote:

<form-beans>
    <form-bean name=/"userInfoForm/" type=/"entity.UserInfoForm/" />
  </form-beans>
 



特别要提醒一下的是:关于ActionForm的大小写,一定要按照上面的写,以免造成不必要的麻烦。 

到此,我们完成了第一步工作。 

第二步,我们建一个名为ApplicationResource.properties的文件,并把它放在/webapps/mystruts/WEB-INF/classes目录下。它在struts-config.xml的配置信息我们已在第一篇文章的末尾说了,就是:


目前我们在ApplicationResource.properties文件中加入的内容是: 
quote:

#Application Resource for the logon.jsp
logon.jsp.title=The logon page
logon.jsp.page.heading=Welcome World!
logon.jsp.prompt.username=Username:
logon.jsp.prompt.password=Password:
logon.jsp.prompt.submit=Submit
logon.jsp.prompt.reset=Reset

#Application Resource for the main.jsp
main.jsp.title=The main page
main.jsp.welcome=Welcome:
 



到此,我们已完成了第二个步骤。 

第三步,我们开始生成和配置Controller组件。 

在前面我们已经提到,Struts应用程序的控制器由org.apache.struts.action.ActionServlet和org.apache.struts.action.Action类组成,其中,前者已由Struts准备好了,后者Struts只是为我们提供了个骨架,我们要做的是为实现应用程序的特定功能而扩展Action类,下面是实现我们登录程序的Action类的代码清单: 
quote:

package action;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionError;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionServlet;
import bussness.UserInfoBo;
import entity.UserInfoForm;
public final class LogonAction extends Action {
  
  public ActionForward execute(ActionMapping mapping,
         ActionForm form,
         HttpServletRequest request,
         HttpServletResponse response)
         throws IOException, ServletException {
    UserInfoForm userInfoForm = (UserInfoForm) form;         
    //从web层获得用户名和口令
    String username = userInfoForm.getUsername().trim();
    String password = userInfoForm.getPassword().trim();
    //声明错误集对象
    ActionErrors errors = new ActionErrors();
    //校验输入
    if(username.equals(/"/")){
      ActionError error=new ActionError(/"error.missing.username/");
      errors.add(ActionErrors.GLOBAL_ERROR,error);
    }
    if(password.equals(/"/")){
      ActionError error=new ActionError(/"error.missing.password/");
      errors.add(ActionErrors.GLOBAL_ERROR,error);
    }
    
    //调用业务逻辑
    if(errors.size()==0){
      String validated = /"/";
      try{
        UserInfoBo userInfoBo=new UserInfoBo();
        validated =userInfoBo.validatePwd(username,password);
        if(validated.equals(/"match/")){
          //一切正常就保存用户信息并转向成功的页面    
          HttpSession session = request.getSession();
          session.setAttribute(/"userInfoForm/", form);          
            return mapping.findForward(/"success/");
        } 
      }
      
      catch(Throwable e){
        //处理可能出现的错误
        e.printStackTrace();
        ActionError error=new ActionError(e.getMessage());
        errors.add(ActionErrors.GLOBAL_ERROR,error);
      }
    }  
    //如出错就转向输入页面,并显示相应的错误信息
    saveErrors(request, errors);    
    return new ActionForward(mapping.getInput());    
  } 
}
 



这个action类中有两个错误消息键要加到ApplicationResource.properties文件中,清单如下: 
quote:

#Application Resource for the LogonAction.java
error.missing.username=<li><font color=/"red/">missing username</font></li>
error.missing.password=<li><font color=/"red/">missing password</font></li>>
 



第四步:在struts-config.xml文件中定义Views与 Controller的关系,也就是配置所谓的ActionMapping。它们在struts-config.xml中的位置是排在… 标签后,我们的登录程序的配置清单如下: 
quote:

<action-mappings>
    <action input=/"/logon.jsp/" name=/"userInfoForm/" path=/"/logonAction/" scope=/"session/" 
    type=/"action.LogonAction/" validate=/"false/">
      <forward name=/"success/" path=/"/main.jsp/" />      
    </action>
  </action-mappings>
 



第五步:生成应用程序所需要的model组件,该组件是完成应用程序业务逻辑的地方,现在我的登录程序的业务逻辑很简单,就是判断用户是不是lhb并且其口令是不是awave如果是就返回一个表示匹配的字符串/"match/",否则,就抛出出错信息。其代码清单如下: 
quote:

package bussness;

import entity.UserInfoForm;

public class UserInfoBo {

  public UserInfoBo(){
    
  }      

  public String validatePwd(String username,String password){
        
    String validateResult=/"/"; 
       
    if(username.equals(/"lhb/")&&password.equals(/"awave/")){
      validateResult=/"match/";
    }
    else{
      
      throw new RuntimeException(/"error.noMatch/");
    }        
    
    return validateResult;   
    
  }
}
 



将其放在bussness包中。 

我们同样要将其表示错误信息的键值设置在ApplicationResource.properties文件中,清单如下: 
quote:

#Application Resource for the UserInfoBo.java
error.noMatch=<li><font color=/"red/">no matched user</font></li>
 



到此为止,我们已经完成了这个简单登录程序的所有组件。下面就可以享受我们的劳动成果了。 

第六步、编译运行应用程序。 

常规的做法是用Ant来装配和部署Struts应用程序,如果按这个套路,这篇文章就会显得十分冗长乏味,同时也没有太大的必要,因为,用一个IDE一般可以很方便地生成一个应用。因此,我们采用简便的方法,直接编译我们的.java文件。不过这里要注意一点的是:实践证明,要使得编译过程不出错,还必须将struts.jar文件放一份拷贝到/common/lib目录中,并在环境变量中设置CLASSPATH 其值是/common/lib/struts.jar;配置好后就可以分别编译entity、bussness及action目录下的.java文件了。编译完成后:打开/conf目录下的server.xml文件,在前加上如下语句为我们的应用程序建一个虚拟目录: 
quote:

<Context path=/"/mystruts/" docBase=/"mystruts/" debug=/"0/"
                 reloadable=/"true/">                 
</Context>
 

启动,tomcat。在浏览器中输入:http://localhost:8080/mystruts/logon.jsp
如果前面的步骤没有纰漏的话,一个如图所示的登录画面就会出现在你的眼前

如果,不输入任何内容直接点击Submit按钮,就会返回到logon.jsp并显示missing username和missing password错误信息;如果输入其他内容,则会返回no matched user的错误;如果输入的用户名是lhb且口令是awave则会显示表示登录成功的欢迎页面。 

上面虽然是一个功能很简单的应用程序,但麻雀虽小,五脏俱全,基本涉及到了struts的主要组成部分。下面我们就来分析一下程序的特点和基本的工作原理。 

首先,我们在浏览器中输入.jsp文件时,后台将struts的自定义标签/"翻译/"成普通的html标签返回给浏览器,而一些提示信息如作为输入框label的username、password还有按钮上提示信息还有错误信息等都来自MessageResources即ApplicationResource.properties文件中对应的键值。当我们点击Submit按钮时,从web.xml的配置可以看出,请求将被ActionServlet截获。它通过表单中提供的action参数在struts-config.xml文件中查找对应的项目,如果有对应的ActionForm,它就用表单中数据填充ActionForm的对应属性,本例中的ActionForm为userInfoForm,相应的属性是username和password,这就是所谓的实例化ActionForm。然后,将控制交给对应的Action,本例中是LogonAction,它做的主要工作是对ActionForm中取出的username和password做了一下校验,这里只是简单检验它们是否为空(这些简单的格式化方面的校验应该放在客户端进行,而且struts也为我们提供了一个很好的模式,后面如果有可能会详细介绍)。如果不为空则调用判断用户及口令是否正确的业务逻辑模块UserInfoBo,同时,它会捕获可能出现的错误,然后根据业务逻辑返回的结果将程序导向不同的页面,本例中如果业务逻辑返回的结果是/"match/"则依据中的返回main.jsp页面给浏览器同时在session对象中保存了用户的登录信息;否则,返回输入页面并显示相应的出错信息,完成了上篇文章所说的它的四个主要职责。 

大家一定注意到了,在本例的业务逻辑模块UserInfoBo中,将用户与密码是写死在程序中的,在一个真实的应用程序中是不会这样做的,那些需要永久保存的信息如,username及口令等都会保存在数据库文件之类的永久介质中,下一篇文章我们将介绍在struts中如何访问数据库。 

本文作者:罗会波 当阳市国税局信息中心 可通过lhbf@sina.com与他联系
原创粉丝点击