亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

(IBM)Struts2、Spring、Hibernate 高效開發的最

系統 1577 0

引言

SSH(Struts2+Spring+Hibernate)是最為 Java 業界熟知的 Java EE Web 組件層的開發技術。很多人提起 Java EE,甚至都會將其誤認為就是 SSH。無論是書籍還是電子教程,大部分都已經千篇一律,講解各種標簽、配置的用法。許多人包括筆者在內,第一次使用 SSH 的時候,按照教程的介紹進行開發。繁瑣的配置,重復的修改配置,不斷定義的參數轉換器,真的讓筆者苦不堪言。本文對 SSH 的開發模式嘗試了重新定義,按照規約優于配置的原則,利用 Java 反射、注解等技術,設計了新的一套 SSH 開發框架,應用該框架,可以大大提高開發效率,筆者多次將該開發框架應用在各種小型 SSH Web 應用系統之中,屢試不爽。

閱讀文章之前,讀者需要對 SSH 的結合開發有一些了解,最好是有實踐的經驗,特別是對 Struts2 需要較為了解,掌握 Struts2 自定義攔截器、自定義驗證器等的開發。另外,讀者還需要掌握一些前提技術,包括 Java 反射、Java 注解、理解事務隔離級別等。

文章首先進行框架的總體介紹,然后分點介紹各個部分的詳細設計。另外,文章還將列舉該框架中采用的技術特點及其相應目的,希望讀者可以從中獲益。


框架總體介紹

文章之所以說框架是通用的,因為它的思想適應任何的業務需求。按照文章介紹,按照介紹的框架搭建完代碼架構后,可以屏蔽許多技術細節,讓開發人員專注于業務邏輯的實現,這些繁瑣的技術細節包括技術配置、權限控制、頁面跳轉、錯誤處理等等。框架大致的風格如圖 1 所示,總體來說,該框架遵守了“規約優于配置”的原則。


圖 1. 框架大致風格( 查看大圖
(IBM)Struts2、Spring、Hibernate 高效開發的最佳實踐

上圖中,系統只有一個 action 配置。每個業務操作,不再對應一個 ActionSupport 子類,而是對應一個 ActionSupport 子類的類方法,利用 Struts2 的動態方法特性,使得業務方法擺脫了繁瑣的配置,方便的增加和刪除。全面的 result 配置,解決了各種頁面跳轉的問題。Action 方法的起名,遵守了權限與業務模型規約,讓模型選擇與權限控制交給框架來實現,同時訪問的操作名就是【方法名】 .action。下面,將一一對框架的各部分進行講解。


Struts2 的不動配置

該框架中,我們建議只定義少量的類繼承于 ActionSupport,這樣可以使得 struts.xml 的配置盡量減少,甚至只進行少量配置,而不用隨著業務的增加而修改配置。清單 1 是筆者為一個教師考勤系統定義的 Action 配置。


清單 1. Struts2 的配置清單
     <action name="*" method="{1}" class="Main"> 
     <interceptor-ref name="fileUpload"> 
         <param name="maximumSize">4073741824</param> 
     </interceptor-ref> 
     <interceptor-ref name="myInterceptorStack"></interceptor-ref> 
     <result name="input">/noDir/error.jsp</result> 
     <result type="json" name="success"></result> 
     <result name="errorJson" type="json"></result> 
     <result type="json" name="error"></result> 
     <result type="stream" name="stream"> 
         <param name="contentType">${contentType}</param> 
         <param name="contentDisposition">fileName="${inputFileName}"</param> 
         <param name="inputName">inputStream</param>  
     </result> 
     <result name="dynamic">/${url}</result> 
     <result name="otherAction" type="redirectAction">/${url}</result> 
     <result name="red" type="redirect">/${url}</result> 
 </action>
  


清單 1 定義了很多規則。首先,該配置使用了動態方法調用技術,這可以使得許多的 Action 方法可以聲明到一個類里,不用重復定義 Action 類,同時對業務的增加和刪除可以簡約到對 Action 類里方法增加和刪除,增加的 Action 方法不需進行其他配置,如果業務被刪除,則只需要將方法注釋或者刪除,非常方便。第二,配置的 package 繼承于 json-default,也就是說這個包里的 action 是支持 Ajax 調用的,默認的,如果返回 ERROR、SUCCESS,則會將 Action 序列化為 JSON 返回到客戶端。我們定義了各種的跳轉類型,包括重定向到頁面(具體的頁面由 Action 里的 url 指定)、重定向到 Action、重定向到錯誤頁面、流類型的返回等等,這為我們動態的選擇返回結果數據提供了方便。那么使用上述的配置,對我們開發有什么好處呢?假設有一個新的業務,我們只需要在 Action 添加新的方法,如清單 2 所示。


清單 2. 添加新業務方法
    public String business() throws Exception
	{
		…business process…

		if (has error)
		{
			addFieldError(“error message”) return INPUT;
		} else {
			//url是action中定義的一個String變量,指定跳轉地址
			url = “business.jsp”; return “dynamic”;
		} 
	}


  


調用這個新的業務方法,只需要調用這個鏈接:http://{host}:{port}/{webapp}/business.action。正如我們看到的,定義了新的業務邏輯方法,我們沒有修改或添加任何配置,因為我們的配置是完整的,考慮到了各種跳轉、錯誤情況,同時動態方法調用特性,讓我們可以動態的指定業務方法。如果我們對清單 2 中的跳轉代碼進行抽取,清單 2 會更加簡單。如清單 3 所示。


清單 3. 抽取基礎方法后的業務方法
    public String business() throws Exception
{
		…business process…

		if (has error)
		{
			return redirectToErrorPage("error message")
		} else {
			return redirectToPage("business.jsp");
		}
}


  


上面的清單中,我們抽取了 redirectToErrorPage 和 redirectToPage 方法,這樣就可以使得其他的業務方法可以重用這些跳轉方法,整個業務過程變得清晰易懂。類似的我們還可以抽取出 redirectToAction(跳轉到另一個業務方法)、redirectStream(流類型的跳轉)、redirectToAnotherPage(用于重定向的跳轉)、redirectToJson(Ajax 的跳轉)等等。這樣這些公共方法就可以讓其他的開發人員一起使用。程序員可以從跳轉、錯誤提示、重復配置 Action 的痛苦中解救出來,專注于編寫業務邏輯。


ModelDriven 的規約

有了上面的配置,我們還不能做到完全脫離配置。比如,我們定義了一個 Action 類繼承于 ActionSupport,我們知道使用 ModelDriven 可以將用戶上傳的數據封裝到一個業務 Bean 里,而不用直接在 Action 里聲明變量,這很重要。我相信有很多讀者遇到過這個問題。當業務 Bean 不同時,也就是需要用戶上傳的數據不同時,我們就要隨之添加新的 Action,這直接導致修改 struts.xml 的配置,然后還要修改 applicationContext.xml 的事務配置、Bean 的配置,哪天我們不要這個業務了,又要重復的修改刪除配置,筆者開始時為此事近乎抓狂,為什么我們不能只定義一個 Action,而 ModelDriven 的模型動態改變呢?

仔細考慮 Struts2 的機制,Struts2 將客戶端的參數裝配到 ModelDriven 的模型里,是通過“裝配攔截器”裝配的。只要我們在裝配攔截器執行前,改變 ModelDriven 里的模型對象就行了。這就需要我們自定義一個攔截器,struts2 提供了這個機制。在自定義的攔截器里,我們根據用戶調用的 Action 方法,新建一個模型,并且將模型設置到 Action 中,這樣模型就可以是動態的了,記住,這個攔截器需要放在 defaultStack 的前面。

同樣,新的問題是如何根據 Action 方法動態的選擇業務模型呢?難道重復的寫 if 方法嗎?當然不能這樣,動態的模型,就應該來自于動態的方法。因此定義的 action 方法需要有規約,筆者在自己的程序中,是這樣定義規約的。Action 方法是這樣組成:_$_,使用美元符隔開(美元符是 Java 方法合法的標識符),前部分是操作名,可以任意取,后部分是業務模型的類名。同時,所有的業務模型,都放到指定的一個包里,假設該包名為 com.dw.business。那么在自定義的攔截里,我們獲得用戶調用的 Action 方法名,按美元符隔開獲得后半部分的類名,指定的包名(這里是 com.dw.business)+ 類名就是業務模型類的全路徑,使用 Java 反射機制動態生成一個空的業務模型對象(所以,業務模型類必須有一個無參的構造函數),設置到 Action 里,再交給裝配器的時候,裝配器會自動組裝這個模型。該攔截器的核心代碼如清單 4 所示。


清單 4. 攔截器清單
     public String intercept(ActionInvocation ai) throws Exception {
		ai.addPreResultListener(this);
	Main action = (Main)ai.getAction();
	//業務方法名
	String name = ai.getInvocationContext().getName();
	int lastIndex = name.lastIndexOf("{1}quot;);
	if (lastIndex != -1)
	{
	  try {
		String head = "com.dw.business.";
		String className = name.substring(lastIndex+1, name.length());
		//關鍵:動態設置業務模型
		action.setModel(Class.forName(head).newInstance());
	    } catch (Exception e) {}
	}
	return ai.invoke();
}


  


有了上面的配置,基本可以做到屏蔽大多數技術細節開發了,但是我們還有一個問題,當在業務方法中,意外拋出了異常,struts2 默認的是返回 INPUT,按照 清單 1 的配置,發生錯誤將跳轉到 noDir/error.jsp 頁面,顯示錯誤信息,這適合在非 Ajax 的處理。但是有時候我們希望他返回錯誤是 JSON 類型,因為 Action 的一些方法是 Ajax 的調用方式,也就是 Action 方法的執行結果需要返回 errorJson。我的解決方法是利用 Java 注解技術,定義一個新的注解,名為 IfErrorReturnToJson,它的代碼如清單 5 所示。


清單 5. IfErrorReturnToJson 的代碼
     @Target(ElementType.METHOD) 
 @Retention(RetentionPolicy.RUNTIME) 
 public @interface IfErrorReturnToJson { 

 } 

  


該注解作用在方法上,也就是 Action 的業務方法,如果我們希望某業務方法在發送錯誤時,就返回 JSON 類型,那么我們只需要在該方法上加上這個注解。現在,我們如何動態的修改返回值呢。 清單 2 的第二行,為 ActionInvocation 添加了 PreResultListener,這個監聽器是在返回結果前進行一些處理,正符合我們的需求。我們為自定義攔截器類實現了 PreResultListener 接口,實現了接口方法,如清單 6 所示。


清單 6. PreResultListener 的代碼
    public void beforeResult(ActionInvocation ai, String result) {
		
	if (Main.INPUT.equals(result) || Main.ERROR.equals(result))
	{
		try {
			String methodName = ai.getInvocationContext().getName();
			Method method = Main.class.getMethod(methodName);
			if (method != null && method.getAnnotation(
			        IfErrorReturnToJson.class) != null)
			{
					ai.setResultCode(Main.ERROR_JSON);
			}
		} catch (Exception e) {
		}
	}
} 

  


可以看到,我們在返回結果前,如果當前的返回結果是 INPUT 或者 ERROR,我們會使用反射機制,檢查該方法是否加了 IfErrorReturnToJson 的注解,如果加了注解,則調用 ai.setResultCode(Main.ERROR_JSON); 方法,修改返回值,使得結果為 JSON 數據類型。


事務隔離級別的規約

在 SSH 開發中,需要重點考慮的是 Spring 的事務配置。根據不同的業務,定義的事務隔離級別就不同,比如對隔離級別要求高的,就要用到 Spring 的序列化讀的隔離配置;有一些方法只是為了權限控制,用于頁面跳轉,則不需要用到事務控制;一些操作目的是搜索,那么該事務就是只讀的。精細的事務配置,可以提高業務處理的代碼效率。這時候,業務方法的命名規約就可以起到隔離級別的控制作用,比如方法名是 *begin*( 方法名中包含 begin),則該方法沒有事務控制;方法名是 *search* 的,則該方法擁有只讀的事務;方法名是 *seri*,則用序列化讀事務控制,提高并發安全級別。這個事務配置清單如所示。


權限規約

在一些應用中,涉及到簡單的權限管理。讀者可能會想到一些開源的中間件,如 ralasafe 這樣的開源權限組件,雖然很全面,但是學習起來需要一定的時間,熟練掌握,并配合 SSH 開發則更需要細致的學習。當我們只是簡單的權限控制時,我們完全可以用到一些規約,來完成用戶的權限控制。在我設計的規約中,需要在數據庫中定義一張 Permission 表,代表權限 , 它與用戶表是多對一的關系,它至少有兩個字段,一個是 permissionName,一個是 permissionPrefix。permissionName 用于描述該權限,而 permissionPrefix 是我們所關心的。我們設計 Action 的方法,遵守 permissionPrefix_actionMethodName$BussinessBean 這樣的原則,permissionPrefix 前綴代表數據庫中權限表的 permissionPrefix 值 , 使用下劃線隔開。當用戶登錄后,會將該用戶所擁有的權限列表存放到 session 之中。當用戶試圖訪問一個 Action Method 時,會使用 ModelDriven 的規約 里一樣的方法,截取方法名獲得該方法允許的訪問權限,如果用戶的權限列表中包含了該方法的權限,則允許調用,否則不允許調用。這樣設計,雖然無法做到數據的訪問權限,卻可以滿足一大部門的功能權限控制。這里需要記住,權限描述可以修改,但是權限的 permissionPrefix 不能修改,如果方法名中沒有權限標識,則代表任何用戶都可以訪問。類似的,如果一個方法多個權限都可以訪問,則可以這樣設計方法 p1_p2_p3_methodName$BussinessBean,使用多個下劃線分割。


合理利用 Struts2 的傳參技術

基于 HTTP 協議的特殊性,上傳到 Web 服務器的數值都是字符串,而我們的業務模型都是對象類型,有一些還是復雜的業務對象。Struts2 提供了 Conveter 的機制,允許程序員將 String 轉換成復雜的業務對象。但是筆者剛用這個機制的時候,開始的確興奮,但是隨著業務的修改,業務模型的修改,這些 Conveter 的管理著實讓人頭疼。因此,本人認為 Conveter 技術應該盡量少用。我提出了一個新的方法,假設一個業務模型中,里面包含一個 List<People> pids 屬性對象,People 里有一個 id 屬性,我們需要客戶端上傳 People 的 id 列表,放入 List<People> pids 之中。如果使用 Conveter,我們在客戶端需要定義規則,如客戶端上傳 pids=1,2,3,4,6,8。然后服務器端使用 Conveter 執行分割字符串、新建 People 對象、設置 ID、添加到列表等一系列操作。聽著都頭暈不是嗎 ? 而且這相對并不安全,對程序員解析字符串的功底要求很高。我們感謝 Struts2 的傳參機制,如果我們這樣傳參:<input name=”pids[0].id”/><input name=”pids[1].id”/>。這兩個 input 的上傳,Struts2 會根據上傳數據的 name,自動組裝成 List<People> 對象,并且賦值給 pids,pids[0] 代表列表的第 0 個元素,這用到了 OGNL 表達式的傳參規則,它會自動識別 pids 是數組還是列表,如果 pids 默認是空,它還會自動新建一個空的數組或列表。筆者可以查看 OGNL 的相關教程。合理利用該技術,可以大大縮減傳參的難度。


合理使用 Struts2 的標簽

Struts2 提供了眾多的標簽,這些標簽大致包括了 UI 標簽、數據標簽以及邏輯標簽。這里,我們需要理解 UI 標簽與服務器端的數據交互格式,比如 checkboxlist 標簽,傳到服務器端就是一個數組,該數組存放的是選定的 checkbox 列表的數值 , 這比使用 iterator 標簽生成 checkbox 列表容易獲得數據。Doubleselect 標簽,用于生成 2 級的級聯 select,經常使用的是部門 - 用戶的級聯。Optiontransferselect 標簽,用于批量的遷移,比如用于批量的為部門分配用戶。使用 struts2 的標簽可以大大減少用戶界面的開發,以及使得用戶界面到服務器的數據傳輸方式變得非常簡單。


Action 的模型驗證

Struts2 具有一套完善的驗證機制,在 ActionSupport 類里,可以將模型驗證方法寫在 validate* 方法里。如果重寫了 ActionSupport 的 validate 方法,這個 validate 會在執行所有 Action Method 前調用,執行驗證。而自定義的 validate*(* 是方法名),比如方法名是 add,則這個方法名就是 validateAdd),它只會在執行 add 方法前執行驗證。對于數據的驗證,筆者建議使用 validater 文件驗證,它更加容易配置和修改,利用現有的驗證器,可以減少硬編碼驗證的痛苦。在上面提到的框架中,由于使用的是動態方法機制,我們需要在 Action 類所在的包里,新建 validator 的 XML 文件,名字是 { 類名 }-{ 方法名 }-validation.xml(如果不是動態的方法,則 { 類名 }-validation.xml 就足夠了)。最后的結果如圖 2 所示。


圖 2. Validator 文件配置結果
(IBM)Struts2、Spring、Hibernate 高效開發的最佳實踐

具體的配置內容,讀者可以搜索 Struts2 的 validation 框架教程。


自定義業務模型驗證器

Struts2 提供的驗證器,包括 date、required、requiredstring 等等,這些可以歸于數據驗證。而對于特定的業務模型驗證,則比較復雜,因此,在該框架中,可以自定義一個業務驗證器,這是 struts2 支持的,它負責對業務模型進行驗證,比如可以驗證用戶上傳的用戶 ID 的用戶是否存在,這可以在很大程度上保證系統的安全性。驗證器的代碼清單 7 如下面所示。


清單 7. 業務驗證器代碼
     public class BusinessValidator extends FieldValidatorSupport {

	private String property = null;
	
	public String getProperty() {
		return property;
	}
	
	public void setProperty(String property) {
		this.property = property;
	}
	
	@Override
	public void validate(Object exist) throws ValidationException {
		String fieldName = getFieldName();
		Object fieldValue = getFieldValue(fieldName, exist);
		if (fieldValue != null && fieldValue instanceof Integer && 
		((Integer)fieldValue) <= 0)
		{
			addFieldError("message", "上傳的ID,該數據是不存在!");
		} else if (fieldValue == null)
		{
			addFieldError("message", "上傳的ID,該數據是不存在!");
		} else {
			if (exist != null && exist instanceof Main && 
			((Main)exist).getModel() instanceof IChecker)
			{
				Main pa = (Main)exist;
				IChecker e = (IChecker)pa.getModel();
				boolean isRight = e.checkOk(property, pa);
				if (!isRight)
				{
					addFieldError("message", "上傳的ID,該數據是不存在!");
				} else {
					pa.getPubDao().getHibernateTemplate().clear();
				}
			}
		}
	}
} 
  


清單 7 中,用到一個 IChecker 接口,需要驗證的業務模型需要實現 IChecker 接口,在接口實現方法中實現業務驗證過程,錯誤的話返回 false。

在 src 目錄(或者 WEB-INF 下的 class 目錄),添加 validater.xml 文件,在其他自帶的驗證器后,添加業務驗證器配置,命名為 check。


清單 8. 驗證器的配置
    				 
 <validators> 
    ……
    <validator name="check" class="com.attendance.action.BusinessValidator"/> 
 </validators>
 

  


接下來就可以使用這個驗證器,在圖 2 中的 validation 文件里,添加如清單 9 的配置。


清單 9. 驗證器的使用
     <field-validator type="check" short-circuit="true"> 
 <param name="property">department</param> 
 <message> 該部門不存在 !</message> 
 </field-validator>
  


利用 JEE Eclipse 生成 Hibernate 的 JPA 模型

IBM 提供了 JEE 版的 Eclipse,專門用于開發 Java EE 的應用,它提供了從數據庫中生成符合 JPA 規范的數據模型的能力。Hibernate3 以后,支持了 JPA 規范(不是完全支持,但是已經較為全面),利用 JEE Eclipse 的生成能力,就可以避免繁瑣的 hbm 文件的配置。同時,JPA 的規范里,還可以提供 NamedQuery、OrderBy 等注解,對于復雜的數據庫,該規范可以減少開發時間。


UI 重用

Struts2 的 action 標簽,用于調用某個 action。這個標簽筆者認為非常有用,尤其體現在 UI 重用中,比如用戶管理中,在很多個界面里,都允許用戶信息修改和用戶刪除,那么我們就可以將用戶信息修改和用戶刪除的頁面代碼以及 JavaScript 放在一個 JSP 里,同時定義一個 Action 方法 ( 名為 A),為這個 JSP 執行初始化。接下來在允許進行用戶修改和刪除的界面,都用 s:action 標簽調用這個 A 方法,設置 executeResult 為 true,將用戶修改和刪除的代碼包含在頁面里。這樣就實現了 Action 的重用。如果重用的界面不需要服務器的初始化,這直接使用 jsp:include 或 s:include 引用重用的 JSP。


小結

本文通過一系列的講解,講述了如何搭建一個通用的 SSH 開發框架,陳述了其中的設計思想,由于篇幅限制,文章只介紹了框架中的重要部分和重要思想,希望讀者可以從中獲益。由于筆者水平有限,如有錯誤,請聯系我批評指正。

文章轉自: http://www.ibm.com/developerworks/cn/java/j-lo-ssh/

(IBM)Struts2、Spring、Hibernate 高效開發的最佳實踐


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 国产精品视频分类一区 | 午夜视频精品 | 精品无人区乱码一区二区三区手机 | 精品伊人久久久久7777人 | 欧美精品久久久久久久影视 | 久热re这里只有精品视频 | 国产精品九九久久一区hh | 五月中文字幕 | 国内外成人在线视频 | 在线观看免费黄色小视频 | 91精选在线观看 | 99 久久99久久精品免观看 | 日本久久99 | 伊人国产在线 | a级精品九九九大片免费看 a级毛片高清免费视频 | 天天做天天爱天天爽 | 亚洲精品久久久久综合91 | 91午夜精品亚洲一区二区三区 | 亚洲一区综合在线播放 | 久久久毛片 | 色综合狠狠操 | 性夜黄a爽爽免费视频国产 性夜影院爽黄a爽免费看网站 | 狼人综合干伊人 | 一级片免费视频 | 最新国产精品自拍 | 亚洲国产一区二区三区精品 | 国产成人一区二区三区影院免费 | 亚洲视频一区在线观看 | 一区二区成人国产精品 | 亚洲视色 | 免费一级a毛片 | 久草6| 色偷偷久久一区二区三区 | 国产在线观看自拍 | 国产高清在线91福利 | 成人国产欧美精品一区二区 | 男女拍拍视频黄的全免费 | 日韩免费观看一级毛片看看 | 国产自愉怕一区二区三区 | 国产欧美精品一区aⅴ影院 国产欧美精品一区二区 | 亚洲欧美日韩在线观看你懂的 |