完整JavaWeb專案筆記 第二部分-專案結構及Bean和Dao設計
阿新 • • 發佈:2018-12-24
文章目錄
一 服務端專案結構
Java開發工具我用的是Eclipse,配置完Maven後,建立的war工程,接下來就是專案目錄結構的劃分,這一點的重要性說來可大可小,結構清晰,則開發更加順利,結構不合理則變動會比較頻繁,對於體量較小的專案而言雖然影響不大,但是出於習慣的考慮,還是對結構進行下劃分:
- bean包中為資料表對應的Java類;
- common中放置專案中其他類引用的公用設計;
- dao包中放置兩部分,一個是資料訪問介面設計,一個是介面實現;
- filter包中放置Servlet請求過濾器;
- service包為服務層設計,所有的業務邏輯實現都在這裡;
- servlet包下為所有處理請求的Servlet實現類;
- util包下則為各類公用函式的實現。
二 表結構設計
資料表設計不細說了,簡簡單單幾張表,大致看一下對應的Bean就差不多,這裡不涉及任何技術問題。但是需要注意的是,表及表字段的命名必須遵守規範,合理的命名規範對於未來可能出現的重構、其他需求而言及其重要,附上Navicat的截圖:
三 bean設計
這裡再提一嘴,所有的bean需要有較為嚴格的結構設計:
- 除和表字段對應的成員屬性(私有訪問許可權),必須有一一對應的屬性訪問器(getter、setter方法);
- 如果有特殊的物件建立需求,則除特殊的建構函式外,必須保留預設的無引數構造;
- 必須要重寫equals、hashCode方法,方法重寫一般使用表主鍵欄位作為主要判斷邏輯,重寫是為了滿足業務邏輯上的等值判斷;
- 儘量重寫toString方法,以便設計時進行日誌列印、打樁除錯的資訊輸出。
- 需要注意的是bean屬性未必需要和表字段結構一一對應,比如說自增欄位,雖然常被設定為主鍵,但是為了方便未來的拆表及資料遷移,我們還是會使用UUID作為其唯一索引,這種情況下自增id欄位就沒有必要做為bean的屬性存在,其查詢邏輯中也不應該使用。
附上大致的設計:
- Module為帖子的分類,學習、工作、兩性什麼的;
- Topic為帖子的結構,包括帖子的標題、內容;
- TopicReply為帖子的回覆內容,包括回覆人id、回覆時間等;
- TopicInof則為帖子的附加資訊,回覆數量、發表時間、作者等資訊;
- User為使用者資訊,包括使用者的賬號、密碼等;
- UserSession為使用者會話資訊,包括登陸時間、token有效期等。
以Module為例:
package com.bubbling.bean;
import java.util.Date;
public class Module
{
private String name;
private String description;
private Date creatime;
private Date updatime;
public Module()
{
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public String getDescription()
{
return description;
}
public void setDescription(String description)
{
this.description = description;
}
public Date getCreatime()
{
return creatime;
}
public void setCreatime(Date creatime)
{
this.creatime = creatime;
}
public Date getUpdatime()
{
return updatime;
}
public void setUpdatime(Date updatime)
{
this.updatime = updatime;
}
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj)
{
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Module other = (Module) obj;
if (name == null)
{
if (other.name != null)
return false;
}
else if (!name.equals(other.name))
return false;
return true;
}
@Override
public String toString()
{
return "Module [name=" + name + ", description=" + description + ", creatime=" + creatime + ", updatime="
+ updatime + "]";
}
}
三 Dao設計
Dao層為資料訪問介面,我們所有的設計要儘量面向介面,雖然當下我們的實現採用的是Mysql資料庫,且實現為JDBC的方式,但是難保以後不會有實現上的改變,如果有,那麼介面的意義就大了,對應用設計來說,整體結構無需任何變化,僅介面實現改變即可。
對Dao的設計,需要充分考慮應用對錶資料的訪問需求,不能一味的按增刪改查需求設計,而對於MVC分層結構的設計來說,對請求的業務處理應該交由服務層實現,也就是說Service應該是Dao的使用大戶,那麼Dao的介面設計就應該主要考慮Service的實現需求。
Dao也不多說,對於這個專案而言,主要就三個資料訪問需求:
- Module,模組
- Topic,帖子
- User,使用者
貼一張參考圖:
以ModuleDao為例,介紹下介面定義及其實現:
package com.bubbling.dao;
import java.util.List;
import com.bubbling.bean.Module;
public interface ModuleDao
{
public boolean addModule(String name, String description);
public Module getModuleByUuid(String uuid);
public List<Module> getModuleList();
}
ModuleDaoMysqlImpl實現:
package com.bubbling.dao.impl.mysql;
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.bubbling.bean.Module;
import com.bubbling.dao.ModuleDao;
import com.bubbling.util.DatabaseUtil;
public class ModuleDaoMysqlImpl implements ModuleDao
{
private static final String SqlAddModule = "INSERT INTO module ( `uuid`, `name`, `description`, `creatime` ) VALUES ( REPLACE (UUID(), '-', ''), ?, ?, NOW())";
@Override
public boolean addModule(String name, String description)
{
Connection conn = null;
PreparedStatement st = null;
boolean ret = false;
int index = 1;
try
{
conn = DatabaseUtil.getConnection();
st = conn.prepareStatement(SqlAddModule);
st.setString(index++, name);
st.setString(index++, description);
int i = st.executeUpdate();
if (i > 0)
{
ret = true;
}
}
catch (SQLException e)
{
e.printStackTrace();
}
finally
{
DatabaseUtil.close(conn, st);
}
return ret;
}
private static final String SqlGetModuleByUuid = "SELECT `name`, `description` FROM module WHERE uuid = ?";
@Override
public Module getModuleByUuid(String uuid)
{
Connection conn = null;
PreparedStatement st = null;
ResultSet rs = null;
Module module = null;
int index = 1;
try
{
conn = DatabaseUtil.getConnection();
st = conn.prepareStatement(SqlGetModuleByUuid);
st.setString(index++, uuid);
rs = st.executeQuery();
if (rs.next())
{
module = new Module();
module.setName(rs.getString("name"));
module.setDescription(rs.getString("description"));
}
}
catch (SQLException e)
{
e.printStackTrace();
}
finally
{
DatabaseUtil.close(conn, st, rs);
}
return module;
}
private static final String SqlGetModuleList = "SELECT `name`, `description` FROM module";
@Override
public List<Module> getModuleList()
{
Connection conn = null;
PreparedStatement st = null;
ResultSet rs = null;
List<Module> ret = new ArrayList<>();
try
{
conn = DatabaseUtil.getConnection();
st = conn.prepareStatement(SqlGetModuleList);
rs = st.executeQuery();
while (rs.next())
{
Module module = new Module();
module.setName(rs.getString("name"));
module.setDescription(rs.getString("description"));
ret.add(module);
}
if (ret.size() == 0)
{
ret = null;
}
}
catch (SQLException e)
{
e.printStackTrace();
}
finally
{
DatabaseUtil.close(conn, st, rs);
}
return ret;
}
}
注意,上例中資料庫連線的獲取及關閉定義在了DatabaseUtil中,資料庫方面設計將在第三部分介紹,資料庫連線池採用阿里的Druid,資料來源配置採用JNDI。