1. 程式人生 > >從零寫一個Java WEB框架(二)Server層 優化

從零寫一個Java WEB框架(二)Server層 優化

  • 該系列,其實是對《架構探險》這本書的實踐。本人想記錄自己的學習心得所寫下的。
  • 從一個簡單的Servlet專案開始起步。對每一層進行優化,然後形成一個輕量級的框架。
  • 每一篇,都是針對專案的不足點進行優化的。
  • 專案已放上github
  • 上一篇地址:上一篇

開篇

本篇針對專案中的Server層進行優化介紹。先來看看Server層的目前情況。
image.png
可以看到由於業務簡單。只有一個Server類。
以下是CustomerService類的靜態程式碼塊
image.png

以下是CustomerService類的其中一個方法
image.png

缺點:
- 將資料庫的載入是一個公共程式碼塊,應該提取出來,不應該寫在某個類中。
- Service 層是對業務邏輯的處理,但是在方法中,對查詢的結果進行了大量的操作。這樣使業務層的程式碼太過渾濁。應該講查詢結果的處理封裝起來。

程式碼實現

將Server層的對資料庫操作的程式碼提取出來

要求:
- 建立一個DatabaseUtil類 封裝對資料庫的載入
- 再建立兩個方法getConnection()獲取資料庫連線 和closeConnection() 關閉資料庫連線。
- 對資料庫操作的程式碼實現封裝起來

實現:
- 為了能更好地封裝JDBC的操作。這裡還使用了Apache Common專案中的DbUtils類庫,這個類庫可以更好地幫我處理資料庫資料。
- DatabaseUtil 類就實現了載入驅動獲取連線,和對資料庫進行操作並對查詢結果進行處理,然後結果給Server層

的3個主要功能。

程式碼如下:


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()上,每次呼叫資料庫操作,都需要重新連線資料庫和關閉資料庫,這樣的消耗很大。

總結

竟然我們已經把資料庫處理這一塊跨分到一個層了。那麼我們就應該對這一塊有一個更好地優化才行。比如資料庫連線池 就是以後需要優化的一個點。