- Java EE框架開發技術與案例教程
- 張繼軍 董衛
- 3894字
- 2020-05-28 14:20:32
3.3 Struts 2入門案例
創建一個基于Struts 2的Web應用程序,需要完成以下5項工作。
1)創建Dynamic Web project工程,并搭建其支持Struts 2的開發環境。
2)設計模型層(設計有關的模型類),設計有關的業務邏輯處理。
3)設計控制層(設計有關的Action類),實現模型和視圖之間的交互。
4)設計視圖層(設計有關的JSP頁面),實現信息的提交與顯示。
5)修改映射文件struts.xml,在其中添加有關的Action和視圖類之間的映射。
3.3.1 入門案例1——基于Struts 2計算任意兩個數據的和
【例3-1】設計Web程序,其功能是用戶輸入兩個整數,提交給Action,在Action中計算這兩個數的和值,若和值為非負數,則跳轉到positive.jsp頁面,否則跳轉到negative.jsp頁面。運行界面如圖3-3所示。其中圖3-3a所示是輸入界面,而圖3-3b、圖3-3c所示是顯示結果界面。

圖3-3 【例3-1】的運行界面
a) 輸入界面b) 結果為非負數的輸出界面c) 結果為負數的輸出界面
【分析與設計】根據基于Struts 2開發的步驟,需要做的具體工作如下。
1)模型組件的創建:創建一個模型類Add.java,實現求和并保存和值。
2)控制器組件的創建:創建一個Action類AddAction.java,該類有一個屬性——Add add),利用該屬性,調用模型Add完成業務處理,并返回“頁面邏輯值”,當返回值為“-”時,表示計算結果為負數,否則,當返回值為“+”時,表示計算結果為非負數。
3)視圖組件的創建:視圖組件有3個JSP頁面:提交數據頁面(input.jsp),顯示結果為非負數的positive.jsp頁面,以及顯示結果為負數的negative.jsp頁面。
4)在配置文件struts.xml中,添加Action與視圖之間的映射關系,即AddAction與positive.jsp和negative.jsp之間的關系。
它們之間的邏輯關系如圖3-4所示。

圖3-4 【例3-1】的各組件之間的邏輯關系
【實現】按照設計步驟,依次實現。
1)創建Web工程struts2Add,并導入Struts 2必需的jar包(見3.2節)。
2)在web.xml中添加對Struts 2支持的核心控制器(具體配置信息見3.2節)。
3)編寫模型類:Add.Java(設計的類必須滿足JavaBean規范),其代碼如下。

4)設計業務控制類(Action類):AddAction.java。
該控制器的屬性為Add add,通過add接受用戶提交的數據x和y,計算并獲得sum值,該Action與網頁positive.jsp或negative.jsp共享數據add,其代碼如下。

5)修改struts.xml配置文件,添加Action的配置信息。

這些配置信息是Action與JSP頁面之間關聯的信息,其具體配置格式和配置內容將在后面給出詳細說明。
6)編寫JSP頁面:需要3個頁面:input.jsp、positive.jsp和negative.jsp。
① 提交數據頁面:input.jsp,主要代碼如下。

② 代數和為非負數時要跳轉到頁面positive.jsp,主要代碼如下。

③ 代數和為負數時要跳轉到頁面negative.jsp,主要代碼如下。
<body>代數和為負整數,其和值為:${add.x}+${add.y}=${add.sum}</body>
7)將該工程添加到服務器Tomcat中并運行,運行界面如圖3-3所示。
提示:各組件實現數據共享是通過“Action容器”實現的,所以,在提交頁面和從Action實現的跳轉頁面中所共享的數據,必須與Action屬性一樣。
3.3.2 入門案例2——基于Struts 2實現用戶注冊與登錄
【例3-2】在Web應用程序中,一般都需要實現用戶注冊與用戶登錄子系統。在本例中基于Struts 2開發設計用戶注冊與登錄功能。運行界面如圖3-5所示。

圖3-5 【例3-2】的運行界面
a) 主頁面b) 注冊頁面c) 注冊成功頁面d) 登錄頁面e) 登錄成功頁面f) 登錄失敗頁面
【分析與設計】
1)模型組件的創建。
該系統需要數據庫(MySQL數據庫),對數據庫進行操作,利用DAO模式,所以需要設計與數據庫有關的添加、查詢等操作的模型類和數據庫操作的通用類。
● DBConnection:實現數據庫連接和關閉的工具類。
● UserDao:實現數據庫操作的DAO業務類。
● EndUser:用戶JavaBean類,用于描述用戶信息及有關的處理方法。
2)控制器組件的創建。
創建Action類UserAction.java,包含用戶登錄方法和注冊方法,以及相關的屬性。
3)視圖組件的創建,視圖組件有8個JSP頁面。
● 登錄頁面(login.jsp):當需要登錄或者注冊時,顯示該頁面。
● 登錄成功頁面(login_success.jsp):用戶名和密碼都輸入正確,顯示該頁面。
● 登錄失敗頁面(login_failure.jsp):當用戶名或密碼不正確時顯示該頁面。
● 注冊頁面(register.jsp):當沒有注冊時,需要利用該頁面提交并注冊信息。
● 注冊成功頁面(register_success.jsp):當將注冊信息寫入數據庫后,顯示的頁面。
● 注冊失敗頁面1(register_failure_user.jsp):注冊時,若用戶已存在,提示重新注冊。
● 注冊失敗頁面2(register_failure.jsp):訪問數據庫出錯時,給出的提示頁面。
● 系統主頁面(index.jsp):當正確登錄后,進入系統的主頁面。
4)針對所要完成的模塊,單獨設計了一個滿足該模塊的struts配置文件:struts-user.xml,并且將該配置文件包含到struts.xml配置中。
這些組件之間的組織結構如圖3-6所示,其中圖3-6a是src目錄下的Java類和配置文件,圖3-6b是視圖目錄下的各JSP與web.xml文件。

圖3-6 【例3-2】各組件的組織結構圖
a) Java類和配置文件b) 視圖目錄下的各JSP與web.xml文件
這些組件是基于MVC的,它們之間的邏輯關聯關系如圖3-7所示。

圖3-7 【例3-2】的各組件之間的邏輯關聯關系
【Struts 2的關鍵思想】
在圖3-7中,視圖組件與Action組件之間是“數據耦合”的,如圖3-8所示。在登錄頁面和注冊頁面中分別輸入域屬性(name屬性),與Action類中的EndUser user屬性同名稱,這樣兩者之間就可以共享數據(在Action容器內共享)。圖3-8只給出了登錄過程中的數據共享示例,對于注冊過程是類似的,請讀者自己思考并給出。

圖3-8 數據之間的共享關系圖
【數據庫的設計】
該系統設計的數據庫為struts 2,其中的數據表為user,各數據字段如表3-1所示。采用MySQL數據庫,其中的數據庫密碼為123456,用戶名為root。
表3-1 數據表結構字段

【實現】按照設計步驟,依次實現。
1)在Eclipse中創建Web工程struts2user,并導入Struts 2必需的jar包。
2)修改web.xml配置文件,在web.xml中添加配置信息。
注意:這里的1)和2)兩步與【例3-1】一樣,不再詳述。
3)編寫模型類。
● 描述用戶信息EndUser類的實現,其代碼如下。
package com.model.user; public class EndUser{ private Integer userId; private String userName; private String userPassword; private String userRealName; //這里省略了所有屬性的setter/getter方法 }
● 數據庫連接及關閉工具類DBConnection的實現,其代碼如下。
package com.db_util; import java.sql.*; public class DBConnection { private static String driverName="com.mysql.jdbc.Driver"; //MySQL數據庫驅動程序 private static String userName="root"; //數據庫用戶名 private static String userPwd="123456"; //數據庫用戶密碼 private static String dbName="struts2"; 數據庫名稱 public static Connection getDBConnection(){ //獲取數據庫連接對象的方法 String url1="jdbc:mysql://localhost/"+dbName; String url2="? user="+userName+"&password="+userPwd; String url3="&useUnicode=true&characterEncoding=utf-8"; String url=url1+url2+url3; //形成數據庫連接字 Connection con=null; try { Class.forName(driverName); //加載驅動 con=DriverManager.getConnection(url); //獲取數據庫連接對象 } catch (Exception e) {e.printStackTrace(); } return con; } //關閉數據庫連接的各資源對象 public static void closeDB(Connection con, PreparedStatement pstm, ResultSet rs){ if(rs! =null) try {rs.close(); } catch (SQLException e) {e.printStackTrace(); } if(pstm! =null) try {pstm.close(); } catch (SQLException e) {e.printStackTrace(); } if(con! =null) try {con.close(); } catch (SQLException e) {e.printStackTrace(); } } }
● 數據庫操作的DAO類UserDao類的實現。
其代碼如下,這里只給出了兩個方法,即添加記錄和查找記錄的方法。
package com.dao.user; //省略了import導入包; public class UserDao { public int save(EndUser user) { //向數據庫中插入一個用戶的方法 Connection con=null; PreparedStatement pstmt=null; ResultSet rs=null; con=DBConnection.getDBConnection(); int row=0; String sql="insert into user(userName, userPassword, userRealName) values(? , ? , ? )"; try { pstmt=con.prepareStatement(sql); pstmt.setString(1, user.getUserName()); pstmt.setString(2, user.getUserPassword()); pstmt.setString(3, user.getUserRealName()); row=pstmt.executeUpdate(); } catch (Exception e) {e.printStackTrace(); } finally{DBConnection.closeDB(con, pstmt, rs); } return row; } public EndUser find(EndUser user) { //從數據庫中查找一個用戶,用于驗證是否注冊 Connection con=null; PreparedStatement pstmt=null; ResultSet rs=null; con=DBConnection.getDBConnection(); EndUser user2=null; String sql="select * from user where userName=? and userPassword=? "; try { pstmt=con.prepareStatement(sql); pstmt.setString(1, user.getUserName()); pstmt.setString(2, user.getUserPassword()); rs=pstmt.executeQuery(); if(rs.next()){ user2=new EndUser(); user2.setUserId(rs.getInt("id")); user2.setUserName(rs.getString("userName")); user2.setUserPassword(rs.getString("userPassword")); user2.setUserRealName(rs.getString("userRealName")); } } catch (Exception e) {e.printStackTrace(); } finally{DBConnection.closeDB(con, pstmt, rs); } return user2; } }
4)設計控制類(Action類):UserAction.java。
該類利用模型層中的兩個類:EndUser和UserDao,給出對應的兩個屬性,通過Action方法實現所要求的功能,并利用user屬性實現與視圖層的數據共享。代碼如下。
package com.action.user; //省略了import導入包; public class UserAction { private EndUser user; private UserDao userDao = new UserDao(); public String userLogin() throws Exception {//用戶登錄Action方法 String forward = null; EndUser user2 = userDao.find(user); if(user2! =null){forward="success"; }else{ forward="failure"; } return forward; } public String userRegister() throws Exception {//用戶注冊Action方法 String forward="error"; //數據庫存數據時出錯標記值 int flag = 0; EndUser user2=(userDao.find(user)); if (user2! =null){forward = "error_user"; //用戶名已被占用標記標記值 } else { flag = userDao.save(user); if (flag = = 1) {forward = "success"; //成功注冊標記值} } return forward; } //這里省略了屬性user的set/get方法,對于屬性UserDao userDao,不需要set/get方法 }
5)配置Action形成單獨的配置文件struts-user.xml,并將其包含到struts.xml文件中。文件struts-user.xml的具體配置信息如下(注意該文件的格式與struts.xml一樣,這里省略了文件頭部分),在該配置中,配置了兩個Action。

將配置文件包含到struts.xml中,其內容如下。
<struts> <include file="struts-user.xml" /> </struts>
提示:這種配置方式是便于模塊化開發系統,每個模塊都有單獨的配置文件,易于維護和擴展。
6)編寫JSP頁面。
視圖組件有8個JSP頁面,這里只給出每個頁面的body標簽內的內容。
● 登錄頁面(login.jsp),當需要登錄或者注冊時,顯示的初始頁面。
<body> <form method="post" action="/struts2user/user/logincheck"> <table> <tr><th colspan="2">用戶登錄</th></tr> <tr><td align="right">用戶名:</td> <td><input name="user.userName" /></td> </tr> <tr><td align="right">密碼:</td> <td><input type="password" name="user.userPassword" /></td> </tr> <tr><td align="left"><input type="submit" value="登錄" /></td> <td>未注冊者,請先注冊,單擊<a href="/struts2user/user/register.jsp">注冊</a></td> </tr> </table> </form> </body>
● 登錄成功頁面(login_success.jsp),當用戶名和密碼都正確時,顯示該頁面。
<body> 歡迎你,${user.userRealName},你登入成功!! <br> 進入主頁面,請點擊<a href="/struts2user/index.jsp">主頁面</a> </body>
● 登錄失敗提示頁面(login_failure.jsp),當用戶名或密碼不正確時,顯示該頁面。
<body> <h2 align="center"> <font color="red">對不起,你填寫的賬號和密碼不正確!請</font> <a href="/struts2user/user/login.jsp">重新登錄</a> </h2> </body>
● 注冊頁面(register.jsp),注意采用js腳本實現輸入驗證。
<head><title>注冊頁面</title> <script type="text/javascript"> function isValidate(form) { var username=document.getElementById("username").value; var userpass=document.getElementById("userpassword").value; var userpass1=document.getElementById("userpass1").value; if (userpass ! = userpass1) { alert("兩次密碼輸入不一致,請重新輸入!"); return false; }else if (userpass.length<=0 ||username.length<=0 ) { alert("用戶名以及密碼不能為空,請重新輸入!"); return false; } else{return true; } } </script></head> <body> <h3 align="left">歡迎注冊我們的系統,請認真填寫您的信息</h3> <form name="register" action="/struts2user/user/register" method="post" onsubmit="return isValidate()"> <table> <tr><td align="right">賬戶名:</td> <td><input name="user.userName" id="username"></td></tr> <tr><td align="right">為您的賬戶設置密碼:</td> <td><input type="password" name="user.userPassword" id="userpassword"></td></tr> <tr><td align="right">再次確認您的密碼:</td> <td><input type="password" name="userpass1" id="userpass1"></td></tr> <tr><td align="right">真實姓名:</td> <td><input name="user.userRealName"id="userrealname"></td></tr> <tr><td align="right"><input type="submit" value="提交"></td> <td colspan="2"><input type="reset" value="重新填寫"></td></tr> </table> </form> </body>
對于頁面register_success.jsp、register_failure_user.jsp、register_failure.jsp、index.jsp與登錄成功、失敗頁面類似,這里就不再給出介紹。
本節通過兩個簡單的案例,較詳細地給出了基于Struts 2開發應用程序的思想、方法和步驟。這是深入學習和掌握Struts 2所必需的基礎知識。在后面的章節中,將Struts 2按MVC三層結構,分別給出M、C、V有關內容的詳細說明與應用設計。
提示:Struts 2的中文亂碼問題處理:在視圖頁面與Action進行信息交互時,若有中文字符,會出現亂碼問題。Struts 2中有兩種方法可以解決這個問題:①設置JSP頁面的pageEncoding="UTF-8"。②如果JSP頁面的pageEncoding="GBK",那么需要在源包(src)下建立一個屬性文件struts.properites,并在該文件內填寫如下內容,修改有關的屬性值:struts.locale=zh_CN, struts.i18n.encoding=gbk
- 零基礎搭建量化投資系統:以Python為工具
- 工程軟件開發技術基礎
- ASP.NET Core Essentials
- Visual C++實例精通
- Spring Boot+Spring Cloud+Vue+Element項目實戰:手把手教你開發權限管理系統
- 基于差分進化的優化方法及應用
- Cassandra Data Modeling and Analysis
- Building a Quadcopter with Arduino
- Hands-On Microservices with Kotlin
- Mastering Android Game Development
- 輕松上手2D游戲開發:Unity入門
- 計算機應用技能實訓教程
- Software Architecture with Python
- Magento 2 Developer's Guide
- 軟件自動化測試實戰解析:基于Python3編程語言