從零寫一個Java WEB框架(二)Server層 優化
開篇
本篇針對專案中的Server層進行優化介紹。先來看看Server層的目前情況。
可以看到由於業務簡單。只有一個Server類。
以下是CustomerService類的靜態程式碼塊
以下是CustomerService類的其中一個方法
缺點:
- 將資料庫的載入是一個公共程式碼塊,應該提取出來,不應該寫在某個類中。
- Service 層是對業務邏輯的處理,但是在方法中,對查詢的結果進行了大量的操作。這樣使業務層的程式碼太過渾濁。應該講查詢結果的處理封裝起來。
程式碼實現
將Server層的對資料庫操作的程式碼提取出來
要求:
- 建立一個DatabaseUtil類 封裝對資料庫的載入
- 再建立兩個方法getConnection()獲取資料庫連線 和closeConnection() 關閉資料庫連線。
- 對資料庫操作的程式碼實現封裝起來
實現:
- 為了能更好地封裝JDBC的操作。這裡還使用了Apache Common專案中的DbUtils類庫,這個類庫可以更好地幫我處理資料庫資料。
- DatabaseUtil 類就實現了載入驅動,獲取連線,和對資料庫進行操作並對查詢結果進行處理,然後結果給Server層
程式碼如下:
public class DatabaseUtil {
private static final String DRIVER;
private static final String URL;
private static final String USERNAME;
private static final String PASSWORD;
// 利用Apache的一個工具庫DbUtils 對JDBC的封裝
private static final QueryRunner QUERY_RUNNER = new QueryRunner();
private static final Logger logger = LoggerFactory.getLogger(DatabaseUtil.class);
static{
System.out.println("配置載入");
Properties conf = PropsUtil.loadProps("config.properties");
DRIVER = conf.getProperty("jdbc.driver");
URL = conf.getProperty("jdbc.url");
USERNAME = conf.getProperty("jdbc.username");
PASSWORD = conf.getProperty("jdbc.password");
//JDBC流程第一步 載入驅動
try {
Class.forName(DRIVER);
} catch (ClassNotFoundException e) {
logger.error("載入jdbc驅動失敗",e);
e.printStackTrace();
}
}
public static Connection getConnection() {
try {
Connection connection = DriverManager.getConnection(URL, USERNAME, PASSWORD);
return connection;
} catch (SQLException e) {
logger.error("獲取連線失敗",e);
e.printStackTrace();
}
return null;
}
public static void closeConnection(Connection connection) {
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
logger.error("關閉連線失敗",e);
e.printStackTrace();
}
}
}
/**
* 查詢獲取實體列表
* @param entityClass 返回物件
* @param sql 查詢語句
* @param params 查詢條件
*
*
*/
public static <T> List<T> queryEntityList(Class<T> entityClass,String sql, Object... params) {
List<T> entityList = null;
Connection con = null;
try {
con = getConnection();
entityList =
QUERY_RUNNER.query(con, sql, new BeanListHandler<T>(entityClass), params);
} catch (SQLException e) {
logger.error("查詢失敗",e);
e.printStackTrace();
}finally {
closeConnection(con);
}
return entityList;
}
/**
* 查詢實體
* @param tClass
* @param sql
* @param params
* @param <T>
* @return
*/
public static <T> T queryEntity(Class<T> tClass, String sql, Object... params) {
T entity = null;
Connection con = null;
try {
con = getConnection();
entity =
QUERY_RUNNER.query(con, sql, new BeanHandler<T>(tClass), params);
} catch (SQLException e) {
logger.error("查詢失敗",e);
e.printStackTrace();
}finally {
closeConnection(con);
}
return entity;
}
/**
* 執行查詢語句
* 返回一個List物件。Map 表示列名與列值得對映關係
* @param sql
* @param params
* @return
*/
public static List<Map<String, Object>> executeQuery(String sql, Object... params) {
List<Map<String,Object>> entity = null;
Connection con = null;
try {
con = getConnection();
entity =
QUERY_RUNNER.query(con, sql, new MapListHandler(), params);
} catch (SQLException e) {
logger.error("查詢失敗",e);
e.printStackTrace();
}finally {
closeConnection(con);
}
return entity;
}
/**
* 執行更新語句(update,insert,delete)
* @param sql
* @param params
* @return
*/
public static int executeUpdate(String sql, Object... params) {
int rows=0;
Connection con = null;
try {
con = getConnection();
rows =
QUERY_RUNNER.update(con, sql, new MapListHandler(), params);
} catch (SQLException e) {
logger.error("查詢失敗",e);
e.printStackTrace();
}finally {
closeConnection(con);
}
return rows;
}
/**
* 插入實體
* @param entityClass
* @param filedMap
* @param <T>
* @return
*/
public static <T> boolean insertEntity(Class<T> entityClass, Map<String, Object> filedMap) {
/*
* 1. 判斷filedMap是否為空
* 2. 對Map遍歷,拼接sql語句
* 3. 執行語句
* */
if (MapUtils.isEmpty(filedMap)) {
logger.error("插入實體失敗,實體Map為空");
return false;
}
Iterator<String> iterator = filedMap.keySet().iterator();
StringBuffer columns = new StringBuffer("(");
StringBuffer values = new StringBuffer("(");
String sql=("insert into" + entityClass.getSimpleName());
while (iterator.hasNext()) {
String key = iterator.next();
columns.append(key).append(", ");
values.append("?, ");
}
// 刪除最後一個 , 然後加上 )
columns.replace(columns.lastIndexOf(", "), columns.length(), ")");
values.replace(values.lastIndexOf(", "), values.length(), ")");
sql += columns + " values " + values;
Object[] params = filedMap.values().toArray();
return executeUpdate(sql,params)==1;
}
public static <T> boolean updateEntity(Class<T> entityClass, long id, Map<String, Object> fieldMap) {
//TODO
return false;
}
public static <T> boolean deleteEntity(Class<T> entityClass, long id) {
String sql = "Delete From " + entityClass.getSimpleName() + " Where id = ?";
return executeUpdate(sql, id) == 1;
}
}
重建Server層
在構建了DatabaseUtil類後,Server層的程式碼如下:
/*
* 提供客戶資料服務
* */
public class CustomerService {
private static final Logger logger = LoggerFactory.getLogger(CustomerService.class);
/*
* 獲取客戶列表
* */
public List<Customer> getCustomerList() {
String sql = "select * from customer";
List<Customer> list = DatabaseUtil.queryEntityList(Customer.class, sql, null);
return list;
}
/*
* 獲取客戶
* */
public Customer getCustomer(long id) {
String sql = "select * from customer where id = ?";
return DatabaseUtil.queryEntity(Customer.class, sql, id);
}
/*
* 建立客戶
* */
public boolean createCustomer(Map<String,Object> fieldMap) {
return DatabaseUtil.insertEntity(Customer.class,fieldMap);
}
/*
* 更新客戶
* */
public boolean updateCustomer(long id,Map<String,Object> fieldMap) {
//TODO
return false;
}
/*
* 刪除客戶
* */
public boolean deleteCustomer(long id) {
return DatabaseUtil.deleteEntity(Customer.class, id);
}
}
可以看到Server層的程式碼非常簡潔,這樣就可以開心地寫業務邏輯程式碼了。而不需要對資料庫的操作操心了。
缺陷
雖然Server層是非常的簡潔,舒服。但是相對地,又建立了一個數據層。在這個剛建立的資料層上,顯然還是有很多不足的。
- 在getConnection()和closeConnection()上,每次呼叫資料庫操作,都需要重新連線資料庫和關閉資料庫,這樣的消耗很大。
總結
竟然我們已經把資料庫處理這一塊跨分到一個層了。那麼我們就應該對這一塊有一個更好地優化才行。比如資料庫連線池 就是以後需要優化的一個點。