[Struts2]從頭開始-簡易CRUD範例實作
開發工具:Eclipse / Maven
AP:Tomcat 6
資料庫:MySQL 5.6
畫面:
Class Diagram:
Sequence Diagram:(僅舉add部份)
先使用 MySQL 建立一張Table
語法:
CREATE TABLE `tbl_user` (
`userId` int(11) NOT NULL,
`name` varchar(20) DEFAULT NULL,
`sex` varchar(10) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
PRIMARY KEY (`userId`)
) ENGINE=InnoDB DEFAULT CHARSET=big5;
請順手建立幾筆測試資料!!!!
接著我們準備要用來接取資料的 UserModel
package com.Model;
public class UserModel {
private int userId;
private String name;
private String sex;
private int age;
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int hashCode(){
final int prime =31;
int result = 1;
result = prime * result + userId;
return result;
}
public boolean equals(Object obj){
if(this == obj){
return true;
}
if(obj == null){
return false;
}
if(getClass() != obj.getClass()){
return false;
}
final UserModel other = (UserModel) obj;
if(userId != other.userId){
return false;
}
return true;
}
}
我們先準備一個 DataSourceHolder,算是一個中繼點,或是一個Service,讓其幫我們處理與資料庫之間的開啟與中斷。當中使用了BasicDataSource 代替一般的 jdbc (Class.forName(driver)) 設定方式。
package com.util;
import javax.sql.DataSource;
import org.apache.tomcat.dbcp.dbcp.BasicDataSource;
public class DataSourceHolder {
private BasicDataSource ds = new BasicDataSource();
private DataSourceHolder(){
//ds.setDriverClassName("org.gjt.mm.mysql.Driver");
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=big5");
ds.setUsername("root");
ds.setPassword("XXXXXX");
}
private static class SingletonHolder{
private static DataSourceHolder instance = new DataSourceHolder();
}
public static DataSourceHolder getInstance(){
return SingletonHolder.instance;
}
public DataSource getDataSources(){
return ds;
}
}
裡面因為有考慮到查詢資料時的條件,故我們會需要在編寫一個 UserQueryModel 其繼承自 UserModel用於查詢資料用,於 Dao 中的 getByCondition() Function 會使用到
package com.Model;
public class UserQueryModel extends UserModel {
private int age2;
public int getAge2() {
return age2;
}
public void setAge2(int age2) {
this.age2 = age2;
}
}
再來編寫Dao的部份:
當中就是使用我們建立好的 DataSourceHolder,當作我們與 db 之間的好朋友。記得 DataSource使用完後,必須要記得關閉其與 DB 之間的連線喔
package com.CRUD;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import com.Model.UserModel;
import com.Model.UserQueryModel;
import com.util.DataSourceHolder;
public class UserJDBCDao {
public void create(UserModel user){
Connection conn = null;
try {
conn= DataSourceHolder.getInstance().getDataSources().getConnection();
final String sql = "insert into tbl_user(userId,name,sex,age) values(?,?,?,?)";
PreparedStatement ps = conn.prepareStatement(sql);
int count =1 ;
ps.setInt(count++, user.getUserId());
ps.setString(count++, user.getName());
ps.setString(count++, user.getSex());
ps.setInt(count++, user.getAge());
ps.execute();
ps.close();
} catch (Exception e) {
e.printStackTrace();
} finally{
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public void update(UserModel user){
Connection conn = null;
try {
conn= DataSourceHolder.getInstance().getDataSources().getConnection();
final String sql = "update tbl_user set name=?,sex=?,age=? where userId=?";
PreparedStatement ps = conn.prepareStatement(sql);
int count =1 ;
ps.setString(count++, user.getName());
ps.setString(count++, user.getSex());
ps.setInt(count++, user.getAge());
ps.setInt(count++, user.getUserId());
ps.execute();
ps.close();
} catch (Exception e) {
e.printStackTrace();
} finally{
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public void delete(int userId){
Connection conn = null;
try {
conn= DataSourceHolder.getInstance().getDataSources().getConnection();
final String sql = "delete from tbl_user where userId=?";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setInt(1, userId);
ps.execute();
ps.close();
} catch (Exception e) {
e.printStackTrace();
} finally{
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public UserModel getSingle(int userId){
UserModel user = null;
Connection conn = null;
try {
conn = DataSourceHolder.getInstance().getDataSources().getConnection();
final String sql = "select * from tbl_user where userId=?";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setInt(1, userId);
ResultSet rs = ps.executeQuery();
if(rs.next()){
user = this.rs2Model(rs);
}
rs.close();
ps.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return user;
}
private UserModel rs2Model(ResultSet rs) throws Exception{
UserModel user = new UserModel();
user.setUserId(rs.getInt("userId"));
user.setName(rs.getString("name"));
user.setSex(rs.getString("sex"));
user.setAge(rs.getInt("age"));
return user;
}
public List<UserModel> getAll(){
List<UserModel> list = new ArrayList<UserModel>();
Connection conn = null;
try {
conn = DataSourceHolder.getInstance().getDataSources().getConnection();
final String sql = "select * from tbl_user order by userId";
PreparedStatement ps = conn.prepareStatement(sql);
ResultSet rs = ps.executeQuery();
while(rs.next()){
UserModel user = this.rs2Model(rs);
list.add(user);
}
rs.close();
ps.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return list;
}
private String generateWhere (UserQueryModel uqm){
StringBuffer buffer = new StringBuffer();
//用戶是否選用用戶編號作為條件
if(uqm.getUserId()>0){
buffer.append(" and userId = ?");
}
//用戶是否選用用戶姓名作為條件
if(uqm.getName()!=null && uqm.getName().trim().length()>0){
buffer.append(" and name like ?");
}
//用戶是否選用用戶姓性別為條件
if(uqm.getSex()!=null && uqm.getSex().trim().length()>0){
buffer.append(" and sex = ?");
}
//用戶是否選用用戶姓年齡最小值為條件
if(uqm.getAge()>0){
buffer.append(" and age >= ?");
}
//用戶是否選用用戶姓年齡最大值為條件
if(uqm.getAge()>0){
buffer.append(" and age <= ?");
}
return buffer.toString();
}
private void preparePs(UserQueryModel uqm,PreparedStatement ps) throws SQLException{
int count = 1;
if(uqm.getUserId()>0){
ps.setInt(count++, uqm.getUserId());
}
if(uqm.getName()!=null && uqm.getName().trim().length()>0){
ps.setString(count++, "%" + uqm.getName() + "%" );
}
if(uqm.getSex()!=null && uqm.getSex().trim().length()>0){
ps.setString(count++, uqm.getSex());
}
if(uqm.getAge()>0){
ps.setInt(count++, uqm.getAge());
}
if(uqm.getAge2()>0){
ps.setInt(count++, uqm.getAge2());
}
}
public List<UserModel> getByCondition(UserQueryModel uqm){
List<UserModel> list = new ArrayList<UserModel>();
Connection conn = null;
try {
conn = DataSourceHolder.getInstance().getDataSources().getConnection();
final String sql = "select * from tbl_user where 1=1 " +
this.generateWhere(uqm) + " order by userId";
PreparedStatement ps = conn.prepareStatement(sql);
this.preparePs(uqm, ps);
ResultSet rs = ps.executeQuery();
while(rs.next()){
UserModel user = this.rs2Model(rs);
list.add(user);
}
rs.close();
ps.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return list;
}
}
接著我們可以先把畫面設計好:
index.jsp 就省略不說,裡面就是使用
<s:form action="/crud1/userToList" method="POST">
<s:submit value="開始" />
</s:form>
跳轉到我們的主畫面中。
再來我們可以看一下,stuts.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>
<constant name="struts.devMode" value="true" />
<constant name="struts.locale" value="zh_TW" />
<constant name="struts.i18n.encoding" value="UTF-8" />
<!-- 允許使用OGNL -->
<constant name="struts.ognl.allowStaticMethodAccess" value="true" />
<!-- 使用struts2 ui -->
<!-- <constant name="struts.ui.theme" value="simple" /> -->
<constant name="struts.ui.theme" value="xhtml" />
<package name="crud1" namespace="/crud1" extends="struts-default">
<global-results>
<result name="toList">/list.jsp</result>
</global-results>
<action name="userToList" class="com.Action.UserAction" method="toList">
</action>
<action name="userToAdd" class="com.Action.UserAction" method="toAdd">
<result name="toAdd">/add.jsp</result>
</action>
<action name="userAdd" class="com.Action.UserAction" method="add" />
<action name="userToUpdate" class="com.Action.UserAction" method="toUpdate">
<result name="toUpdate">/update.jsp</result>
</action>
<action name="userUpdate" class="com.Action.UserAction" method="update" />
<action name="userDelete" class="com.Action.UserAction" method="delete" />
<action name="userToQuery" class="com.Action.UserAction" method="toQuery">
<result name="toQuery">/query.jsp</result>
</action>
<action name="userQuery" class="com.Action.UserAction" method="query" />
</package>
</struts>
用來顯示主要資料的頁面:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>顯示使用者資料</title>
</head>
<body>
<hr>
<table border="1" cellpadding="1" cellspacing="0" align="center">
<tr>
<td>編號</td>
<td>姓名</td>
<td>性別</td>
<td>年齡</td>
<td>操作</td>
</tr>
<s:iterator value="list">
<tr>
<td><s:property value="userId"/></td>
<td><s:property value="name"/></td>
<td><s:property value="sex"/></td>
<td><s:property value="age"/></td>
<td>
<!--
<a href="/HelloStruts2_CRUD_001/crud1/userToAdd.action">添加用戶</a>|
-->
<a href="<s:url action='userToAdd'/>">添加用戶</a>|
<a href="/HelloStruts2_CRUD_001/crud1/userToUpdate.action?user.userId=<s:property value='userId' />">修改</a>|
<a href="javascript:if(confirm('確認刪除嗎?'))window.location.href='/HelloStruts2_CRUD_001/crud1/userDelete.action?user.userId=<s:property value='userId' />'">刪除</a>
</td>
</tr>
</s:iterator>
</table>
<div align="center">
<!--
<a href="/HelloStruts2_CRUD_001/crud1/userToList.action">顯示全部用戶</a>
<a href="/HelloStruts2_CRUD_001/crud1/userToQuery.action">查詢用戶</a>
-->
<a href="<s:url action='userToList'/>">顯示全部用戶</a><br />
<a href="<s:url action='userToQuery'/>">查詢用戶</a>
</div>
</body>
</html>
看到這可能有些頭昏眼花了,當然若是使用 ctrl+C ctrl+V 就不會有這樣的困擾了。
其實在這邊我們畫面跟功能決定後,應該要開始先設計整個 Action
我們可以將不同的Action 功能寫在不同的 Action 類別中,也可以透過指定Method的方式,將相關的功能寫在同一支 Action 類別中。
如下:
UserAction.java
package com.Action;
import java.util.List;
import com.CRUD.UserJDBCDao;
import com.Model.UserModel;
import com.Model.UserQueryModel;
import com.opensymphony.xwork2.ActionSupport;
public class UserAction extends ActionSupport {
private static final long serialVersionUID = -1651659160635719619L;
private List<UserModel> list;
private String[] sexs = new String[]{"男","女"};
private UserModel user;
private UserQueryModel uqm;
/**
* 主要顯示
* @return
* @throws Exception
*/
public String toList() throws Exception {
UserJDBCDao dao = new UserJDBCDao();
list = dao.getAll();
return "toList";
}
public String toAdd() throws Exception {
return "toAdd";
}
public String add() throws Exception {
UserJDBCDao dao = new UserJDBCDao();
dao.create(user);
return this.toList();
}
public String toUpdate() throws Exception{
UserJDBCDao dao = new UserJDBCDao();
user = dao.getSingle(user.getUserId());
return "toUpdate";
}
public String update() throws Exception{
UserJDBCDao dao = new UserJDBCDao();
dao.update(user);
return this.toList();
}
public String delete() throws Exception{
UserJDBCDao dao = new UserJDBCDao();
dao.delete(user.getUserId());
return this.toList();
}
public String toQuery() throws Exception{
return "toQuery";
}
public String query() throws Exception{
UserJDBCDao dao = new UserJDBCDao();
list = dao.getByCondition(uqm);
return "toList";
}
public List<UserModel> getList() {
return list;
}
public void setList(List<UserModel> list) {
this.list = list;
}
public String[] getSexs() {
return sexs;
}
public void setSexs(String[] sexs) {
this.sexs = sexs;
}
public UserModel getUser() {
return user;
}
public void setUser(UserModel user) {
this.user = user;
}
public UserQueryModel getUqm() {
return uqm;
}
public void setUqm(UserQueryModel uqm) {
this.uqm = uqm;
}
}
說明一下程式流程應該會讓想法更清楚一點,我們一開始要點擊按鈕,讓程式導到我們的的Action中 (/crud1/userToList),而這個 Action 我們當初想好就是要用來顯示資料的,所以我們建立一個 ActionSupport 類別,將所要導入的資料 UserModel 帶入,並把相關的資料都設定好 (如:<s:property value="userId"/>),但是這樣只有資料而已,我們還沒有與 Dao 做連結,並向 DB 取得目前存於資料庫中的資料,看一下 struts 中對應的 (/crud1/userToList) 資料,因為我們要將多個 功能 寫進同一個 Action 類別中,所以我們會採用指定 Method 方式,這邊設定我們我指定的 Method 是 toList(),故要在我們的 Action 類別中編寫一個 toList 的方法,而該方法就是藉由 Dao 來取得目前 DB 中所有的資料,並回傳一個 String,該 String 表示該 Action 要切換到哪一個結果,我們將其設定為 toList,也就是在 Struts.xml 的設定檔中,要有一個 <result name="toList">/list.jsp</result> 對應的結果。而這個 list.jsp 的頁面,就是我們設計好的 用來顯示資料的頁面,只是剛開始時,資料是空的,而目前我們藉由與 Dao 連線之後,將資料儲存起來了,再次進入這個畫面時,我們剛剛所設定的 <s:property value="userId"/> 就可以取得對應的資料,並將其顯示出來囉。
第一個功能出來之後,接下來就可以慢慢的將其他 CRUD 的相關功能加上,整個的流程都是相似的,只是要先想好,要顯示什麼樣的資料,而什麼樣的資料是必須要被產出的,畫面與畫面之間要如何做承接的動作。只要把握一個原則,若是跟筆者一樣新手上路,一定都是先求有,再求好!!!!!
以上,其他的部份就不多說了,只是單純的資料面的操作,若是對 Struts Tags 有疑問的,可以去 http://struts.apache.org/release/2.3.x/docs/using-struts-2-tags.html 官方網頁去稍微複習一下,這整個範例並未將Struts 與其他後端的工具做結合,如 Mybatis / Hibernate ,若有需要相關資料,可以求助一下 Google 大神哦。
後面會附上範例的程式碼,其他部份若有信心的也可以自由發揮哦,當然也可以充分利用 ctrl+C ctrl+V 先看看做出來的成果是如何,再來看程式了解吧
原文網址 http://kuoshenghsu.blogspot.tw/2014/08/struts2-crud.html