如果userDAO設置了autowire="byName" ,假設ServiceImpl有一個屬性名為userDAO,Spring就會在配置文件里查找有沒有名字為userDAO的bean, 自動為ServiceImpl注入。
如果bean有兩個屬性,一個想默認注入,一個想自定義,只要設定了autowire,然后顯式的聲明那個想自定義的,就可以達到要求。這就應了需求,在需要特別配置的時候就提供配置,否則給我一個默認注入。
還可以在根部的<beans>節點寫一句default-autovwrie="byName",可以讓文件里的所有bean 都默認autowrie。不過有人認為開發期可以這樣,但Production Server上不應該使用Autowire。但有人認為那些自定義一次的地方比如TranscationManager應該詳細定義,而Dao,Service這種大量重復定義的bean就可以這樣做。
前 言 http://www.365key.com/gluttony/%E5%B7%A5%E4%BD%9C%E6%B5%81/
本文沒有拋出可運行的范例,僅僅是程序片斷而已,不過在 OSWorkflow 的 Wiki 上,Quake Wang 已把官方入門教程完整地翻譯成中文了,有興趣的讀者可去閱讀。關于 OSWorkflow 更加細節性的內容,可參考官方手冊,相信你在了解了入門教程后,可輕松閱讀官方手冊。
OSWorkflow 概念
在商用和開源世界里,OSWorkflow 都不同于這些已有的工作流系統。最大不同在于 OSWorkflow 有著非常優秀的靈活性。在開始接觸 OSWorkflow 時可能較難掌握(有人說不適合工作流新手入門),比如,OSWorkflow 不要求圖形化工具來開發工作流,而推薦手工編寫 xml 格式的工作流程描述符。它能為應用程序開發者提供集成,也能與現有的代碼和數據庫進行集成。這一切似乎給正在尋找快速“即插即用”工作流解決方案的人制造了麻煩,但研究發現,那些“即插即用”方案也不能在一個成熟的應用程序中提供足夠的靈活性來實現所有需求。
OSWorkflow 優勢
OSWorkflow 給你絕對的靈活性。OSWorkflow 被認為是一種“低級別”工作流實現。與其他工作流系統能用圖標表現“loops(回路)”和“conditions(條件)”相比,OSWorkflow 只是手工“編碼(coded)”來實現的。但這并不能說實際的代碼是需要完全手工編碼的,腳本語言能勝任這種情形。OSWorkflow 不希望一個非技術用戶修改工作流程,雖然一些其他工作流系統提供了簡單的 GUI 用于工作流編輯,但像這樣改變工作流,通常會破壞這些應用。所以,進行工作流調整的最佳人選是開發人員,他們知道該怎么改變。不過,在最新的版本中,OSWorkflow 也提供了 GUI 設計器來協助工作流的編輯。
OSWorkflow 基于有限狀態機概念。每個 state 由 step ID 和 status 聯合表現(可簡單理解為 step 及其 status 表示有限狀態機的 state)。一個 state 到另一 state 的 transition 依賴于 action 的發生,在工作流生命期內有至少一個或多個活動的 state。這些簡單概念展現了 OSWorkflow 引擎的核心思想,并允許一個簡單 XML 文件解釋工作流業務流程。
OSWorkflow 核心概念
step(步驟)
一個 step 是工作流所處的位置。可能從一個 step 流轉到另外一個 step(或者有時候還是停留在一樣的 step)。舉例來說,一個 OA 系統的請假流程,它的 step 名稱可能有“本部門審批階段”,“辦公室審批階段”,“總經理審批階段”等。
status(狀態)
工作流 status 是一個用來描述工作流程中具體步驟狀態的字符串。OSWorkflow 的有 Underway(進行中)、Queued(等候處理中)、Finished(完成)三種 status。
action(動作)
action 指定了可能發生在 step 內的轉變,會導致 step 的變更。在 OA 系統中,“本部門審批階段”可能有“拒絕”或“批準”兩個 action。action 和 step 之間的關系是,step 說明“在哪里”,action 說明“可以去哪里”。 一個 action 典型地由兩部分組成:可以執行此動作的 condition(條件),以及執行此動作的 result(結果)。
condition(條件)
類似于邏輯判斷,可包含“AND”和“OR”邏輯。比如一個請假流程中的“本部門審批階段”,該階段利用“AND”邏輯,判斷流程狀態是否為等候處理中,以及審批者是否為本部門主管。
result(結果)
Result 代表指向新的 step 及其 step status,也可能進入 split 或者 join。Result 分為兩種, contidional-result (有條件結果),只有條件為真時才使用該結果,和 unconditional-result(無條件結果),當條件不滿足或沒有條件時使用該結果。
split/join(分離/連接)
流程的切分和融合。很簡單的概念,split 提供多個 result;join 則判斷多個 current step 的狀態,提供一個 result。
OSWorkflow 包用途分析及代碼片斷
com.opensymphony.workflow
該包為整個 OSWorkflow 引擎提供核心接口。例如 com.opensymphony.workflow.Workflow 接口,可以說,實際開發中的大部分工作都是圍繞該接口展開的,該接口有 BasicWorkflow、EJBWorkflow、OfbizWorkflow 三個實現類。
com.opensymphony.workflow.basic
該包有兩個類,BasicWorkflow 與 BasicWorkflowContext。BasicWorkflow 不支持事務,盡管依賴持久實現,事務也不能包裹它。BasicWorkflowContext 在實際開發中很少使用。
public void setWorkflow(int userId) { Workflow workflow = new BasicWorkflow(Integer.toString(userId)); } |
com.opensymphony.workflow.config
該包有一個接口和兩個該接口的實現類。在 OSWorkflow 2.7 以前,狀態由多個地方的靜態字段維護,這種方式很方便,但是有很多缺陷和約束。最主要的缺點是無法通過不同配置運行多個 OSWorkflow 實例。實現類 DefaultConfiguration 用于一般的配置文件載入。而 SpringConfiguration 則是讓 Spring 容器管理配置信息。
public void setConfiguration(SpringConfiguration configuration) { SpringConfiguration configuration = configuration; workflow.setConfiguration(configuration); } |
com.opensymphony.workflow.ejb
該包有兩個接口 WorkflowHome 和 WorkflowRemote。該包的若干類中,最重要的是 EJBWorkflow,該類和 BasicWorkflow 的作用一樣,是 OSWorkflow 的核心,并利用 EJB 容器管理事務,也作為工作流 session bean 的包裝器。
com.opensymphony.workflow.loader
該包有若干類,用得最多的是 XxxxDescriptor,如果在工作流引擎運行時需要了解指定的動作、步驟的狀態、名字,等信息時,這些描述符會起到很大作用。
public String findNameByStepId(int stepId,String wfName) { WorkflowDescriptor wd = workflow.getWorkflowDescriptor(wfName); StepDescriptor stepDes = wd.getStep(stepId); return stepDes.getName(); } |
com.opensymphony.workflow.ofbiz
OfbizWorkflow 和 BasicWorkflow 在很多方面非常相似,除了需要調用 ofbiz 的 TransactionUtil 來包裝事務。
com.opensymphony.workflow.query
該包主要為查詢而設計,但不是所有的工作流存儲都支持查詢。通常,Hibernate 和 JDBC 都支持,而內存工作流存儲不支持。值得注意的是 Hibernate 存儲不支持混合型查詢(例如,一個查詢同時包含了 history step 上下文和 current step 上下文)。執行一個查詢,需要創建 WorkflowExpressionQuery 實例,接著調用 Workflow 對象的 query 方法來得到最終查詢結果。
public List queryDepAdmin(int userId,int type) { //構造表達式 for (int i = 0; i < arr.length; i++) { //查詢未完成流編號 |
com.opensymphony.workflow.soap
OSWorkflow 通過 SOAP 來支持遠端調用。這種調用借助 WebMethods 實現。
com.opensymphony.workflow.spi
該包可以說是 OSWorkflow 與持久層打交道的途徑,如當前工作流的實體,其中包括:EJB、Hibernate、JDBC、Memory、Ofbiz、OJB、Prevayler。
HibernateWorkflowEntry hwfe = (HibernateWorkflowEntry) getHibernateTemplate() .find("from HibernateWorkflowEntry where Id=" + wfIdList.get(i)).get(0); |
com.opensymphony.workflow.util
該包是 OSWorkflow 的工具包,包括了對 BeanShell、BSF、EJB Local、EJB Remote、JNDI 的支持。
小 結
由于本人所在公司希望在 OA 系統中引入工作流引擎,經過分析決定采用 OSWorkflow 引擎。利用 OSWorkflow,已經在系統中實現了請假條流程原型,該流程結合 OA 系統中已有的 RBAC 模型進行逐級審核。我個人認為要用 OSWorkflow 讓某個流程跑起來似乎很麻煩,主要是需要擴展和自己實現的太多。
另外,引用一段 Quake Wang 的原話:電子政務/OA 如果要使用workflow engine的話,shark,jbpm 之類的workflow engine有點殺雞用牛刀的味道。shark 和 jbpm 都強迫你使用它的用戶模型,怎樣把企業現有的用戶模型(包括組織結構)映射過來是很繁瑣的事情,比如常見的 OA 應用中,申請者對應的部門負責人為下一個流程的人工參與者,使用 shark 或者 jbpm 都得繞一圈,通過現有的人力資源系統,獲得用戶,再對應過來。這還僅僅是一個簡單的需求,更不用說國內企業千奇百怪的組織結構,以及各種特殊流程,用 wfmc 或者其他所謂的 workflow 通用標準去做不怎么標準的事情。吃力不討好。用 osworkflow 這種基于狀態機的 workflow engine 反而會輕松很多,而且它也沒有強迫你使用它的用戶模型。另外糾正一點:osworkflow 不僅僅支持簡單的 BeanShell,還支持 java class,bsf,ejb。如果做電子政務/OA 的話,覺得目前 osworkflow 是最適用的 opensource workflow engine。
(申明:本文來源于網絡,摘錄于此,僅為日后方便查看)
http://www.netbei.com/Article/jsp/Tapestry/Index.html
Tapestry是一個開源的基于servlet的應用程序框架,它使用組件對象模型來創建動態的,交互的web應用。一個組件就是任意一個帶有jwcid屬性的html標記。其中jwc的意思是Java Web Component。Tapestry使得java代碼與html完全分離,利用這個框架開發大型應用變得輕而易舉。并且開發的應用很容易維護和升級。Tapestry支持本地化,其錯誤報告也很詳細。Tapestry主要利用javabean和xml技術進行開發。
第一個應用程序
在介紹第一個應用之前,先介紹一下Tapestry的安裝。從sourceforge下載其最新版,解壓后,將lib目錄下的jar文件放到CLASSPATH中,將其中的war文件放到tomcat的webapp目錄下。然后就可以通過http://localhost:8080/tutorial訪問其tutorial應用。
在Tapestry中一個應用程序有以下幾部分組成,我們以其自身帶的HelloWorld程序為例介紹:
Servlet:
這是一個應用的主體部分:servlet類,這個類必須是ApplicationServlet的子類,并且必須實現getApplicationSpecificationPath()方法。示例如下:
import com.primix.tapestry.*;
public class HelloWorldServlet extends ApplicationServlet
{
protected String getApplicationSpecificationPath()
{
return "/tutorial/hello/HelloWorld.application";
}
}
/tutorial/hello/HelloWorld.application是一個應用的說明文件。
Application Specification:
其實就是描述這個應用的一個xml文件,在這個應用中有許多參數需要設置,engine-class將在下面介紹,page中的name屬性指定html文件名,specification-path指定對這個頁面的說明文件。在一個應用中可以有很多個page,但必須有一個page的name為"Home",因為當訪問你的應用時,首先顯示的就是這個page。
<?xml version="1.0" encoding="UTF-8"?>;
<!DOCTYPE application PUBLIC "-//Howard Ship//Tapestry Specification 1.1//EN" "http://tapestry.sf.net/dtd/Tapestry_1_1.dtd">;
<application name="Hello World Tutorial" engine-class="com.primix.tapestry.engine.SimpleEngine">;
<page name="Home" specification-path="/tutorial/hello/Home.jwc"/>;
</application>;
Application Engine:
當客戶連接到Tapestry應用時,Tapestry將會創建一個Engine對象(類似于session)。通常我們程序中的application engine 一般是SimpleEngine類的一個實例,當然這個類的子類也可以。
Page Specification:
跟應用說明相似,頁說明也是一個xml描述文件:
<?xml version="1.0" encoding="UTF-8"?>;
<!DOCTYPE specification PUBLIC "-//Howard Ship//Tapestry Specification 1.1//EN" "http://tapestry.sf.net/dtd/Tapestry_1_1.dtd">;
<specification class="com.primix.tapestry.BasePage"/>;
因為這個應用是靜態的,所以使用com.primix.tapestry.BasePage即可,如果是動態的應用,則需在這個文件中定義一些component,當然使用BasePage為基類的派生類也可以。
html頁面:
這個應用的html頁面非常簡單:
<html>;
<head>;
<title>;Hello World</title>;
</head>;
<body>;
<b>;HelloWorld</b>;
</body>;
</html>;
注意上面所講到的各種文件都要放到放在WAR的WEB-INF/classes目錄下。
一個復雜的應用
在這個應用中我們以一個簡單的學生管理系統為例介紹一下Tapestry的常用功能。我們要實現學生的增加和顯示,因此我們需要兩個html頁面。至于StudentServlet類和Student.application我們就不描述了,在Student.application中定義了兩個page:Home和EditStudent,具體看附件。學生數據存放在數據庫中,我們用Student類表示數據中的一條記錄,用StudentFactory類檢索學生數據,這兩個類用到了一個JDBC包裝器,關于這個JDBC包裝器可以見我的另外一篇文章<<對一個簡單的 JDBC 包裝器的擴展及應用>;>;。
首先看一下Home.html
<html>;
<head>;
<title>;學生管理</title>;
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">;
</head>;
<body bgcolor="#FFFFFF">;
<p align="center">;學生列表</p>;
<table width="100%" border="1">;
<tr>;
<td >;學號</td>;
<td >;姓名</td>;
<td >;性別</td>;
<td >;班級</td>;
</tr>;
<span jwcid="liststudent">;
<tr>;
<td>;<span jwcid="id">;20012400</span>;</td>;
<td>;<span jwcid="sname">;宗鋒</span>;</td>;
<td>;<span jwcid="gender">;男</span>;</td>;
<td>;<span jwcid="department">;計算機研一</span>;</td>;
</tr>;
</span>;
<tr jwcid="$remove$">;
<td>;20011389</td>;
<td>;桑一珊</td>;
<td>;男</td>;
<td>;計算機研一</td>;
</tr>;
</table>;
<a jwcid="add">;添加學生</a>;
</body>;
</html>;
與前面的簡單應用不同,我們在這個頁面中定義了七個組件,下面看一下部分Home.jwc文件,我們將詳細講述一下怎樣描述這些組件。
<specification class="test.ListStudent">;
<component id="liststudent" type="Foreach">;
<binding name="source" property-path="student"/>;
<binding name="value" property-path="eachstudent"/>;
</component>;
<component id="id" type="Insert">;
<binding name="value" property-path="eachstudent.id"/>;
</component>;
<component id="add" type="Page">;
<static-binding name="page">;EditStudent</static-binding>;
</component>;
</specification>;
在這里,我們的specification的class屬性值不再是BasePage,而是其派生類ListStudent。對于每一個組件,id屬性指定唯一的標識符,這個值與html文件中的jwcid值相對應,type 指定組件名,binding指定組件怎得到數據,property-path是一系列屬性的集合,這些屬性一般定義在javabean中,例如上面的property-path="student",則在相應的javabean類ListStudent中應該有個函數getStudent。liststudent是一個Foreach組件,這個組件其實是一個for循環,它從source中讀入一個數組,將其一個一個的賦值給value參數指定的屬性。id,name,gender,department四個是Insert組件,這個組件用來插入文本數據,參數value指定要插入的值,property-path指定怎樣獲取這些值,eachstudent.id相當于調用javabean的getEachstudent().getId()。add是一個Page組件,page屬性指定頁面名(定義在application文件中),static-binding表明要綁定的數據是不可修改的。$remove$組件沒有在這個文件中描述,因為Tapestry運行時會自動刪除這種組件。
下面看一下ListStudent類:
package test;
import com.primix.tapestry.*;
import sun.jdbc.odbc.JdbcOdbcDriver ;
/**
* 返回每個學生的數據
*
*/
public class ListStudent extends BasePage
{
private Student eachstudent;
private Student[] student;
public void detach()
{
eachstudent=null;
student=null;
super.detach();
}
public Student getEachstudent()
{
return eachstudent;
}
public void setEachstudent(Student value)
{
eachstudent = value;
}
public Student[] getStudent()
{
try{
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
student=StudentFactory.findAllStudents();
}catch(Exception e){
e.printStackTrace();
}
return student;
}
}
這個類有四個函數,其中detach函數是將頁面放入緩沖池時執行的操作,getStudent函數返回所有的學生記錄,這是給jwc文件中liststudent組件的source參數賦值,getEachstudent給這個組件的value參數賦值,因為source是一個數組,每次循環需要從中取出一條記錄賦值給eachstudent,所以還有一個函數為setEachstudent,你會注意到這個函數很簡單,其實是Tapestry幫你做了大部分工作。
至此,顯示學生的部分已經完成,下面看一下EditStudent.html
<html>;
<head>;
<title>;增加學生</title>;
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">;
</head>;
<body>;
<p>;<img src="student.gif" width="32" height="32"/>; 學生管理系統</p>;
<form jwcid="form">;
<span jwcid="ifError">;
<font size=+2 color=red>;<span jwcid="insertError"/>;</font>;
</span>;
<p>;學號:
<input jwcid="id"/>;
</p>;
<p>;姓名:
<input jwcid="name"/>;
</p>;
<span jwcid="gender">;
<p>;性別:
<input jwcid="male"/>;
男
<input jwcid="female"/>;
女
</p>;
</span>;
<p>;班級:
<input jwcid="department"/>;
</p>;
<p>;
<input type="submit" value="確定">;
</p>;
</form>;
</body>;
</html>;
在這個文件中,用到了另外一些常用的組件,先看一下EditStudent.jwc中的這些組件的描述:
<specification class="test.EditStudent">;
<component id="form" type="Form">;
<binding name="listener" property-path="listeners.formSubmit"/>;
</component>;
<component id="gender" type="RadioGroup">;
<binding name="selected" property-path="gender"/>;
</component>;
<component id="ifError" type="Conditional">;
<binding name="condition" property-path="error"/>;
</component>;
<component id="insertError" type="Insert">;
<binding name="value" property-path="error"/>;
</component>;
<component id="id" type="TextField">;
<binding name="value" property-path="id"/>;
</component>;
<component id="male" type="Radio">;
<field-binding name="value" field-name="test.EditStudent.MALE"/>;
</component>;
</specification>;
form是一個Form組件,它的參數listener指定submit這個form時有那個函數處理。ifError是一個Conditional組件,這個組件指定當condition滿足時才會顯示,在本例中,如果error不為空,則condition滿足。在這個組件中,有嵌套了一個Insert類型的組件,用于將錯誤顯示。這是Tapestry中經常用到的處理錯誤的方式。gender是一個RadioGroup組件,它綁定了javabean中的gender屬性,selected參數指定那個radio被選中,在這個組件中,又嵌套了兩個Radio組件,分別用來表示男,女。Radio的value參數指定當用戶選定這個radio時,RadioGroup綁定的屬性值將會等于field-name中指定的值(這個值必須是static的),在本例中,gender=test.EditStudent.MALE。id是一個TextField組件,其參數value綁定到javabean中的id屬性。
下面是相應的EditStudent類:
package test;
import com.primix.tapestry.*;
public class EditStudent extends BasePage
{
public static final int MALE = 1;
public static final int FEMALE = 2;
private int gender;
private String error;
private String id;
private String sname;
private String department;
public void detach()
{
error = null;
id=null;
sname=null;
gender=0;
department=null;
super.detach();
}
public int getGender()
{
return gender;
}
public String getId()
{
return id;
}
public String getSname()
{
return sname;
}
public String getDepartment()
{
return department;
}
public void setGender(int value)
{
gender = value;
fireObservedChange("gender", value);
}
public void setId(String value)
{
id = value;
fireObservedChange("id", value);
}
public String getError()
{
return error;
}
public void setSname(String value)
{
sname = value;
fireObservedChange("sname", value);
}
public void setDepartment(String value)
{
department = value;
fireObservedChange("department", value);
}
public void formSubmit(IRequestCycle cycle)
{
//判斷用戶是否添完了所有數據
if (gender== 0||id==null||id.equals("")||sname==null||sname.equals("")||
department==null||department.equals(""))
{
error = "請填充完所有選項";
return;
}
//將學生保存
try{
Student student=new Student();
student.setId(id);
student.setName(sname);
if(gender==1)
student.setGender("男");
else
student.setGender("女");
student.setDepartment(department);
student.save(null);
}catch(Exception e){
e.printStackTrace();
}
//清空當前的各個屬性,以免再次進入此頁面時,各屬性仍舊保留原來的值
setSname(null);
setDepartment(null);
setId(null);
setGender(0);
//重定向到Home頁面
cycle.setPage("Home");
}
}
在本類的一些設置屬性的函數中使用了fireObservedChange這個函數,這個函數激發一個改變事件,通知當前的屬性的值已經改變。
其他應用
Tapestry中自帶的例子中的Workbench中的localization例子演示了怎樣使用本地化,你只需要創建不同語言的html模板,還有圖形等其它一些html中用到的資源。例如創建一個法語版的EditStudent.html,則相應的html文件名為EditStudent_fr.html,而jwc中定義的組件的描述不用有多個版本。這里要介紹一下Tapestry本地化中經常用到的一個概念:assets。assets是一些web應用中用到的資源,如圖象,視頻。assets有三種:external, internal 和private。External類型的assets來源于任意的URL。Internal類型的assets來源于和Tapestry應用在同一個服務器上的URL。Private 類型的assets允許部署在WAR的WEB-INF/classes目錄下(同上面的html模板,jwc文件一樣),這個目錄對于web服務器來說是不可見的。
看一下Workbench中localization例子中的localization.jwc文件的片斷:
<component id="changeButton" type="ImageSubmit">;
<binding name="image" property-path="assets.change-button"/>;
</component>;
<private-asset name="change-button" resource-path="/tutorial/workbench/localization/Change.gif"/>;
在changeButton組件中就使用了private assets,而這些圖像文件就放在WAR的WEB-INF/classes下,注意圖像跟html一樣也有多個語言的版本。
注意jwc文件中的inputLocale這個組件,其實localization應用就是通過這個組件來實現本地化。具體參數請看其Developer guide。
<component id="inputLocale" type="PropertySelection">;
<binding name="value" property-path="page.engine.locale"/>;
<binding name="model" property-path="localeModel"/>;
</component>;
Tapestry還支持創建自己的可重用組件,其自身帶了一個這樣的例子:Border。同時它還有其它一些例子:Inspector展示了怎樣監視你的應用程序。vlib是一個用tapestry作表示層的j2ee應用程序(用jboss作為應用服務器)。
Tapestry的功能非常強大,本文只是介紹了其一小部分,還有很多方面沒有涉及到,例如javascript在Tapestry中的應用。具體可以看其文檔,相信如果你用一下這個框架,你就會被它深深吸引。Tapestry的文檔做的不是很全,不過經過不斷的摸索,相信你會很快掌握它。
http://wiki.opensymphony.com/display/WF/Tutorial+-+Chinese
使用java.exe 的-Xmx 參數來設定最大的heap size. 所以啟動時的命令可以如下
java -Xmx512m 如果用eclipse.exe 啟動也是可以下達參數
eclipse.exe -vmargs -Xmx512M
public String toString()
public boolean equals(Object object)
public int hashCode()
some of them are used by hibernate.
Eclipse 3.0.1 + Commonclipse 1.2 can work together well.
Date 約會
Bunch 花束
Rose 玫瑰
Candy 糖果
Chocolate 巧克力
Forget-Me-Not 勿忘我
Puppy Love/First Love 初戀
Cute Meet 浪漫的邂逅
Fall In Love 墜入愛河
Love At The First Sight 一見鐘情
Propose 求婚
Valentine Cards 情人節卡片
Candlelight Dinner 燭光晚餐
Heart-Shaped/Cordate 心形的
Truelove 真愛
Enamored 傾心的
Saint Valentine\'s Day 情人節
The Chemical Feeling 奇妙的感覺,觸電
Sweet Bitterness 甜蜜的痛苦
A Doomed Couple 天生一對
A Happy Ending 大團圓結局
Sweetheart 甜心
Lover 愛人
Cupid 愛神丘比特
Admirer 仰慕者
Romance 浪漫
Heartthrob 激情
Courtship 求愛
Infatuation 醉心
Promise/Pledge/Vow 誓言
Fidelity 忠心
Eternal/Immortal/Everlasting 永恒
實現兩個Web下拉選擇框關聯
比如要實現國家Country與城市City的關聯:
動態javascript方法實現如下:
<!-- 引入js文件-->
<script src="/scripts/xselect.js"></script>
<script language="javascript">
<!--
var dsy = new Dsy();
//countryID是父select控件名稱, cityID是子select控件名稱.
var sel = ["countryID","cityID"];
//定義父與子兩個select控件的默認值
var def = ['<c:out value="${storeForm.countryID}" />','<c:out value="${storeForm.cityID}" />'];
//父select控件內容的定義
dsy.add("0",[['-------','0']
<logic:iterate name="CountryList" id="country">
,['<bean:write name="country" property="label"/>','<bean:write name="country" property="value"/>']
</logic:iterate>
]);
//下面定義子select控件的內容
dsy.add("0_0",[['------','0']]);
<logic:iterate name="CountryList" id="country" indexId="index">
dsy.add('0_<%=index.intValue()+1%>',[['------','0']
<logic:iterate name="Citys" id="city">
<bean:define id="c" name="city" property="countryID" />
<bean:define id="c2" name="country" property="value" />
//由于city.countryID是long類型,而country.value是String類型,所以把long類型轉換為String類型
<%
String str = c + "";
%>
//遍歷所有的City List, 如果city的countryID與country id一致,就加入select控件
<logic:equal name="country" property="value" value="<%=str%>">
,['<bean:write name="city" property="name"/>','<c:out value="${city.id}" />']
</logic:equal>
</logic:iterate>]);
</logic:iterate>
attachSelect(dsy,sel,def);
// -->
</script>
//注意,上述代碼寫到html form里面