帅帅个人账务管理项目说明
项目功能
查看账务
多条件组合查看账务
增加账务
编辑账务
删除账务
导出账务
表结构
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();
}
}
当然,异常处理不只是我写出来的那些,还有更多的异常等着我们去发现,去处理;