- JavaEE主流開源框架
- 唐振明主編
- 6254字
- 2018-12-29 03:38:01
第1章 Struts2快速入門
Struts2是在WebWork基礎上發展起來的一個新的MVC框架,與Struts1沒有太多關系。本章將通過簡單案例幫助讀者快速理解Struts2框架的工作原理、開發部署步驟以及主要優點。
1.1 Struts2概述

從名稱上看,Struts2應該是Struts1版本的擴展和升級。實際上,Struts2和Struts1沒有太多的關系。
Struts1最初是Apache Jakarta項目的一部分,后來作為一個開源的MVC框架存在。Struts1曾經被很多Web應用采用,作為構建MVC的基礎框架使用。Struts1最大的特點是提供了JSP標記庫以及頁面導航。
Struts2是從WebWork框架上發展起來的。WebWork是一個很優秀的MVC框架,然而,由于是一個新的框架,在一段時間內并沒有被廣泛應用。后來,Struts和WebWork社區決定將二者合并,推出Struts2框架。Struts2兼具Struts1和WebWork的優點,從而得到了廣泛的使用。
為了盡快對Struts2框架有較為全面的了解,本節首先介紹Struts2的工作原理。Struts2工作原理比較復雜,圖1-1-1是官方提供的Struts2工作原理圖。
下面結合圖1-1-1展示的Struts2工作原理,對Struts2的基本工作過程進行總結:

圖1-1-1 Struts2工作原理
(1)客戶端向服務器端提交請求,容器初始化HttpServletRequest請求對象。
(2)請求對象被一系列的Servlet過濾器過濾。Struts2中的過濾器有三種,如下所述:
① ActionContextCleanUp過濾器:是一個可選的過濾器,主要用來集成其他框架。
② 其他插件的核心過濾器:如SiteMesh插件的過濾器。
③ FilterDispatcher過濾器:是Struts2 API中提供的過濾器,必須使用。
(3)FilterDispatcher過濾器調用ActionMapper,決定該請求是否需要調用某個Action。
(4)如果請求需要調用某個Action,ActionMapper將通知FilterDispatcher過濾器把請求的處理交給ActionProxy來處理。
(5)ActionProxy通過Configuration Manager解析框架的配置文件struts.xml,找到需要調用的Action類。
(6)ActionProxy將創建一個ActionInvocation實例。
(7)ActionInvocation實例使用命令模式回調Action中的execute方法,Action調用業務邏輯類完成業務邏輯。在調用Action的前后,將調用該Action涉及的相關攔截器(Interceptor)。
(8)Action執行完畢后,ActionInvocation根據struts.xml中的配置找到對應的返回結果(稱為Result)。返回結果通常是JSP、FreeMarker等模板文件。
在闡述Struts2工作原理的過程中,涌現了很多新名詞,如攔截器、返回結果等,讀者暫時不需要深入考慮,在后續章節將繼續詳細學習。
為了幫助讀者快速入門Struts2開發,下面總結Struts2應用開發過程中開發人員需要做的主要工作。
(1)Model層開發。
Struts2框架對于Model層沒有特別要求,也沒有特殊支持,Model層可以使用任何開發技術實現,如JavaSE的普通Java類(POJO)、EJB組件、WebService等。Model層的業務邏輯往往使用Action類調用。
(2)在web.xml中配置FilterDispatcher。
FilterDispatcher是Struts2中的核心控制器,在Struts2 API中已經定義。在Struts2應用中,必須通過web.xml配置FilterDispatcher過濾器,代碼如下所示:
<filter> <filter-name>FilterDispatcher</filter-name> <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class> </filter> <filter-mapping> <filter-name>FilterDispatcher</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
上述配置中將FilterDispatcher映射到/*路徑,那么客戶端對服務器端的任何路徑的請求,都將被FilterDispatcher過濾。
(3)開發Action類。
Action類是一個符合一定命名規范的JavaSE類,不是Servlet。Action實現的功能與Servlet類似,承擔調用Model、根據返回結果決定頁面導航等職責。在Struts2應用中,需要編寫大量的Action類,作為業務控制器使用。
(4)攔截器(Interceptor)的配置或自定義開發。
攔截器用來在Action類的前后執行一些通用的操作,Struts2 API中已提供了常用的攔截器,只需要進行配置即可使用。如果應用中需要自定義一些通用操作,需要自定義攔截器,并通過配置使用。
(5)開發視圖。
Struts2可以支持多種視圖技術,包括JSP、FreeMarker、Velocity。目前,使用較多的仍然是JSP技術,本教材中也采用JSP技術實現視圖。Struts2框架提供了強大的JSP標記庫,可以便捷地開發JSP頁面。
1.2 Struts2簡單實例

通過上一節的學習,讀者已經了解Struts2基本概念以及工作原理,并且對Struts2應用開發中的主要工作也有所了解。本節將構建簡單的Struts2實例,該實例實現如下邏輯:用戶在index.jsp中輸入用戶名和密碼,如果用戶名和密碼是ETC和123,則登錄成功,顯示歡迎頁面welcome.jsp;否則,登錄失敗,跳轉到index.jsp頁面。該實例不注重業務邏輯,主要目的是幫助讀者快速掌握開發Struts2應用的步驟。
(1)到Struts官方網站下載Struts的jar包(http://struts.apache.org/)。
(2)將下載到的jar包導入到Web工程中。
Struts2框架有很多jar包,某些包是和其他插件有關的。如果將全部jar包都導入到工程中,需要同時導入其他插件的jar包,否則將出現錯誤。如果不需要使用其他插件,僅導入下面5個jar包即可實現Struts2的基本功能,如圖1-1-2所示。

圖1-1-2 導入Struts2的5個核心包
(3)開發Model層業務邏輯。
導入所需要的jar包后,下面使用Java類實現Model層的登錄邏輯,代碼如下所示:
public class LoginService{ public boolean login(String custname,String pwd){ if(custname.equals("ETC")&&pwd.equals("123")){ return true; }else{ return false; }}}
(4)開發視圖文件。
完成業務邏輯后,進一步可以開發視圖文件,視圖使用JSP實現。JSP文件中可以使用Struts2框架提供的JSP標記庫,使用Struts2的標記與使用JSTL的標記步驟相同。Struts2標記庫只有一個tld文件,存在于struts2-core.jar包的META-INF目錄下,如圖1-1-3所示。

圖1-1-3 struts-tags.tld文件所在目錄
首先編寫index.jsp文件,用來輸入用戶名和密碼進行登錄,代碼如下所示:
<body> <%@taglib uri="/struts-tags" prefix="s" %> <s:form action=""> Input your custname:<s:textfield name="custname"></s:textfield><br> Input your password:<<s:password name="pwd"></s:password><br> <s:submit value="Login"></s:submit> </s:form> </body>
上述代碼中使用了Struts2框架的標記庫來構建表單,如<s:textfield>表示文本框,<s:password>表示密碼框。
接下來編寫welcome.jsp文件,當登錄成功后,顯示歡迎信息,代碼如下所示:
<body> Welcome,${param.custname} </body>
歡迎頁面將顯示登錄的用戶名,使用EL顯示請求參數custname的值。
(5)定義Action類,調用業務邏輯,返回結果視圖。
業務邏輯和視圖都完成后,需要創建控制器,將二者聯系起來,Action是Struts2使用的業務控制器。Action類不需要繼承或實現任何父類或接口,只要遵守某些命名規范即可:如果該Action類是通過表單提交調用,且Action類中需要使用表單提交的請求參數,那么必須在Action類中聲明與表單域的名字對應的變量,并為變量提供getters/setters方法;Action類中必須有一個public String execute(){}形式的方法,該方法將在訪問Action時被Struts2框架自動調用,實現控制邏輯。
下面創建LoginAction類,調用Model中的登錄邏輯,并根據登錄結果不同而返回不同的結果,代碼如下所示:
public class LoginAction{ private String custname; private String pwd; public String getCustname(){ return custname; } public void setCustname(String custname){ this.custname=custname; } public String getPwd(){ return pwd; } public void setPwd(String pwd){ this.pwd=pwd; } public String execute(){ LoginService ls=new LoginService(); boolean flag=ls.login(custname,pwd); if(flag){ return"success"; }else{ return"fail"; }}}
可見,由于LoginAction類通過index.jsp中的表單提交請求,且LoginAction類中需要使用登錄表單的請求參數值,所以LoginAction類中聲明了與index.jsp中表單元素對應的屬性custname和pwd,并提供了getters和setters方法。在LoginAction類的execute方法中,可以直接使用請求參數custname和pwd,不需要像Servlet中那樣使用request.getParameter方法獲取。請求參數的賦值過程將在后面章節學習。execute方法通過調用LoginService類中的login方法進行登錄驗證,登錄成功返回success字符串,否則返回fail字符串。
(6)在struts.xml中配置Action類。
前面的步驟已經創建了Action類LoginAction,但必須在struts.xml中進行配置才能使用。在Web工程的src文件夾下,創建struts.xml文件,如圖1-1-4所示。

圖1-1-4 在src目錄下創建struts.xml文件
框架在加載自定義的struts.xml文件前,會先加載框架自帶的配置文件struts-default.xml,所以首先了解一下struts-default.xml文件。struts-default.xml文件存在于struts2-core.jar包中,定義了Struts2的基本配置信息,定義了名字為struts-default的包。struts-defualt.xml的部分配置信息如下:
<package name="struts-default" abstract="true"> <result-types> <result-type name="chain" class="com.opensymphony.xwork2.ActionChainResult"/> <result-type name="dispatcher"class="org.apache.struts2.dispatcher.ServletDispatcherResult"default= "true"/> <result-type name="freemarker" class="org.apache.struts2.views.freemarker. FreemarkerResult"/> <result-type name="httpheader" class="org.apache.struts2.dispatcher. HttpHeaderResult"/> <result-type name="redirect" class="org.apache.struts2.dispatcher. ServletRedirectResult"/> <result-type name="redirectAction" class="org.apache.struts2.dispatcher.ServletActionRedirectResult"/> <result-type name="stream" class="org.apache.struts2.dispatcher. StreamResult"/> <result-type name="velocity" class="org.apache …
struts.xml文件規范與struts-default.xml相同,可以根據struts-default.xml來修改struts.xml。struts.xml的基本結構如下:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd"> <struts> </struts>
struts.xml中的所有元素都必須在<struts></struts>標記之間。Action必須在<package>元素中配置,使用<action>元素配置,主要指定name屬性和class屬性。name屬性可以是任意合法標記符,調用Action即通過name值調用;class屬性指定Action的完整類名。代碼如下所示:
<struts> <package name="com.etc.chapter01"extends="struts-default"> <action name="Login"class="com.etc.LoginAction"> <result name="success">/welcome.jsp</result> <result name="fail">/index.jsp</result> </action> </package> </struts>
上述配置文件將LoginAction類定義成一個名字為Login的Action,該Action存在于com.etc.chapter01包中,同時為Action定義了兩個返回結果result,分別是success和fail,對應頁面分別為welcome.jsp和index.jsp。Action的配置信息必須放在<package>元素中,每個<package>必須使用name屬性指定包名,同時必須通過extends屬性指定該包繼承的父包。某個包繼承了父包之后,該包就具有父包中定義的對象。默認情況下,自定義的包都應該繼承struts-default.xml中的struts-default包,因為struts-defautl.xml中的struts-default包定義了很多必要的對象。
<action>元素的子元素通常是<result>,<result>的name屬性與Action類的execute方法的返回值對應,例如,LoginAction類的execute方法有success和fail兩個返回值,代碼如下所示:
if(flag){ return"success"; }else{ return"fail"; }
由于LoginAction中的execute方法有兩個可能的返回值,即success和fail,所以需要配置兩個<result>,<result>的name屬性值分別是success和fail,對應execute方法返回不同值時的頁面導航。通過在struts.xml中配置LoginAction,定義了如下信息:
① 使用LoginAction時,通過Action的name值訪問,即Login。
② 容器根據LoginAction的execute方法返回值來匹配<result>的name屬性,決定頁面導航。如返回success時,跳轉到welcome.jsp頁面;返回fail時,跳轉到index.jsp頁面。
(7)在index.jsp中調用LoginAction。
開發并配置LoginAction后,就可以在JSP中調用LoginAction,代碼如下所示:
<body> <%@taglib uri="/struts-tags" prefix="s" %> <s:form action="Login"> <s:textfield name="custname" label="Input your custname"></s:textfield> <s:password name="pwd" label="Input your password"></s:password> <s:submit value="Login"></s:submit> </s:form> </body>
上述代碼中,將表單的action屬性值指定為LoginAction的名字Login,如<s:form action="Login">,從而,表單將被提交到LoginAction。
(8)在web.xml中配置FilterDispatcher。
如上節中演示的Struts2工作原理圖,任何一個客戶端的請求都必須經過FilterDispatcher進行過濾,才能進入Struts2架構流程。FilterDispatcher是Struts2框架API中提供的類,必須在web.xml中將其配置給任意URL才能生效。代碼如下所示:
<filter> <filter-name>FilterDispatcher</filter-name> <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class> </filter> <filter-mapping> <filter-name>FilterDispatcher</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
至此,簡單的Struts2實例已經開發完成,部署到容器中后,訪問index.jsp頁面,輸入用戶名和密碼進行登錄,如圖1-1-5所示。

圖1-1-5 index.jsp頁面
在index.jsp頁面中輸入用戶名ETC和123 后,單擊“Login”按鈕,將請求提交到LoginAction,LoginAction將調用LoginService中的login方法,登錄成功,跳轉到welcome.jsp歡迎頁面,如圖1-1-6所示。

圖1-1-6 歡迎頁面
如果輸入其他用戶名和密碼,則登錄失敗,跳轉到index.jsp頁面,并回顯曾經輸入的用戶名,如圖1-1-7所示。

圖1-1-7 登錄失敗
可見,登錄失敗跳轉到index.jsp時,用戶名自動回顯,不用寫任何腳本。因為index.jsp中的表單不是使用HTML標記完成,而是使用Struts2的標記完成的,標記已經實現了回顯的功能。
1.3 實例的運行過程

本節將結合Struts2的工作原理,了解上節中實例的運行過程,幫助讀者更進一步理解Struts2框架。實例的大致運行過程如下:
訪問http://localhost:8080/chapter01/index.jsp頁面,如圖1-1-8所示。

圖1-1-8 登錄頁面
index.jsp頁面中的表單使用Struts2框架的JSP標記構建,容器對JSP頁面進行解析,將最終結果輸出到客戶端瀏覽器。在頁面中單擊右鍵,查看源代碼,如下所示:
<form id="Login" name="Login" onsubmit="return true;" action="/chapter01/Login.action " method="post"><table class="wwFormTable"> <tr> <td class="tdLabel"><label for="Login_custname" class="label">Input your custname:</label> </td> <td><input type="text" name="custname" value="" id="Login_custname"/></td> </tr> <tr> <td class="tdLabel"><label for="Login_pwd" class="label">Input your password: </label> </td> <td><input type="password" name="pwd" id="Login_pwd"/></td> </tr> <tr> <td colspan="2"><div align="right"><input type="submit" id="Login_0" value= "Login"/> </div></td> </tr> </table></form>
分析上面的源碼可見,容器執行index.jsp后,輸出到客戶端的是解析后的HTML代碼,其中表單的action值被解析為action="/chapter01/Login.action"。默認情況下,容器總是將Action路徑解析成后綴為.action的URL。
用戶輸入用戶名和密碼,單擊“Login”按鈕后,則向服務器端發送請求,請求的URL根據表單的action值生成http://localhost:8080/chapter01/Login.action。
web.xml中對/*的URL配置了過濾器FilterDispatcher,所以該請求將被FilterDispatcher過濾。
FilterDispatcher調用ActionMapper,ActionMapper判斷URL的資源后綴為.action,因此ActionMapper認為需要調用Struts2框架中的Action類。
FilterDispatcher將請求處理交給ActionProxy,ActionProxy通過解析URL,認為需要調用的Action的名字是Login。
ActionProxy通過Configuration Manager解析struts.xml,找到name=Login的Action配置。
ActionProxy實例化ActionInvocation類。ActionInvocation實例調用與Action有關的攔截器以及Action類的execute方法。其中攔截器的內容將在后面章節學習。每一個Action都默認存在很多攔截器,其中有一個攔截器的功能就是將提交表單的請求參數賦值給Action的實例變量。如index.jsp中表單的custname和pwd域的值,將被賦值給LoginAction中的custname和pwd變量。
Action執行結束后,根據struts.xml中配置的action的result,將頁面導航到URL。
到此為止,已經通過詳細步驟解析了上節實例的運行過程。通過學習這個實例的運行步驟,可以更為清楚地理解Struts2的工作原理。
1.4 Struts2的特點

上節使用Struts2框架完成了一個簡單實例,展示了Struts2應用開發的基本步驟。本節將與Servlet/JSP開發技術進行對比,總結Struts2框架的特點。
(1)Model層無區別。
使用Struts2框架開發Web應用時,Model層的開發沒有特殊要求,可以使用普通的JavaSE類、EJB組件或者其他技術實現。
(2)Controller層區別最大。
MVC框架中最強大的部分往往都是Controller層。使用Servlet和JSP開發Web應用,往往使用Servlet承擔Controller層。而使用Struts2開發Web應用,Controller層包含三部分:過濾器、攔截器、Action。其中Action是數量最多的控制器,基本可以替代Servlet的功能。
(3)單元測試。
Servlet無法脫離容器環境進行單元測試,因為Servlet的doXXX方法的參數是請求和響應,而請求和響應對象依賴容器創建,所以Servlet無法脫離容器環境進行單元測試。而Struts2中的控制器Action的execute方法沒有參數,所以可以脫離容器環境進行單元測試。
(4)獲取請求參數。
Servlet中獲取表單的請求參數,需要使用request.getParameter方法實現。Action中按照命名規范聲明與表單元素對應的屬性以及getter/setter方法,攔截器可以自動攔截請求參數,封裝到Action對應的屬性中,在execute中可以直接使用。
(5)頁面導航。
Servlet中的頁面導航在doXXX方法中通過sendRedirect或者forward方法進行,導航頁面的URL硬編碼到Servlet源代碼中。Action中的頁面導航在struts.xml中通過result定義,頁面URL不需要硬編碼到源碼中,可維護性增強。
(6)視圖技術。
Servlet中直接支持的視圖技術只有JSP一種,而Struts2可以支持多種視圖技術,包括JSP、FreeMarker、Velocity。
(7)JSP標記庫。
Struts2提供了強大的JSP標記庫,能夠實現很多動態功能,如輸入信息回填、校驗信息顯示等,同時也可以使用JSTL等其他標記庫。
Struts2還有很多優點,例如可配置的輸入校驗、便捷的國際化編程等。本節只列出現階段能夠理解的優點,其他相關內容會在后面章節學習。
1.5 教材案例準備

為了幫助讀者更輕松、更容易地理解相關技術,教材中使用一個案例貫穿每個知識點(案例的業務邏輯與叢書之一《JavaEE架構與程序設計》中案例相同),如果閱讀過《JavaEE架構與程序設計》教材,本節可以跳過。該案例不注重業務邏輯,重點在于輔助理解每個知識點。本節將對案例進行簡單介紹,并實現案例的Model部分。在后面章節中,將對案例逐漸完善,為學習各知識點起到輔助作用。
案例中的主要用例描述如下:
用例一:用戶輸入用戶名和密碼進行登錄。
用例二:用戶輸入用戶名、密碼、年齡、地址進行注冊,用戶名不能重復。
用例三:用戶登錄成功后,通過歡迎頁面上的超級鏈接,可以查看個人信息,可以查看所有注冊用戶的除密碼外的信息。
數據庫使用MySQL,創建關系表customer,如圖1-1-9所示。

圖1-1-9 創建customer表
本節將實現教材案例的Model部分,Model由三部分組成,下面逐一進行介紹。
(1)VO類。
VO(Value Object)即值對象,用來封裝實體數據,在MVC各層之間傳遞數據。“教材案例”中只有一種實體,即客戶,所以需要創建一個Customer類,作為VO類使用。代碼如下所示:
package com.etc.vo; public class Customer{ private String custname; private String pwd; private Integer age; private String address; public Customer(){ super(); } public Customer(String custname,String pwd){ super(); this.custname=custname; this.pwd=pwd; } public Customer(String custname,String pwd,Integer age,String address){ super(); this.custname=custname; this.pwd=pwd; this.age=age; this.address=address; } public String getCustname(){ return custname; } public void setCustname(String custname){ this.custname=custname; } public String getPwd(){ return pwd; } public void setPwd(String pwd){ this.pwd=pwd; } public Integer getAge(){ return age; } public void setAge(Integer age){ this.age=age; } public String getAddress(){ return address; } public void setAddress(String address){ this.address=address;}}
VO類中封裝了客戶的4個屬性,包括custname、pwd、age以及address,同時為這些屬性提供了getter和setter方法,用來返回及設置屬性。
(2)DAO層。
DAO(Data Access Object)即數據訪問對象,用來封裝數據訪問邏輯。很多時候,初學者可能將數據訪問邏輯與業務邏輯混在一起實現。然而,很多數據訪問邏輯可能被多個業務邏輯共同使用,如銀行系統中的存款和取款兩個業務邏輯,都會使用到修改余額的數據訪問邏輯。因此,有必要將數據訪問邏輯與業務邏輯分離。通過分析教材案例的業務邏輯,可以總結出案例中需要實現根據用戶名查詢、根據用戶名密碼查詢、插入一條記錄、查詢所有記錄四種數據邏輯,那么將這4種數據邏輯使用接口CustomerDAO定義,在類CustomerDAOImpl中實現,作為數據訪問對象使用。
由于數據訪問邏輯中總需要獲得連接對象,所以將獲得連接對象的方法封裝到一個工具類中。創建工具類JDBCConnectionFactory,作為Connection對象的工具類,代碼如下所示:
public class JDBCConnectionFactory{ public static Connection getConnection(){ Connection conn=null; try{ Class.forName("com.mysql.jdbc.Driver"); conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/scwcd","root","123 "); }catch(ClassNotFoundException e){ e.printStackTrace(); }catch(SQLException e){ e.printStackTrace(); } return conn; }}
上述代碼中聲明了一個靜態方法getConnection,可以獲得一個MySQL數據庫的連接對象。接下來,創建CustomerDAOImpl類,實現4個數據邏輯方法。代碼如下所示:
public class CustomerDAOImpl implements CustomerDAO{ public List<Customer>selectAll(){ List<Customer>list=new ArrayList<Customer>(); Connection conn=JDBCConnectionFactory.getConnection(); try{ Statement stmt=conn.createStatement(); String sql="select custname,age,address from customer"; ResultSet rs=stmt.executeQuery(sql); while(rs.next()){ list.add(new Customer(rs.getString(1),null,rs.getInt(2),rs.getString(3))); } }catch(SQLException e){ e.printStackTrace(); }finally{ if(conn!=null){ try{ conn.close(); }catch(SQLException e){ e.printStackTrace(); } } } return list; } public Customer selectByName(String custname){ Customer cust=null; Connection conn=JDBCConnectionFactory.getConnection(); String sql="select*from customer where custname=?"; try{ PreparedStatement pstmt=conn.prepareStatement(sql); pstmt.setString(1,custname); ResultSet rs=pstmt.executeQuery(); if(rs.next()){ cust=new Customer(rs.getString(1),rs.getString(2),rs.getInt(3),rs.getString(4)); } }catch(SQLException e){ e.printStackTrace(); }finally{ if(conn!=null){ try{ conn.close(); }catch(SQLException e){ e.printStackTrace(); } } } return cust; } public Customer selectByNamePwd(String custname,String pwd){ Customer cust=null; Connection conn=JDBCConnectionFactory.getConnection(); String sql="select*from customer where custname=?and pwd=?"; try{ PreparedStatement pstmt=conn.prepareStatement(sql); pstmt.setString(1,custname); pstmt.setString(2,pwd); ResultSet rs=pstmt.executeQuery(); if(rs.next()){ cust=new Customer(rs.getString(1),rs.getString(2),rs.getInt(3),rs.getString(4)); } }catch(SQLException e){ e.printStackTrace(); }finally{ if(conn!=null){ try{ conn.close(); }catch(SQLException e){ e.printStackTrace(); } } } return cust; } public void insert(Customer cust){ Connection conn=JDBCConnectionFactory.getConnection(); String sql="insert into customer values(?,?,?,?)"; try{ PreparedStatement pstmt=conn.prepareStatement(sql); pstmt.setString(1,cust.getCustname()); pstmt.setString(2,cust.getPwd()); pstmt.setInt(3,cust.getAge()); pstmt.setString(4,cust.getAddress()); pstmt.executeUpdate(); }catch(SQLException e){ e.printStackTrace(); }finally{ if(conn!=null){ try{ conn.close(); }catch(SQLException e){ e.printStackTrace();}}}}}
上述代碼中,CustomerDAOImpl類通過JDBCConnectionFactory獲得數據庫連接對象,然后使用JDBC API進行數據庫編程,實現了4個數據訪問邏輯。
(3)Service層。
實現了必需的數據邏輯后,就可以實現業務邏輯,往往使用服務類來封裝業務邏輯,案例中創建CustomerService接口,定義登錄、注冊、查看個人信息、查看所有人信息4種業務邏輯。在CustomerServiceImpl類中使用DAO層數據訪問邏輯,實現業務邏輯。代碼如下所示:
public class CustomerServiceImpl implements CustomerService{ private CustomerDAO dao; public void setDao(CustomerDAO dao){ this.dao=dao; } public boolean login(String custname,String pwd){ Customer cust=dao.selectByNamePwd(custname,pwd); if(cust!=null){ return true; }else{ return false; } } public boolean register(Customer cust){ Customer c=dao.selectByName(cust.getCustname()); if(c==null){ dao.insert(cust); return true; }else{ return false; } } public Customer viewPersonal(String custname){ return dao.selectByName(custname); } public List<Customer>viewAll(){ return dao.selectAll(); }
至此,案例中的Model部分已經完成,共分為三部分,分別為VO、DAO、Service,在Service層最終實現了所有業務邏輯,控制器將調用Service層的業務邏輯實現功能。
1.6 本章小結
本章主要目標是幫助讀者快速入門Struts2框架。Struts框架已經盛行多年,然而Struts2和Struts1之間并不是擴展和升級關系。Struts2是另一個著名框架WebWork的擴展,與Struts1沒有太多直接的聯系。本章首先結合官方網站的Struts2工作原理圖,介紹Struts2的基本工作流程。接下來,通過一個簡單實例展示Struts2應用的開發步驟,幫助讀者能夠順利開發、部署并運行基于Struts2框架的Web應用。同時,結合該簡單實例進一步解釋了Struts2運行過程,以幫助讀者直觀理解Struts2的工作原理。本章還為教材接下來的章節準備了一個實例,稱為“教材案例”,將在后面章節中不斷完善,以輔助學習相關知識點。
- iOS Game Programming Cookbook
- LabVIEW入門與實戰開發100例
- 網頁設計與制作教程(HTML+CSS+JavaScript)(第2版)
- PLC編程及應用實戰
- 實戰Java高并發程序設計(第3版)
- Building an RPG with Unity 2018
- Symfony2 Essentials
- Visual FoxPro程序設計習題集及實驗指導(第四版)
- ArcGIS for Desktop Cookbook
- Creating Data Stories with Tableau Public
- 玩轉.NET Micro Framework移植:基于STM32F10x處理器
- 大學計算機應用基礎(Windows 7+Office 2010)(IC3)
- INSTANT JQuery Flot Visual Data Analysis
- Java Hibernate Cookbook
- jQuery Mobile Web Development Essentials(Second Edition)