Struts原理與實踐(2)

Struts原理與實踐(2)
作者:羅會波 發文時間:2004.08.04
line_4.jpg
marginwidth="0" marginheight="0" src="http://www.cnnet.com.cn/servlets/ad?Pool=tech_pip" frameborder="0" width="360" scrolling="no" height="300">下面,我們就從一個最簡單的登錄例子入手,以對Struts的主要部分有一些直觀而清晰的認識。這個例子功能非常簡單,假設有一個名爲lhb的用戶,其密碼是awave,程序要完成的任務是,呈現一個登錄界面給用戶,如果用戶輸入的名稱和密碼都正確返回一個歡迎頁面給用戶,否則,就返回登錄頁面要求用戶重新登錄並顯示相應的出錯信息。這個例子在我們講述Struts的基礎部分時會反覆用到。之所以選用這個簡單的程序作爲例子是因爲不想讓過於複雜的業務邏輯來沖淡我們的主題。

因爲Struts是建立在MVC設計模式上的框架,你可以遵從標準的開發步驟來開發你的Struts Web應用程序,這些步驟大致可以描述如下:
1定義並生成所有代表應用程序的用戶接口的Views,同時生成這些Views所用到的所有ActionForms並將它們添加到struts-config.xml文件中。
2在ApplicationResource.properties文件中添加必要的MessageResources項目
3生成應用程序的控制器。
4在struts-config.xml文件中定義Views與 Controller的關係。
5生成應用程序所需要的model組件
6編譯、運行你的應用程序.

下面,我們就一步步按照上面所說的步驟來完成我們的應用程序:

第一步,我們的應用程序的Views部分包含兩個.jsp頁面:一個是登錄頁面logon.jsp,另一個是用戶登錄成功後的用戶功能頁main.jsp,暫時這個頁面只是個簡單的歡迎頁面。

其中,logon.jsp的代碼清單如下:

<%@ page contentType="text/html; charset=UTF-8" %>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<HTML>
<HEAD>
<TITLE><bean:message key="logon.jsp.title"/></TITLE>
<html:base/>
</HEAD>
<BODY>
<h3><bean:message key="logon.jsp.page.heading"/></h3>
<html:errors/>
<html:form action="/logonAction.do" focus="username">
<TABLE border="0" width="100%">
<TR>
<TH align="right"><bean:message key="logon.jsp.prompt.username"/></TH>
<TD align="left"><html:text property="username"/></TD>
</TR>
<TR>
<TH align="right"><bean:message key="logon.jsp.prompt.password"/></TH>
<TD align="left"><html:password property="password"/></TD>
</TR>
<TR>
<TD align="right">
  <html:submit><bean:message key="logon.jsp.prompt.submit"/></html:submit>
</TD>
<TD align="left">
  <html:reset><bean:message key="logon.jsp.prompt.reset"/></html:reset>
</TD>
</TR>
</TABLE>
</html:form>
</BODY>
</HTML>


main.jsp的代碼清單如下:

<%@ 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文件,會發現它有這麼兩個鮮明的特點:一是文件頭部有諸如:
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>

這樣的指令代碼,他們的作用就是指示頁面要用到struts的自定義標籤,標籤庫uri是一個邏輯引用,標籤庫的描述符(tld)的位置在web.xml文件中給出,見上篇文章的配置部分。struts的標籤庫主要由四組標籤組成,它們分別是:
bean標籤,作用是在jsp中操縱bean
logic標籤,作用是在jsp中進行流程控制
html標籤,作用是顯示錶單等組件
template標籤,作用是生成動態模板

關於每類標籤的具體作用及語法,因受篇幅限制,不在這裏詳細討論,大家可參考struts手冊之類的資料。只是心裏要明白所謂標籤其後面的東西就是一些類,這點與bean有些相似,它們在後端運行,生成標準的html標籤返回給瀏覽器。

要使用它們顯然要把它們的標籤庫描述文件引入到我們的系統中,這是些以.tld爲擴展名的文件,我們要把它們放在/webapps/mystruts/WEB-INF/目錄下。引入struts標籤後原來普通的html標籤如文本框的標籤變成了這樣的形式<?XML:NAMESPACE PREFIX = HTML />。

Jsp文件的第二個特點,就是頁面上根本沒有直接寫用於顯示的文字如:username,password等東西,而是用<?XML:NAMESPACE PREFIX = BEAN />這種形式出現。這個特點爲國際化編程打下了堅實的基礎,關於國際化編程後面的文章還會專門討論。

這個簡單的應用所用到的ActionForm爲UserInfoForm,代碼清單如下:

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文件中

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


特別要提醒一下的是:關於ActionForm的大小寫,一定要按照上面的寫,以免造成不必要的麻煩。

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

第二步,我們建一個名爲ApplicationResource.properties的文件,並把它放在/webapps/mystruts/WEB-INF/classes目錄下。它在struts-config.xml的配置信息我們已在第一篇文章的末尾說了,就是:


目前我們在ApplicationResource.properties文件中加入的內容是:

#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類的代碼清單:

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文件中,清單如下:

#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中的位置是排在… 標籤後,我們的登錄程序的配置清單如下:

<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",否則,就拋出出錯信息。其代碼清單如下:

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文件中,清單如下:

#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文件,在前加上如下語句爲我們的應用程序建一個虛擬目錄:

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


啓動,tomcat。在瀏覽器中輸入:http://localhost:8080/mystruts/logon.jsp
如果前面的步驟沒有紕漏的話,一個如圖所示的登錄畫面就會出現在你的眼前。

320304.gif

如果,不輸入任何內容直接點擊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中如何訪問數據庫。

本文作者:羅會波 當陽市國稅局信息中心 可通過[email protected]與他聯繫
發佈了7 篇原創文章 · 獲贊 0 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章