Java開發專案2_個人記賬軟體
帥帥個人賬務管理專案說明
專案功能
檢視賬務
多條件組合檢視賬務
增加賬務
編輯賬務
刪除賬務
匯出賬務
表結構
CREATE TABLE personal_zhangwu ( zwid INT PRIMARY KEY AUTO_INCREMENT, flname VARCHAR(200), money DOUBLE, zhangHu VARCHAR(100), createtime DATE, description VARCHAR(1000) ); INSERT INTO personal_zhangwu(zwid,flname,money,zhangHu,createtime,description) VALUES (1,'支出-餐費',247,'中國銀行','2017-03-02','家庭聚餐'); INSERT INTO personal_zhangwu(zwid,flname,money,zhangHu,createtime,description) VALUES (2,'收入-工資',12345,'現金','2017-03-15','發工資'); INSERT INTO personal_zhangwu(zwid,flname,money,zhangHu,createtime,description) VALUES (3,'支出-服裝',1998,'現金','2017-04-02','買衣服'); INSERT INTO personal_zhangwu(zwid,flname,money,zhangHu,createtime,description) VALUES (4,'支出-餐費',325,'現金','2017-06-18','朋友聚餐'); INSERT INTO personal_zhangwu(zwid,flname,money,zhangHu,createtime,description) VALUES (5,'收入-股票',8000,'建設銀行','2017-10-28','股票賺錢'); INSERT INTO personal_zhangwu(zwid,flname,money,zhangHu,createtime,description) VALUES (6,'收入-股票',5000,'建設銀行','2017-10-28','股票賺錢'); INSERT INTO personal_zhangwu(zwid,flname,money,zhangHu,createtime,description) VALUES (7,'收入-工資',5000,'中國銀行','2017-10-28','發工資'); INSERT INTO personal_zhangwu(zwid,flname,money,zhangHu,createtime,description) VALUES (8,'支出-禮金',5000,'現金','2017-10-28','朋友結婚'); INSERT INTO personal_zhangwu(zwid,flname,money,zhangHu,createtime,description) VALUES (9,'支出-其他',1560,'現金','2017-10-29','丟錢了'); INSERT INTO personal_zhangwu(zwid,flname,money,zhangHu,createtime,description) VALUES (10,'支出-交通',2300,'中國銀行','2017-10-29','油價上升'); INSERT INTO personal_zhangwu(zwid,flname,money,zhangHu,createtime,description) VALUES (11,'支出-餐費',1000,'建設銀行','2017-10-29','吃飯'); INSERT INTO personal_zhangwu(zwid,flname,money,zhangHu,createtime,description) VALUES (12,'收入-工資',1000,'現金','2017-10-30','發工資'); INSERT INTO personal_zhangwu(zwid,flname,money,zhangHu,createtime,description) VALUES (13,'支出-交通',2000,'現金','2017-10-30','外出旅遊機票');
功能展示
主選單
檢視賬務
查詢所有
帶分頁顯示,預設每頁顯示10條記錄。
只可往下一頁翻,不可上翻,提示使用者,按空格鍵,顯示下一頁。
當檢視到最後一頁後,顯示統計資訊(見後面說明)。
當檢視到最後一頁後,顯示功能選單選項。
統計資訊包括:總收入,總支出,總收入-總支出,每種支出的總金額,每種收入的總支出(收入和支出按金額從大到小排序)。
統計資訊的計算要使用到group by 。
統計資訊顯示樣例:
總支出: 8800.0, 總收入: 6000.0,淨收入:-2800.0
收入統計:
收入-工資 5000.0
收入-股票 1000.0
支出統計:
支出-禮金 3800.0
支出-餐費 3000.0
支出-交通 1000.0
支出-其他 1000.0
條件查詢
帶分頁顯示。
只可往下一頁翻,不可上翻,提示使用者,按空格鍵,顯示下一頁。
當檢視到最後一頁後,顯示統計資訊。
當檢視到最後一頁後,顯示功能選單選項。
修改賬務
增加賬務
刪除賬務
匯出賬務記錄
在專案中,嵌入一個TCP server,用於接受客戶端的匯出請求。
再編寫一個單獨的TCP客戶端程式,執行此程式,可以向TCP Server發出匯出請求。
TCP SERVER收到客戶端請求後,從資料庫中讀取所有賬務記錄,按照賬務時間後先順序排序,然後把這些記錄返回給客戶端。
客戶端接收到伺服器端的資料後,把資料寫入本地檔案。
檔案中的格式與內容與“檢視賬務”介面上顯示的格式和內容一樣。
伺服器端要記錄匯出日誌到檔案,日誌檔名為export.log,日誌檔案格式樣例:
匯出總次數: 88,成功次數:77
20181017-10:33:22 192.168.10.66 匯出成功
20181017-10:36:33 127.0.0.1 匯出失敗,非法客戶端
20181022-09:10:12 192.168.10.77 匯出成功
…
記錄日誌檔案是,要避免多個客戶端同時匯出是日誌記錄的併發問題。
伺服器端監聽埠從配置檔案server.ini讀取,配置檔案中還包括客戶端白名單,只有白名單中的客戶端才能匯出。
合法的和非法的客戶端連線時,伺服器端要返回相應的資訊給客戶端,客戶端由此資訊來判斷是否可以匯出。
server.ini格式如下:
port=8888
ips=192.168.10.66,127.0.0.1,192.168.10.77
專案環境搭建
專案技術選型和jar包介紹
每個專案都要使用一些已經成熟的技術,它們通常是由一些專業組織或團隊所提供的開源免費技術。
在今後的學習過程中,我們會逐漸對這些專業組織有所瞭解。本專案中使用的技術如下:
c3p0-0.9.1.2.jar::資料庫連線池c3p0
commons-dbutils-1.4.jar:封裝並簡化了JDBC;
commons-logging-1.1.3.jar:c3p0依賴的包;
mchange-commons-java-0.2.3.4.jar:c3p0依賴的包;
mysql-connector-java-5.1.28-bin.jar:MySQL的JDBC驅動包,用JDBC連線MySQL資料庫必須使用該JAR包。
專案分層開發
分層原理
如果程式規模小,可以一個人全部完成,但當程式規模很大時,一個人難以完成,這時,要多人合作完成程式開發。
多人合作方式將會碰到工作任務分配問題,這時我們會想,每個人負責完成專案的一塊內容就可以了。那麼,這一塊塊內容的劃分,就需要我們採用分層(分包)的方式完成了。
以“使用者註冊功能”為例,來講解下,專案中常見的分層(分包)。
常用的分層層次包括:
view層: 檢視層,即專案中的介面
controller層: 控制層, 獲取介面上的資料,為介面設定資料; 將要實現的功能交給業務層處理
service層: 業務層, 功能的實現, 與controller控制層和資料訪問層DAO互動, 將對資料庫的操作交給DAO資料訪問層來處理
dao層: 資料訪問層, 用來操作資料庫表的資料
db資料庫: 這裡指MySQL
domain 實體包: 存放JavaBean
tools工具包:存放專案中使用到的工具類
test 測試包: 存放專案功能測試的程式碼
工程建立及包管理
- 使用Eclipse建立Java工程,命名為zwgl
- 建立工程包
cn.njit.gjp.app: 存放main方法類;
cn.njit.gjp.domain: 存放JavaBean;
cn.njit.gjp.view: 存放介面,及表現層類;
cn.njit.gjp.service: 存放業務層類;
cn.njit.gjp.dao: 存放資料訪問層類;
cn.njit.gjp.tools:存放工具類 - 建立lib資料夾,用來儲存使用的jar包
各個包結構
- 在app包中,建立類MainApp.java,編寫main主方法,用來完成本專案的啟動。
- 在domain包中,建立類ZhangWu.java,它是用來封裝賬務資訊的JavaBean。
- 在dao包中,建立類ZhangWuDao.java,給ZhangWuDao類新增一個成員變數QueryRunner物件,因為我們使用dbutils來操作資料庫。
- 在service包中,建立類ZhangWuService.java,給ZhangWuService類新增一個型別為ZhangWuDao的成員變數,因為service依賴dao。
- 在view包中,建立類MainView.java,給MainView類新增一個型別為ZhangWuService的成員變數,因為本專案中view依賴service。
開發步驟:
- 首先先在工程下建立lib包,並且把5個驅動包匯入工程;
c3p0-0.9.1.2.jar::資料庫連線池c3p0
commons-dbutils-1.4.jar:封裝並簡化了JDBC;
commons-logging-1.1.3.jar:c3p0依賴的包;
mchange-commons-java-0.2.3.4.jar:c3p0依賴的包;
mysql-connector-java-5.1.28-bin.jar:MySQL的JDBC驅動包,用JDBC連線MySQL資料庫必須使用該JAR包。
- 然後開始構建專案框架,這個專案採用標準的MVC開發,一共8個包,分別存放了:
主函式
控制層
實現層
實體類
tcp網路服務
服務層
工具類
表示層 - 接著進行使用連線池的準備:配置xml以及編寫JDBCUtils
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<default-config>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/njit?useUnicode=true&characterEncoding=utf8
</property>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="user">root</property>
<property name="password">admin</property>
<property name="checkoutTimeout">30000</property>
<property name="idleConnectionTestPeriod">30</property>
<property name="initialPoolSize">10</property>
<property name="maxIdleTime">30</property>
<property name="maxPoolSize">100</property>
<property name="minPoolSize">10</property>
<property name="maxStatements">200</property>
</default-config>
</c3p0-config>
package cn.njit.gjp.tools;
import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class JDBCUtils {
static private DataSource ds=new ComboPooledDataSource();
public static DataSource getDataSource() {
return ds;
}
static public Connection getConnection() {
try {
return ds.getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
}
-
mainview.java
package cn.njit.gjp.view; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Scanner; import cn.njit.gjp.controller.ZhangWuController; import cn.njit.gjp.entity.PageBean; import cn.njit.gjp.entity.ZhangWu; import cn.njit.gjp.ser.ChatServer; import cn.njit.gjp.ser.Server; import cn.njit.gjp.tools.DataUtils; import cn.njit.gjp.tools.DateUtils; /*** * 介面顯示類 * @author Liu * */ public class MainView implements Runnable{ private ZhangWuController controller = new ZhangWuController(); public void run() { /*Server server=new Server(); Thread t=new Thread(server, "服務端"); t.start();*/ Scanner sc = new Scanner(System.in); while (true) { System.out.println("---------------帥帥個人記賬軟體---------------"); System.out.println("1.增加賬務 2.修改賬務 3.刪除賬務 4.檢視賬務 5.登出系統"); System.out.println("請選擇要操作的功能序號[1-5]:"); // 接收使用者的選單選擇 String choose = sc.next(); int mm = 0; try { mm = Integer.parseInt(choose); } catch (NumberFormatException e) { System.out.println("請輸入1-5!"); continue; } switch (mm) { case 1: // 選擇新增賬務,呼叫新增賬務的方法 addZhangWu(); break; case 2: // 選擇的編輯賬務,呼叫編輯賬務方法 editZhangWu(); break; case 3: // 選擇的刪除賬務,呼叫刪除賬務方法 deleteZhangWu(); break; case 4: // 選擇的是查詢賬務,呼叫查詢方法 selectZhangWu(); break; case 5: System.exit(0); break; default: System.out.println("請輸入1—5!"); break; } } } /*** * 二級查詢介面 */ public void selectZhangWu() { // 查詢2級介面 System.out.println("1.查詢所有 2.條件查詢3.返回上一級"); Scanner sc = new Scanner(System.in); while (true) { String choose = sc.next(); int mm = 0; try { mm = Integer.parseInt(choose); } catch (NumberFormatException e) { System.out.println("請輸入1、2或者3!"); continue; } switch (mm) { case 1: selectAll(); break; case 2: conditionSelectZhangwu(); break; case 3: run(); break; default: System.out.println("請輸入1、2或者3!!"); break; } } } public void conditionSelectZhangwu() { // 條件查詢 System.out.println("選擇的條件查詢,請輸入日期格式:XXXX-XX-XX"); Scanner sc = new Scanner(System.in); System.out.println("請輸入開始日期:"); String begin = sc.next(); while(!DataUtils.verifyDate(begin)) { System.out.println("請重新輸入開始日期!"); begin = sc.next(); } System.out.println("請輸入截至日期:"); String end = sc.next(); while(!DataUtils.verifyDate(end)) { System.out.println("請重新輸入截至日期!"); end = sc.next(); } if(DateUtils.Dateyyyy_MM_dd_time(end).before((DateUtils.Dateyyyy_MM_dd_time(begin)))) { System.out.println("日期先後錯誤!"); System.out.println("請輸入開始日期:"); begin = sc.next(); while(!DataUtils.verifyDate(begin)) { System.out.println("請重新輸入開始日期!"); begin = sc.next(); } System.out.println("請輸入截至日期:"); end = sc.next(); while(!DataUtils.verifyDate(end)) { System.out.println("請重新輸入截至日期!"); end = sc.next(); } } PageBean<ZhangWu> page = new PageBean<ZhangWu>(); page.setPageNumber(1); page.setPageSize(4); page = controller.conditionSelectZhangwu(begin,end,page); System.out.println("輸入空格翻頁"); String m = sc.nextLine(); int count=1; while (true) { if (m.equals(" ")) { if (count >= page.getPageCount()) { controller.getTotal(); System.out.println("輸入3返回上一級!"); break; } else { count++; System.out.println("翻頁"); page.setPageNumber(count); } } else { System.out.println(""); } page = controller.conditionSelectZhangwu(begin,end,page); System.out.println("ID\t類別\t賬戶\t金額\t時間\t\t說明"); for (ZhangWu z : page.getData()) { System.out.println(z.toString()); } System.out.println("第" + page.getPageNumber() + "頁;共" + page.getPageCount() + "頁。"); System.out.println("------------------"); m = sc.nextLine(); } } public void deleteZhangWu() { // 刪除 // 呼叫查詢所有賬務資料的功能,顯示出來--- showAll(); // ------------------- Scanner sc=new Scanner(System.in); System.out.println("選擇的刪除賬務,請輸入"); int id=sc.nextInt(); int cnt=controller.deleteZhangWu(id); if(cnt>0) { System.out.println("刪除成功"); }else { System.out.println("刪除失敗"); } } public void editZhangWu() { // 修改 // 呼叫查詢所有賬務資料的功能,顯示出來--- showAll(); // ------------------- System.out.println("選擇的是編輯功能,請輸入"); Scanner sc=new Scanner(System.in); //----------------------- System.out.println("請輸入ID:"); String id=sc.next(); while(!DataUtils.verifyMoney(id)) { System.out.println("請重新輸入!"); id=sc.next(); } //-=--------------------------- System.out.println("請輸入賬務分類:"); String flname = sc.next(); System.out.println("請輸入金額:"); // double money = sc.nextDouble(); String money = sc.next(); while(!DataUtils.verifyMoney(money)) { System.out.println("請重新輸入!"); money=sc.next(); } System.out.println("請輸入賬戶名稱:"); String zhangHu = sc.next(); System.out.println("請輸時間(xxxx-xx-xx):"); String time = sc.next(); while(!DataUtils.verifyDate(time)) { System.out.println("請重新輸入!"); time=sc.next(); } System.out.println("請輸入用途:"); String description = sc.next(); SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd"); Date date = new Date(); try { date = formatter.parse(time); } catch (ParseException e) { System.out.println("日期轉換除了問題!"); e.printStackTrace(); } ZhangWu zhangwu = new ZhangWu(); zhangwu.setZwid(Integer.parseInt(id)); zhangwu.setFlname(flname); zhangwu.setMoney(Double.parseDouble(money)); zhangwu.setZhangHu(zhangHu); zhangwu.setDescription(description); zhangwu.setCreatetime(date); int cnt=controller.editZhangWu(zhangwu); if(cnt>0) { System.out.println("修改成功!"); }else { System.out.println("修改失敗!"); } } public void showAll() { //顯示全部賬戶 PageBean<ZhangWu> page = new PageBean<ZhangWu>(); page.setPageNumber(1); page.setPageSize(5); page = controller.selectAll(page); page.setPageSize(page.getTotal()); page = controller.selectAll(page); System.out.println("ID\t類別\t賬戶\t金額\t時間\t\t說明"); for (ZhangWu z : page.getData()) { System.out.println(z.toString()); } // ---------------- } public void addZhangWu() { // 呼叫查詢所有賬務資料的功能,顯示出來--- showAll(); // ------------------- System.out.println("選擇的是增加賬務功能,請輸入:"); Scanner scc = new Scanner(System.in); System.out.println("請輸入賬務分類:"); String flname = scc.next(); System.out.println("請輸入金額:"); String money = scc.next(); while(!DataUtils.verifyMoney(money)) { System.out.println("請重新輸入!"); money=scc.next(); } System.out.println("請輸入賬戶名稱:"); String zhangHu = scc.next(); System.out.println("請輸時間(xxxx-xx-xx):"); String time = scc.next(); while(!DataUtils.verifyDate(time)) { System.out.println("請重新輸入!"); time=scc.next(); } System.out.println("請輸入用途:"); String description = scc.next(); SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd"); Date date = new Date(); try { date = formatter.parse(time); } catch (ParseException e) { System.out.println("日期轉換除了問題!"); e.printStackTrace(); } ZhangWu zhangwu = new ZhangWu(); zhangwu.setFlname(flname); zhangwu.setMoney(Double.parseDouble(money)); zhangwu.setZhangHu(zhangHu); zhangwu.setDescription(description); zhangwu.setCreatetime(date); int cnt = controller.addZhangWu(zhangwu); if (cnt > 0) { System.out.println("增加賬務成功"); } else { System.out.println("增加賬務失敗"); } } public void selectAll() { // 分頁查詢全部資料 int count = 1; PageBean<ZhangWu> page = new PageBean<ZhangWu>(); page.setPageNumber(1); page.setPageSize(4); page = controller.selectAll(page); System.out.println("ID\t類別\t賬戶\t金額\t時間\t\t說明"); for (ZhangWu z : page.getData()) { System.out.println(z.toString()); } System.out.println("第" + page.getPageNumber() + "頁;共" + page.getPageCount() + "頁。"); System.out.println("------------------"); System.out.println("輸入空格翻頁"); Scanner sc = new Scanner(System.in); String m = sc.nextLine(); while (true) { if (m.equals(" ")) { if (count >= page.getPageCount()) { // System.out.println("_________"); controller.getTotal(); System.out.println("輸入3返回上一級!"); break; } else { count++; System.out.println("翻頁"); page.setPageNumber(count); } } else { System.out.println("+++++++"); } page = controller.selectAll(page); System.out.println("ID\t類別\t賬戶\t金額\t時間\t\t說明"); for (ZhangWu z : page.getData()) { System.out.println(z.toString()); } System.out.println("第" + page.getPageNumber() + "頁;共" + page.getPageCount() + "頁。"); System.out.println("------------------"); m = sc.nextLine(); } }
}
5.在view中寫完自己的需求後,再就可以編寫control層:
package cn.njit.gjp.controller;
import cn.njit.gjp.entity.PageBean;
import cn.njit.gjp.entity.ZhangWu;
import cn.njit.gjp.service.ZhangWuService;
/***
* 控制層
* @author Liu
*
*/
public class ZhangWuController {
private ZhangWuService service=new ZhangWuService();
public int addZhangWu(ZhangWu zhangwu) {
return service.addZhangWu(zhangwu);
}
public PageBean<ZhangWu> selectAll(PageBean<ZhangWu> page) {
return service.selectAll(page);
}
public void getTotal() {
service.getTotal();
}
public PageBean<ZhangWu> conditionSelectZhangwu(String begin, String end,PageBean<ZhangWu> page) {
return service.conditionSelectZhangwu(begin,end,page);
}
public int deleteZhangWu(int id) {
return service.deleteZhangWu(id);
}
public int editZhangWu(ZhangWu zhangwu) {
return service.editZhangWu(zhangwu);
}
}
6.service層
package cn.njit.gjp.service;
import cn.njit.gjp.dao.ZhangWuDao;
import cn.njit.gjp.entity.PageBean;
import cn.njit.gjp.entity.ZhangWu;
public class ZhangWuService {
private ZhangWuDao dao = new ZhangWuDao();
public int addZhangWu(ZhangWu zhangwu) {
/**
* 定義方法,實現刪除功能
* 檢視層呼叫,傳遞int型別主鍵
* 呼叫service層方法,傳遞int主鍵
*/
return dao.addZhangWu(zhangwu);
}
public PageBean<ZhangWu> selectAll(PageBean<ZhangWu> page) {
return dao.selectAll(page);
}
public void getTotal() {
dao.getTotal();
}
public PageBean<ZhangWu> conditionSelectZhangwu(String begin, String end,PageBean<ZhangWu> page) {
return dao.conditionSelectZhangwu(begin,end,page);
}
public int deleteZhangWu(int id) {
return dao.deleteZhangWu(id);
}
public int editZhangWu(ZhangWu zhangwu) {
return dao.editZhangWu(zhangwu);
}
}
7.dao層
package cn.njit.gjp.dao;
import java.sql.SQLException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.ArrayHandler;
import org.apache.commons.dbutils.handlers.ArrayListHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;
import cn.njit.gjp.entity.PageBean;
import cn.njit.gjp.entity.ZhangWu;
import cn.njit.gjp.tools.JDBCUtils;
/**
* Dao實現層
* @author Liu
*
*/
public class ZhangWuDao {
private QueryRunner qr=new QueryRunner(JDBCUtils.getDataSource());
/**
*
* @param zhangwu 實體類
* @return 增加賬務方法
*/
public int addZhangWu(ZhangWu zhangwu) {
String sql="insert into personal_zhangwu(flname,money,zhangHu,createtime,description) VALUES(?,?,?,?,?); ";
Object[] o= {zhangwu.getFlname(),zhangwu.getMoney(),zhangwu.getMoney(),zhangwu.getCreatetime(),zhangwu.getDescription()};
try {
int row=qr.update(sql,o);
return row;
} catch (SQLException e) {
e.printStackTrace();
return 0;
}
}
/***
*
* @param page 引數為一張空白的頁面
* @return 返回有內容的頁面
*/
public PageBean<ZhangWu> selectAll(PageBean<ZhangWu> page) {
String sqll="select count(1) from personal_zhangwu";
ScalarHandler<Long> slh=new ScalarHandler<Long>();
Long cnt = null;
try {
cnt = qr.query(sqll, slh);
} catch (SQLException e1) {
e1.printStackTrace();
}
int total=cnt.intValue();
String sql="select * from personal_zhangwu limit ?,?;";
BeanListHandler<ZhangWu> blh=new BeanListHandler<ZhangWu>(ZhangWu.class);
int pageSize = page.getPageSize();
int begin = (page.getPageNumber() - 1) * pageSize;
// System.out.println(begin+"xxxx"+pageSize);
Object[] o= {begin,pageSize};
try {
List<ZhangWu> list=qr.query(sql, blh,o);
page.setData(list);
page.setTotal(total);
} catch (SQLException e) {
System.out.println("Dao層selectAll出錯");
e.printStackTrace();
}
return page;
}
/***
* 統計所有的賬戶
*/
public void getTotal() {
String sql1="select SUM(money) FROM personal_zhangwu where flname LIKE ('支出%');";
ArrayHandler ah=new ArrayHandler();
String str1 = null;
String str2 = null;
try {
Object[] rs=qr.query(sql1, ah);
str1=rs[0].toString();
// //-------------------------------
// System.out.println(str1);
} catch (SQLException e) {
System.out.println("Dao>>getTotal()出錯>>第1個sql");
System.out.println(sql1);
e.printStackTrace();
}
String sql2="select SUM(money) FROM personal_zhangwu where flname LIKE ('收入%');";
ah=new ArrayHandler();
try {
Object[] rs2=qr.query(sql2, ah);
str2=rs2[0].toString();
// //-------------------------------
// System.out.println(str2);
} catch (SQLException e) {
System.out.println("Dao>>getTotal()出錯>>第2個sql");
System.out.println(sql2);
e.printStackTrace();
}
System.out.println("總支出:"+str1+", 總收入:"+str2+",淨收入:"+(Double.parseDouble(str2)-Double.parseDouble(str1)));
String sql3="select flname as 款項,SUM(money) as 支出 FROM personal_zhangwu where flname LIKE ('支出%') GROUP BY flname ; ";
ArrayListHandler ahs=new ArrayListHandler();
System.out.println("支出統計:");
try {
List<Object[]> list=qr.query(sql3, ahs);
for (int i = 0; i < list.size(); i++) {
Object[] o=list.get(i);
for(Object ox:o) {
System.out.print(ox.toString()+"\t");
}
System.out.println("");
}
} catch (SQLException e) {
System.out.println("Dao>>getTotal()出錯>>第3個sql");
System.out.println(sql3);
e.printStackTrace();
}
String sql4="select flname as 款項,SUM(money) as 收入 FROM personal_zhangwu where flname LIKE ('收入%') GROUP BY flname ; ";
ahs=new ArrayListHandler();
System.out.println("收入統計:");
try {
List<Object[]> list=qr.query(sql4, ahs);
for (int i = 0; i < list.size(); i++) {
Object[] o=list.get(i);
for(Object ox:o) {
System.out.print(ox.toString()+"\t");
}
System.out.println("");
}
} catch (SQLException e) {
System.out.println("Dao>>getTotal()出錯>>第4個sql");
System.out.println(sql4);
e.printStackTrace();
}
}
/* public PageBean<ZhangWu> conditionSelectZhangwu(String begin, String end,PageBean<ZhangWu> page) {
String sqll="select count(1) from personal_zhangwu";
ScalarHandler<Long> slh=new ScalarHandler<Long>();
Long cnt = null;
try {
cnt = qr.query(sqll, slh);
} catch (SQLException e1) {
e1.printStackTrace();
}
int total=cnt.intValue();
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
Date beginDate = new Date();
Date endDate = new Date();
try {
beginDate = formatter.parse(begin);
endDate=formatter.parse(end);
} catch (ParseException e) {
System.out.println("日期轉換除了問題!");
e.printStackTrace();
}
//-----------------------------------------------------
String sql="select * from personal_zhangwu where createtime>? and createtime<? limit ?,?";
BeanListHandler<ZhangWu> blh=new BeanListHandler<ZhangWu>(ZhangWu.class);
int pageSize = page.getPageSize();
int beginSize = (page.getPageNumber() - 1) * pageSize;
Object[] o= {beginDate,endDate,beginSize,pageSize};
try {
List<ZhangWu> list=qr.query(sql, blh,o);
page.setData(list);
page.setTotal(total);
} catch (SQLException e) {
System.out.println("Dao>>conditionSelectZhangwu()出錯>>第1個sql");
e.printStackTrace();
}
return page;
}
*/
/**
*
* @param begin 開始日期
* @param end 截至日期
* @param page 空白的頁面
* @return 有內容的頁面
*/
public PageBean<ZhangWu> conditionSelectZhangwu(String begin, String end,PageBean<ZhangWu> page){
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
Date beginDate = new Date();
Date endDate = new Date();
try {
beginDate = formatter.parse(begin);
endDate=formatter.parse(end);
} catch (ParseException e) {
System.out.println("日期轉換除了問題!");
e.printStackTrace();
}
String sqll="select count(1) from personal_zhangwu where createtime>? and createtime<?";
ScalarHandler<Long> slh=new ScalarHandler<Long>();
Object[] ox= {beginDate,endDate};
Long cnt = null;
try {
cnt = qr.query(sqll, slh,ox);
} catch (SQLException e1) {
e1.printStackTrace();
}
int total=cnt.intValue();
String sql="select * from personal_zhangwu where createtime>? and createtime<? limit ?,?";
BeanListHandler<ZhangWu> blh=new BeanListHandler<ZhangWu>(ZhangWu.class);
int pageSize = page.getPageSize();
int beginPage = (page.getPageNumber() - 1) * pageSize;
Object[] o= {begin,end,beginPage,pageSize};
try {
List<ZhangWu> list=qr.query(sql, blh,o);
page.setData(list);
page.setTotal(total);
} catch (SQLException e) {
e.printStackTrace();
}
return page;
}
/**
*
* @param id 賬務id
* @return 刪除結果 (1/0)
*/
public int deleteZhangWu(int id) {
String sql="Delete from personal_zhangwu where zwid=?";
int cnt = 0;
try {
cnt=qr.update(sql,id);
} catch (SQLException e) {
System.out.println("Dao>>deleteZhangWu()出錯>>第1個sql");
e.printStackTrace();
}
return cnt;
}
/***
*
* @param zhangwu
* @return cnt
*/
public int editZhangWu(ZhangWu zhangwu) {
String sql="Update personal_zhangwu set zwid=?,flname=?,money=?,zhangHu=?,createtime=?,description=? where zwid=?";
Object[] o= {zhangwu.getZwid(),zhangwu.getFlname(),zhangwu.getMoney(),zhangwu.getZhangHu(),zhangwu.getCreatetime(),zhangwu.getDescription(),zhangwu.getZwid()};
int cnt = 0;
try {
cnt=qr.update(sql,o);
} catch (SQLException e) {
System.out.println("Dao>>editZhangWu()出錯>>第1個sql");
e.printStackTrace();
}
return cnt;
}
/***
*
* @return 所有結果封裝在list型中
*/
public List<ZhangWu> showListAll() {
List<ZhangWu> list = null;
String sql="select * from personal_zhangwu;";
BeanListHandler<ZhangWu> blh=new BeanListHandler<ZhangWu>(ZhangWu.class);
try {
list=qr.query(sql,blh);
} catch (SQLException e) {
e.printStackTrace();
}
return list;
}
}
8.當然,這個專案最重要的就是表現層和實現層,寫到DAO層的時候,我們就要寫實體類:兩個JavaBean——一個用於分頁管理,一個是賬務實體;
package cn.njit.gjp.entity;
import java.util.Date;
public class ZhangWu {
private int zwid;
private String flname;
private double money;
private String zhangHu;
private Date createtime;
private String description;
public int getZwid() {
return zwid;
}
public void setZwid(int zwid) {
this.zwid = zwid;
}
public String getFlname() {
return flname;
}
public void setFlname(String flname) {
this.flname = flname;
}
public double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
public String getZhangHu() {
return zhangHu;
}
public void setZhangHu(String zhangHu) {
this.zhangHu = zhangHu;
}
public Date getCreatetime() {
return createtime;
}
public void setCreatetime(Date createtime) {
this.createtime = createtime;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String toString() {
return zwid+"\t"+flname+"\t"+zhangHu+"\t"+money+"\t"+createtime+"\t"+description;
}
}
----------------------------------------------------------------------------------------
package cn.njit.gjp.entity;
import java.util.List;
public class PageBean<T> {
private List<T> data;
private int pageSize;//每頁顯示的條數
private int total;//當前查詢條件下的總記錄條數
private int pageNumber;//顯示哪一頁
public int getPageCount() {
return (int) Math.ceil(total*1.0/pageSize);
}
public List<T> getData() {
return data;
}
public void setData(List<T> data) {
this.data = data;
}
public int getPageSize() {
return pageSize;
}
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
public int getTotal() {
return total;
}
public void setTotal(int total) {
this.total = total;
}
public int getPageNumber() {
return pageNumber;
}
public void setPageNumber(int pageNumber) {
this.pageNumber = pageNumber;
}
}
9.秉承一個類只做一件事的原則,我們還需要大量的工具類,比如讀取配置檔案和對日期的處理;
package cn.njit.gjp.tools;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
/****
* 獲取配置檔案的工具類
* @author Liu
*
*/
public class ConfigurationFiles {
/***
*
* @return port 埠
*
*/
public static String getPort() {
String path="D:\\FileDemo\\SecondProject\\service.ini";
InputStream is = null;
try {
is = new FileInputStream(path);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
Properties pro=new Properties();
try {
pro.load(is);
} catch (IOException e1) {
e1.printStackTrace();
}
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
String port=pro.getProperty("port");
return port;
}
/**
*
* @return 返回IP陣列
*/
public static String[] getIp() {
String path="D:\\FileDemo\\SecondProject\\service.ini";
InputStream is = null;
try {
is = new FileInputStream(path);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
Properties pro=new Properties();
try {
pro.load(is);
} catch (IOException e1) {
e1.printStackTrace();
}
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
String ips=pro.getProperty("ips")+",";
String[] strArray = null;
strArray = ips.split(",");
for (int i = 0; i < strArray.length; i++) {
strArray[i]=strArray[i].trim();
}
return strArray;
}
/**
* 判斷ip是否存在
* @param ip
* @return
*/
public static boolean isExist(String ip) {
String[] array=ConfigurationFiles.getIp();
for (String s : array) {
if(ip.equals(s)) {
return true;
}
}
return false;
}
}
----------------------------------------------------------------------
package cn.njit.gjp.tools;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateUtils {
public static String Dateyyyy_MM_dd_time() {
Date date=new Date();
SimpleDateFormat sdf=new SimpleDateFormat("yyyyMMdd-HH:mm:ss");
String str=sdf.format(date);
return str;
}
public static Date Dateyyyy_MM_dd_time(String str) {
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
Date date = new Date();
try {
date = formatter.parse(str);
} catch (ParseException e) {
System.out.println("日期轉換除了問題!");
e.printStackTrace();
}
return date;
}
}
10.匯出賬務日誌;
在專案中,嵌入一個TCP server,用於接受客戶端的匯出請求。
再編寫一個單獨的TCP客戶端程式,執行此程式,可以向TCP Server發出匯出請求。
TCP SERVER收到客戶端請求後,從資料庫中讀取所有賬務記錄,按照賬務時間後先順序排序,然後把這些記錄返回給客戶端。
客戶端接收到伺服器端的資料後,把資料寫入本地檔案。
檔案中的格式與內容與“檢視賬務”介面上顯示的格式和內容一樣。
伺服器端要記錄匯出日誌到檔案,日誌檔名為export.log,日誌檔案格式樣例:
匯出總次數: 88,成功次數:77
20181017-10:33:22 192.168.10.66 匯出成功
20181017-10:36:33 127.0.0.1 匯出失敗,非法客戶端
20181022-09:10:12 192.168.10.77 匯出成功
…
記錄日誌檔案是,要避免多個客戶端同時匯出是日誌記錄的併發問題。
TCP服務端:
package cn.njit.gjp.ser;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import cn.njit.gjp.tools.ConfigurationFiles;
import cn.njit.gjp.tools.LogUtils;
public class ChatServer {
private ServerSocket serverSocket;
public void setServerSocket() {
try {
this.serverSocket = new ServerSocket(Integer.parseInt(ConfigurationFiles.getPort()));
} catch (IOException e) {
e.printStackTrace();
}
}
private Socket socket;
public void Connect() {
setServerSocket();
while(true)
{
try {
socket=serverSocket.accept();
System.out.println("連線成功");
} catch (IOException e) {
e.printStackTrace();
System.out.println("獲取失敗");
}
ChatThread s=new ChatThread(socket);
Thread t= new Thread(s);
t.start();
try {
LogUtils.LogPrint();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
服務執行緒類:
package cn.njit.gjp.ser;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.util.List;
import cn.njit.gjp.dao.ZhangWuDao;
import cn.njit.gjp.tools.ConfigurationFiles;
import cn.njit.gjp.tools.DateUtils;
import cn.njit.gjp.tools.LogUtils;
public class ChatThread implements Runnable {
private Socket socket;
private DataInputStream dis;
private DataOutputStream dos;
public ChatThread(Socket socket) {
super();
setSocket(socket);
}
public Socket getSocket() {
return socket;
}
public void setSocket(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
//----------------------1.初始化------------//
try {
dis=new DataInputStream(socket.getInputStream());
dos=new DataOutputStream(socket.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
//-----------------------2.驗證ip-----------//
InetAddress address=socket.getInetAddress();
String ip=address.getHostAddress();
StringBuffer strb=new StringBuffer();
boolean tip=ConfigurationFiles.isExist(ip);
//-----------------------3.打檔案-----------//
System.out.println(tip);
if(tip) {
List<?> list=new ZhangWuDao().showListAll();
StringBuffer sb=new StringBuffer();
for (int i = list.size()-1; i >=0; i--) {
sb.append(list.get(i));
sb.append("\n");
}
System.out.println("OKOKOOK");
try {
dos.writeUTF(sb.toString());
} catch (IOException e) {
e.printStackTrace();
}
strb.append(DateUtils.Dateyyyy_MM_dd_time()+"\t"+ip+"\t匯入成功");
}else{
System.out.println("沒有這個ip");
System.out.println("非法ip,非法連線");
try {
dos.writeUTF("非法ip,非法連線");
} catch (IOException e) {
e.printStackTrace();
}
strb.append(DateUtils.Dateyyyy_MM_dd_time()+"\t"+ip+"\t匯入失敗");
}
//------------------------4.打日誌------------------//
try {
//打日誌
LogUtils.Write(strb.toString());
// LogUtils.LogPrint();
} catch (IOException e) {
e.printStackTrace();
}
}
}
客戶端:
package cn.njit.gjp.ser;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Date;
import java.util.UUID;
public class ChatClient {
public static void main(String[] args) throws Exception{
String host=args[0];
int port=8888;
int cnt=5; //執行緒數量
long begin=new Date().getTime();
ClientThread[] cts=new ClientThread[cnt];
for(int i=0;i<cnt;i++) {
ClientThread t=new ClientThread(host,port);
cts[i]=t;
t.start();
}
for(int i=0;i<cnt;i++) {
cts[i].join();
}
long end=new Date().getTime();
System.out.println("花費時間:"+(end-begin)+"毫秒");
}
}
class ClientThread extends Thread{
String host;
int port;
public ClientThread(String host,int port) {
this.host=host;
this.port=port;
}
public void run(){
try {
Socket s=new Socket(host,8888);
InputStream is=s.getInputStream();
int len=0;
byte[] buffer=new byte[1024];
len=is.read(buffer);
//----------------------------------------------------------------//
String fileName="D:\\FileDemo\\SecondProject\\"+UUID.randomUUID().toString()+".txt";
OutputStream os=new FileOutputStream(fileName);
while(-1!=len) {
os.write(buffer,0,len);
len=is.read(buffer);
}
os.close();
is.close();
s.close();
}catch(Exception ex) {
ex.printStackTrace();
}
}
}
11.同樣,對於TCP服務來說,也需要大量的工具類:
package cn.njit.gjp.tools;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
public class ServerUtils {
public static void send(DataOutputStream dos,String ip) {
try {
dos.writeUTF(ip);
dos.flush();//++++
} catch (IOException e) {
e.printStackTrace();
}
}
public static String receiveId(DataInputStream dis) {
String readUTF = null;
try {
readUTF = dis.readUTF();
} catch (IOException e) {
e.printStackTrace();
}
return readUTF;
}
}
-----------------------------------------------------------------------------
package cn.njit.gjp.tools;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/***
* 日誌列印工具類
* @author Liu
*
*/
public class LogUtils {
private static DataInputStream dis;
private static DataOutputStream dos;
/***
*
* @param str 列印的字串
* @throws IOException 丟擲IO異常
*/
public static void Write(String str) throws IOException {
dos=new DataOutputStream(new FileOutputStream("D:\\FileDemo\\SecondProject\\log.log",true));
dos.writeUTF(str+"\n");
dos.flush();
dos.close();
}
public static void LogPrint() throws IOException {
dis=new DataInputStream(new FileInputStream("D:\\FileDemo\\SecondProject\\log.log"));
byte[] buf=new byte[1024];
int len=dis.read(buf);
StringBuffer sb=new StringBuffer();
while(-1!=len) {
String str=new String(buf,0,buf.length);
sb.append(str);
len=dis.read(buf);
}
String[] strArray = null;
strArray = sb.toString().split("\n");
List<String> list=new ArrayList<String>();
for (int i = 0; i < strArray.length; i++) {
list.add(strArray[i].trim());
}
int count1 = 0,count2 = 0;
for (int i = 0; i < list.size(); i++) {
String str=list.get(i);
if(str.contains("匯入")) {
count1++;
}
if(str.contains("匯入成功")) {
count2++;
}
}
String str1="總次數:"+count1;
String str2="成功:"+count2;
String strM=str1+"\t"+str2;
// for (int i = 0; i <list.size(); i++) {
// sbb.append(list.get(i));
// }
//
//
BufferedWriter br = new BufferedWriter(new FileWriter("D:\\FileDemo\\SecondProject\\log的log.txt"));
br.write(strM);
br.close();
}
}
12.最後是主函式:
package cn.njit.gjp.app;
import cn.njit.gjp.ser.ChatServer;
import cn.njit.gjp.view.MainView;
/****
*
* @author Liu
*
*/
public class MainApp{
public static void main(String[] args) {
MainView m=new MainView();
Thread mm=new Thread(m,"主函式");
mm.start();
ChatServer cs=new ChatServer();
cs.Connect();
}
}
結果演示:
增刪改查就不演示了,主要演示的是匯出賬務日誌這一段:
首先,啟動主函式的同時,啟動tcp執行緒:
然後,在命令列啟動客戶端:
最後檢視日誌:
寫在最後:
當然,任何一個專案都要求異常處理,尤其是使用標準輸入流在控制檯輸入資料的時候,對於Scanner函式的nextInt()來說,如果讀取到其他值是會報錯的,所以我們就要進行巧妙的型別檢查,還有日期之類的,平年時沒有2月29日的;
package cn.njit.gjp.tools;
import java.util.regex.Pattern;
/***
* 驗證類,使用正則表示式
* @author Liu
*
*/
public class DataUtils {
public static final String REGEX_money = "^[0-9]{0,10}$";
public static final String REGEX_date = "((\\d{2}(([02468][048])|([13579][26]))[\\-]((((0?[13578])|(1[02]))[\\-]((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\\-]((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\\-]((0?[1-9])|([1-2][0-9])))))|(\\d{2}(([02468][1235679])|([13579][01345789]))[\\-]((((0?[13578])|(1[02]))[\\-]((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\\-]((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\\-]((0?[1-9])|(1[0-9])|(2[0-8]))))))";
/***
*
* @param str
* @return 是否是int
*/
public static boolean verifyMoney(String str) {
return Pattern.matches(REGEX_money,str);
}
public static boolean verifyDate(String str) {
return Pattern.matches(REGEX_date,str);
}
}
Scanner的next是可以讀取到你輸入的任何字元的,所以我們在讀取字元的時候就一律使用這個函式,例如對money的處理。我們一般是使用nextDouble()來讀取,但是一旦讀取到其他型別就會報錯,所以我們使用next()來讀取,然後判斷它合不合法:
String money = scc.next();
while(!DataUtils.verifyMoney(money)) {
System.out.println("請重新輸入!");
money=scc.next();
}
//最後在插入的時候把合法的資料轉換成Double型:
zhangwu.setMoney(Double.parseDouble(money));
對日期的驗證也是一樣,截至日期不能比開始日期早,而且要符合當年的規範(例如平年沒有2月29);
System.out.println("請輸入開始日期:");
String begin = sc.next();
while(!DataUtils.verifyDate(begin)) {
System.out.println("請重新輸入開始日期!");
begin = sc.next();
}
System.out.println("請輸入截至日期:");
String end = sc.next();
while(!DataUtils.verifyDate(end)) {
System.out.println("請重新輸入截至日期!");
end = sc.next();
}
if(DateUtils.Dateyyyy_MM_dd_time(end).before((DateUtils.Dateyyyy_MM_dd_time(begin)))) {
System.out.println("日期先後錯誤!");
System.out.println("請輸入開始日期:");
begin = sc.next();
while(!DataUtils.verifyDate(begin)) {
System.out.println("請重新輸入開始日期!");
begin = sc.next();
}
System.out.println("請輸入截至日期:");
end = sc.next();
while(!DataUtils.verifyDate(end)) {
System.out.println("請重新輸入截至日期!");
end = sc.next();
}
}
當然,異常處理不只是我寫出來的那些,還有更多的異常等著我們去發現,去處理;