最課程階段大作業04:毫無用處的學生管理系統


前面幾期就業班學生知道,我在做簡歷指導時說過:如果你的簡歷中項目經歷寫的是“學生管理系統”、“**辦公自動化”這樣的系統,那么就等於告訴面試官:你沒有項目經驗。

對於面試找工作,學生管理系統這樣的項目簡直毫無用處,甚至是減分項。如果你一定要說你實現了一個NB的學生管理系統,那么就需要拿出你在GITHUB上的源碼來,並對面試官說:我已經把它做成了一個框架,以后所有的用戶管理系統都可以基於這個框架進行擴展~~

學生管理系統對於找工作毫無用處,但對於當前的我們來說,倒是一個好的案例。如果說HelloWorld是我們學習Java的第一個程序,那么學生系統則應該說是我們在做項目時的HelloWorld。

它,簡單,直觀。即使再笨,我們也能切身知道其中的業務邏輯。

為什么?因為現階段我們剛學完MySql+JDBC,迫切需要做一個真實的案例來檢驗和鞏固學習的知識,那么這個簡單的Mis系統再合適不過了。

如果能獨立完成該MIS系統,那意味着我們可以做最基礎的增刪改查(CRUD)了。不過,僅僅用這個案例來完成CRUD的工作,有點太浪費這次練習的時間了,我們不妨稍稍提升下B格:做一個三層架構的CRUD。

 

實現取數據

先假設數據庫中已經存在學生表,現在要用java代碼把所有的學生全部取出來並顯示到前台,該怎么做?

按照以前的寫法,我們會這樣去實現(使用了c3p0和DbUtils,配置文件及附屬代碼略):

package com.zuikc.usermanagement;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.ResultSetHandler;

public class IndexPage {
    public static void main(String[] args) throws SQLException {
        QueryRunner qr = new QueryRunner(C3P0Util.getDataSource());
        List<User> users = qr.query("select * from user_tb", new ResultSetHandler<List<User>>(){

            @Override
            public List<User> handle(ResultSet rs) throws SQLException {
                List<User> list = new ArrayList<User>();
                while(rs.next()){
                    User user = new User();
                    user.setUsername(rs.getObject("username").toString());
                    System.out.println(user.getUsername());
                    list.add(user);
                }
                return list;
            }});

    }
}

 

順便附上整個項目結構:

但緊接着問題來了,現在需求變更為:將用戶列表從數據庫取出來導出到文件中~~。

有同學說,這好辦,讓我們修改代碼:

List<User> list = new ArrayList<User>();
                try {
                    FileWriter writer = new FileWriter("c:\\temp\\temp.txt");
                    while (rs.next()) {
                        User user = new User();
                        user.setUsername(rs.getObject("username").toString());
                        //System.out.println(user.getUsername());
                        writer.write(user.getUsername() + "\n");
                        list.add(user);
                    }
                    
                    writer.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                return list;

 

看上去,問題解決了。但是緊接着問題又來了,讓我們把結果輸出到網頁中或者socket傳輸到另一台電腦中。怎么辦?

難道我們只要有新需求,就去改這個while循環嗎?

不知道大家有沒有發現,無論我們的輸出怎么變化,我們的“獲取數據”這部分的代碼實際上從來沒有變過。

沒有變過的代碼能不能將它隔離開來放到某個層中呢?答案當然是可以的,這種手法就叫做:分層架構的設計思想。

 

什么是三層架構

所謂架構,指的是一種編碼的思想,一種指導我們將代碼寫的更加優美的思想。三層架構是最早出現的軟件架構設計思想之一,它用於指導我們將代碼歸置的更整潔,以便我們完成更龐大的系統。

最原始的分層架構,叫做:三層架構(表示層、業務邏輯層、數據訪問層)。每層的作用如下:

01.表示層(User Interface layer):如果光看英文,直譯過來是:用戶接口層。也就是說,這個層專門負責接收用戶的輸入,將輸出呈現給用戶。另外,輸入輸出過程中的訪問安全性驗證、輸入的數據的正確性驗證也由這個層負責。

02.業務邏輯層(Business Logic Layer):負責系統業務邏輯的處理。它也包括對所輸入的邏輯性數據的正確性及有效性的負責。有人可能要問,UI層不是已經負責了正確性嗎,為什么業務邏輯層也要負責?答案是:因項目而異。在部分項目中,需要將正確性驗證等功能放置在UI層,而在有些項目中,則在業務邏輯層,甚至有些項目,兩個層都要做。

03.數據訪問層(Data Access Layer):數據訪問層的功能較為單一,它負責與數據源的交互,即數據的插入,刪除,修改,以及從數據庫中讀出數據等操作,但對數據的正確性和有效性不負責,對業務邏輯不負責。

結束了嗎?其實並沒有,以上是最主要的三層,實際還有有些輔助的層,如:

04 工具層

通用類庫,比如一些工具類就可以放在這里。這些工具類最簡單的可以是檢驗email是否符合規則,也可以是加密解密工具類,同時,數據庫連接幫助類也放在這里。

05實體層

比如,上文代碼中的User類,就是一個實體類。它很大程度上是數據庫表字段在Java語言中的對應。

以上,基本上就差不多了。它們的主要依賴關系如下:

接下來,讓我們改造代碼以便符合三層架構。

其中,

表示層:com.zuikc.usermanagement.ui

業務邏輯層:com.zuikc.usermanagement.biz

數據訪問層:com.zuikc.usermanagement.dao

工具層:com.zuikc.usermanagement.common

實體層:com.zuikc.usermanagement.bean

從上層到下層的代碼依次為:

表示層,IndexPage:

package com.zuikc.usermanagement.ui;

import java.util.List;
import com.zuikc.usermanagement.bean.User;
import com.zuikc.usermanagement.biz.UserService;

public class IndexPage {
    public static void main(String[] args) throws Exception {
        
        UserService service = new UserService();
        List<User> users = service.getAllUsers();
        for (User user : users) {
            System.out.println(user.getUsername());
        }
    }
}

 

業務邏輯層,UserService:

package com.zuikc.usermanagement.biz;

import java.sql.SQLException;
import java.util.List;

import com.zuikc.usermanagement.bean.User;
import com.zuikc.usermanagement.dao.UserDao;

public class UserService {
    UserDao dao = new UserDao();
    
    public List<User> getAllUsers() throws SQLException{
        List<User> users = dao.queryUsers();
        return users;
    }
}

 

數據訪問層,UserDao:

package com.zuikc.usermanagement.dao;

import java.io.FileWriter;
import java.io.IOException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.ResultSetHandler;

import com.zuikc.usermanagement.bean.User;
import com.zuikc.usermanagement.common.C3P0Util;

public class UserDao {
    public List<User> queryUsers() throws SQLException {
        QueryRunner qr = new QueryRunner(C3P0Util.getDataSource());
        List<User> users = qr.query("select * from user_tb", new ResultSetHandler<List<User>>() {

            @Override
            public List<User> handle(ResultSet rs) throws SQLException {
                List<User> list = new ArrayList<User>();
                while (rs.next()) {
                    User user = new User();
                    user.setUsername(rs.getObject("username").toString());
                    list.add(user);
                }

                return list;
            }
        });

        return users;
    }
}

 

工具層,C3P0Util:

package com.zuikc.usermanagement.common;


import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import javax.sql.DataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;

public class C3P0Util {
    // 得到數據源
    private static DataSource dataSource = new ComboPooledDataSource();

    public static DataSource getDataSource() {
        return dataSource;
    }

    // 得到連接對象
    public static Connection getConnection() {
        try {
            return dataSource.getConnection();
        } catch (SQLException e) {
            throw new RuntimeException("獲取連接失敗");
        }
    }

    public static void release(Connection conn, Statement stmt, ResultSet rs) {
        if (rs != null) {
            try {
                rs.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
            rs = null;
        }
        if (stmt != null) {
            try {
                stmt.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
            stmt = null;
        }
        if (conn != null) {
            try {
                conn.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
            conn = null;
        }
    }

}

 

實體層,User:

package com.zuikc.usermanagement.bean;

public class User {
    String username;
    String password;
    
    public User() {
    }
    public User(String username, String password) {
        super();
        this.username = username;
        this.password = password;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
}

 

最后放上一個c3p0的配置文件c3p0-config.xml,

<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
  <default-config>
    <property name="driverClass">com.mysql.jdbc.Driver</property>
    <property name="jdbcUrl">jdbc:mysql://localhost:3317/test</property>
    <property name="user">root</property>
    <property name="password">root</property>
    <property name="initialPoolSize">10</property>
    <property name="maxIdleTime">30</property>
    <property name="maxPoolSize">100</property>
    <property name="minPoolSize">10</property>
  </default-config>
</c3p0-config>

 

三層架構的優缺點

優點: 

1、在某種架構下,某些開發人員可以只關注整個結構中的其中某一層;

2、可以很容易的用新的實現來替換原有層次的實現(后面要學的動態代理、spring等);

3、可以降低層與層之間的依賴;

4、有利於標准化;

5、利於各層邏輯的復用。

6、擴展性強。不同層負責不同層次的代碼。

7、安全性高。用戶端只能通過邏輯層來訪問數據層,減少了入口點,把很多危險的系統功能都屏蔽了。

8、項目結構更清楚,分工更明確,有利於后期的維護和升級 

缺點:

1、降低了系統的性能。分層之后,會增加代碼,有些地方看上去僅僅就是service層封裝了一下dao層。代碼增加,意味着性能降低。

2、可能存在級聯的修改。為了增加某個功能,相應的要去增加service和dao。

3、增加了代碼量,增加了工作量

 

更進一步的三層架構?

聰明的同學可能已經發現,分層的“層”這個概念在當前這個java項目中對應的就是包(package)的概念。那是不是永遠是這樣的呢?

並不是。層的概念,更多的是project的概念。在大型項目中,一個層就是一個project,就是一個jar包。

我們可以繼續改造我們的三層架構代碼,看下圖:

在這個過程中,我們將每個層都獨立成為了一個Project了。如果大家仔細觀察,我們會發現,上層service和ui層,壓根就沒有依賴數據庫的那幾個第三方包。在實際的開發中,其實也是這樣:

作為UI層的,可能是一個動態網頁,可能是手機APP端的,對於它們來說,實際上它們不應該,也不需要知道我們的數據是來自於數據庫還是來自於其它地方。對於它們來說,只需要知道:我現在需要一個用戶列表,於是底層就給了它一個用戶列表。仔細回味一下這句話。

上層所依賴的只是下層的包:

UI層,依賴com.zuikc.usermanagement.biz, com.zuikc.usermanagement.bean, com.zuikc.usermanagement.common;

Service層,依賴com.zuikc.usermanagement.dao,com.zuikc.usermanagement.bean,com.zuikc.usermanagement.common;

Dao層,依賴com.zuikc.usermanagement.bean,com.zuikc.usermanagement.common;

Bean層,誰都不依賴(可以依賴common),被誰都依賴;

Common,誰都不依賴,被誰都依賴;

有同學可能對於project依賴另一個project不熟悉,下面給出圖示:

第一步,

第二步,

第三步,

以上,我們完成了一個最徹底的三層架構的解決方案。

 

作業之用例

有了上面的知識儲備,現在引出我們的大作業。

 

1.主界面

 

2.添加用戶

 

3.用戶列表

 

4.用戶查詢

 

5.用戶刪除

 

作業之要求

 

 

華麗分割線

===========================================================

最課程JavaEE+互聯網分布式新技術開班進行中,來http://www.zuikc.com

看看吧。你想參加不一樣的培訓班,並且一畢業就NB,那就來加入我們吧;

更多技術文章和開班信息請加入,

QQ群:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM