管家婆家庭记账软件
基本功能:
数据库设计:
字段 |
数据类型 |
备注 |
zwid |
int |
主键,自增 |
flname |
varchar(200) |
|
money |
double |
|
zhangHu |
varchar(100) |
|
createtime |
Varchar(50) |
|
description |
varchar(500) |
新增功能:用户登陆注册、管理员功能、收入与支出统计功能
本次的管家婆家庭记账软件充分的利用了项目开发中分层与分包的理念,为以后的开发打下了很好的基础。具体细节如下:
1、在tools层,先写工具类,将数据库连接中部分重复性代码封装起来
2、在domain层,创建实体类,包括类的属性、get/set方法、构造方法
3、在view层,将软件的大体框架给搭建出来
4、在dao层,操作数据库中的数据,对数据库进行增删改查,将执行的结果传到service层
5、在service层,将dao层传过来的结果集封装成一个方法,并传到controller层
6、在controller层,接收service层传递过来的方法,并将一些需要输出反馈信息封装起来传递到view层
7、在view层,操作controller层的结果,并将方法封装起来,在首页框架中调用这些方法
8、在test层,调用view层的方法,在控制台上打印输出
部分代码如下:
工具类tools代码:
package com.oracle.tools;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
//第一步:先写工具类,将数据库连接的部分重复性代码封装为一个方法
public class DButil {
private DButil() {
}
public static Connection getConn() {
try {
Class.forName("com.mysql.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/demo?characterEncoding=utf-8";
String username = "root";
String password = "123456";
Connection conn = DriverManager.getConnection(url, username, password);
return conn;
} catch (Exception ex) {
throw new RuntimeException(ex + "数据库连接失败!");
}
}
public static void close(Statement sta, Connection conn) {
if (sta != null) {
try {
sta.close();
} catch (SQLException ex) {
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException ex) {
}
}
}
public static void close(ResultSet rs, Statement sta, Connection conn) {
if (rs != null) {
try {
rs.close();
} catch (SQLException ex) {
}
}
close(sta, conn);
}
}
dao层操作数据库代码
public ArrayList find() {
try {
// 获得连接
Connection conn = DButil.getConn();
// 获得SQL语句执行平台
Statement sta = conn.createStatement();
// 执行SQL语句
String sql = "select * from housekeeper";
ResultSet rs = sta.executeQuery(sql);
ArrayList list = new ArrayList();
while (rs.next()) {
House h = new House();
h.setZwid(rs.getInt("zwid"));
h.setFlname(rs.getString("flname"));
h.setZhangHu(rs.getString("zhangHu"));
h.setMoney(rs.getDouble("money"));
h.setCreatetime(rs.getString("createtime"));
h.setDescription(rs.getString("description"));
h.setMark(rs.getString("mark"));
list.add(h);
}
DButil.close(rs, sta, conn);
return list;
} catch (SQLException ex) {
System.out.println(ex);
throw new RuntimeException(ex + "数据查询失败。");
}
}
service层
package com.oracle.service;
import java.util.ArrayList;
import com.oracle.dao.HouseDao;
import com.oracle.domain.House;
import com.oracle.domain.Users;
//第五步:将第四层处理数据库的方法封装起来,并进行调用送到controller层
public class HouseService {
private HouseDao houseDao = new HouseDao();
public ArrayList find() {
return houseDao.find();
}
}
controller层
import java.util.ArrayList;
import com.oracle.domain.House;
import com.oracle.domain.Users;
import com.oracle.service.HouseService;
//第六步,调用第五步封装好的方法,并输出处理结果的一些提示信息,然后返回给view层
public class HouseController {
private HouseService houseService = new HouseService();
// 查询所有账单
public ArrayList find() {
return houseService.find();
}
}
view层
/*
* 定义方法 查询全部账单信息
*/
public void find() {
ArrayList list = houseController.find();
System.out.println("ID\t类别\t账户\t金额\t时间\t\t说明\t\t标记");
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i).getZwid() + "\t" + list.get(i).getFlname() + "\t" + list.get(i).getZhangHu()
+ "\t" + list.get(i).getMoney() + "\t" + list.get(i).getCreatetime() + "\t"
+ list.get(i).getDescription() + "\t\t" + list.get(i).getMark());
}
}
dao层
// 以标记收入为条件查询
public ArrayList findMark(House house) {
try {
Connection conn = DButil.getConn();
String sql = "select * from housekeeper where createtime>=? and createtime<=? and mark=?";
PreparedStatement pst = conn.prepareStatement(sql);
pst.setString(1, house.getCreatetime());
pst.setString(2, house.getEndtime());
pst.setString(3, "+");
ResultSet rs = pst.executeQuery();
ArrayList list = new ArrayList();
// 遍历结果集
while (rs.next()) {
House h = new House();
h.setZwid(rs.getInt("zwid"));
h.setFlname(rs.getString("flname"));
h.setZhangHu(rs.getString("zhangHu"));
h.setMoney(rs.getDouble("money"));
h.setCreatetime(rs.getString("createtime"));
h.setDescription(rs.getString("description"));
h.setMark(rs.getString("mark"));
list.add(h);
}
DButil.close(rs, pst, conn);
return list;
} catch (SQLException ex) {
System.out.println(ex);
throw new RuntimeException(ex + "数据查询失败。");
}
}
//用户名验证
public boolean examine(Users users){
try {
Connection conn=DButil.getConn();
String sql="select * from users where username=?";
PreparedStatement pst=conn.prepareStatement(sql);
pst.setString(1, users.getUsername());
ResultSet rs=pst.executeQuery();
boolean b=rs.next();
DButil.close(pst, conn);
return b;
}catch (SQLException ex) {
System.out.println(ex);
throw new RuntimeException(ex + "用户验证失败。");
}
}
// 用户登陆
public boolean login(Users users) {
try {
Connection conn = DButil.getConn();
String sql = "select * from users where username=?and pwd=?";
PreparedStatement pst = conn.prepareStatement(sql);
pst.setString(1, users.getUsername());
pst.setString(2, users.getPwd());
ResultSet rs = pst.executeQuery();
boolean flag = rs.next();
DButil.close(rs, pst, conn);
return flag;
} catch (SQLException ex) {
System.out.println(ex);
throw new RuntimeException(ex + "用户登陆失败。");
}
}
view层
/*
* 定义一个方法 验证输入的时间的格式
*/
public boolean time(String str) {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
boolean flag = true;
try {
Date date = format.parse(str);
} catch (ParseException e) {
flag = false;
}
return flag;
}
/*
* 定义方法 以时间和支出的标记为条件查询某段时间的支出情况
*/
public void findMarkOut() throws ParseException {
while (true) {
System.out.print("请输入查询起始时间:");
String str1 = sc.next();
//验证时间格式
if (time(str1) == false) {
System.out.println("输入的日期格式错误!");
continue;
}
DateFormat df1 = new SimpleDateFormat("yyyy-MM-dd");
Date date1 = df1.parse(str1);
long start = date1.getTime();
System.out.print("请输入查询结束时间:");
String str2 = sc.next();
//验证时间格式
if (time(str2) == false) {
System.out.println("输入的日期格式错误!");
continue;
}
DateFormat df2 = new SimpleDateFormat("yyyy-MM-dd");
Date date2 = df2.parse(str2);
long end = date2.getTime();
results = (end - start) / 1000 / 60 / 60 / 24;
int result = str1.compareTo(str2);
if (result < 0) {
printOut(str1,str2);
break;
} else if (result == 0) {
printIn(str1,str2);
break;
} else if (result > 0) {
System.out.println("查询时间输入有误,请重新输入");
}
}
}
/*
* 用户验证
*/
public boolean examine(String str) {
Users users = new Users();
users.setUsername(str);
boolean b = houseController.examine(users);
if (b) {
return true;
} else {
return false;
}
}
// 密码验证
public boolean pwd(String str) {
Users users = new Users();
users.setPwd(str);
boolean b = houseController.pwd(users);
if (b) {
return true;
} else {
return false;
}
}
/*
* 定义方法 用户登陆
*/
public void login() throws ParseException {
while (true) {
Users users = new Users();
System.out.print("请输入用户名:");
String regex1 = "[a-z_0-9]{6,8}";// 普通用户的正则
String regex2 = "[a-z]{5}";// 管理员的正则
String str = sc.next();
boolean flagComm = str.matches(regex1);
boolean flagManage = str.matches(regex2);
if (flagComm) {
if (flagComm) {
if (examine(str) == false) {
System.out.println("用户名不存在!");
continue;
}
System.out.println("用户名正确");
users.setUsername(str);
System.out.print("请输入登陆密码:");
String str2 = sc.next();
boolean flagPwd = str2.matches(regex1);
if (flagPwd) {
if (pwd(str2) == false) {
System.out.println("密码错误");
continue;
}
System.out.println("密码正确");
users.setPwd(str2);
String mes = houseController.login(users);
System.out.println(mes);
run();
break;
} else {
System.out.println("密码错误,请重新输入");
}
continue;
} else {
System.out.println("用户名错误,请重新输入:");
}
} else {
if (flagManage) {
if (examine(str) == false) {
System.out.println("用户名不存在!");
continue;
}
System.out.println("用户名正确");
users.setUsername(str);
System.out.print("请输入登陆密码:");
String str2 = sc.next();
boolean flag1 = str2.matches(regex2);
if (flag1) {
System.out.println("密码正确");
users.setPwd(str2);
String mes = houseController.login(users);
System.out.println(mes);
host();
break;
} else {
System.out.println("密码错误,请重新输入");
}
continue;
} else {
System.out.println("用户名错误,请重新输入:");
}
}
}
}
// 找回密码
public void search() {
Users users = new Users();
System.out.print("请输入你的手机号:");
String strPhone = sc.next();
loop: while (true) {
String str = "1[34578][0-9]{9}";
boolean b = strPhone.matches(str);
if (b) {
if(have(strPhone)==false){
System.out.println("手机号不存在!");
break loop;
}
System.out.println("手机号码正确");
users.setPhone(strPhone);
ArrayList list = houseController.search(users);
System.out.println(String.format("%-10s", "ID") + String.format("%-10s", "用户名") + " "
+ String.format("%-10s", "登陆密码") + " " + String.format("%-10s", "联系电话") + "\t\t"
+ String.format("%-10s", "标记"));
System.out.println(
String.format("%-10s", list.get(0).getId()) + String.format("%-10s", list.get(0).getUsername())
+ String.format("%-10s", list.get(0).getPwd())
+ String.format("%-10s", list.get(0).getPhone()) + "\t" + list.get(0).getLogo());
break;
} else {
System.out.println("手机号码错误");
break loop;
}
}
}
/*
* 验证输入的手机号是否存在
* */
public boolean have(String str) {
Users users = new Users();
users.setPhone(str);
ArrayList list=houseController.search(users);
int b=list.size();
if (b>0) {
return true;
} else {
return false;
}
}
view层欢迎界之六芒星
/*
* 定义方法 展示欢迎界面
*/
public void showTime() {
System.out.println("---------->欢迎来到管家婆<----------");
int n = 4;
int line = 4 * n + 1; // 定义行数
for (int i = 1; i <= line; i++) {// 总体的循环
if (i <= n) {
// 第一个for循环打印空格,到三角形的边之间的空格
for (int j = 0; j < line - i - 1; j++) {
System.out.print(" ");
}
// 第二个for循环打印三角形的边
for (int k = 1; k <= i; k++) {
if (k == 1 || k == i) {// 确定每一行首位和末位的位置打印*
System.out.print("* ");
} else {
System.out.print(" ");
}
}
System.out.println();// 换行
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
} else if (i <= 2 * n + 1) {// 定义中间三角形的行数范围5-9
// 第一个for循环先打印空格
for (int y = 1; y < i; y++) {
System.out.print(" ");
}
// 第二个for循环打印*
for (int x = 1; x <= line - i; x++) {
if (x == 1 || x == line - i) {
System.out.print("* ");
// 计算出每个边长所在的位置,依次进行输出*
} else if (i <= n + 1 && x <= line) {
System.out.print("* ");
} else if (x == n * 2 - i + 2) {// 控制左连接线的位置
System.out.print("* ");
} else if (x == n * 2) {// 控制右连接线的位置
System.out.print("* ");
} else {
System.out.print(" ");
}
}
System.out.println();// 换行
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
} else if (i <= 3 * n + 1) { // 定义中下部分的行数10-13行
// 第一个for循环打印空格
for (int y = 1; y <= line - i; y++) {
System.out.print(" ");
}
// 第二个for循环打印边长上的*
for (int x = 1; x <= i - 1; x++) {// 定义镂空星的范围及数量
if (x == 1 || x == i - 1) {// 定义镂空星的打印位置
System.out.print("* ");
} else if (i == n * 3 + 1 && x <= n * 3) { // 打印第13行一整行的*
System.out.print("* ");
} else if (x == i - n * 2 || x == n * 2) {
System.out.print("* ");
} else {
System.out.print(" ");
}
}
System.out.println();// 换行
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
} else if (i <= line) { // 打印最后四行14-17行
// 第一个for循环打印空格
for (int y = 1; y <= i - 2; y++) {
System.out.print(" ");
}
for (int x = 1; x <= line + 1 - i; x++) {
if (x == 1 || x == line + 1 - i) {
System.out.print("* ");
} else {
System.out.print(" ");
}
}
System.out.println();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
项目总结:此次项目历时4天,代码1400行左右。在此次做项目的过程中遇到最多的问题应该是在dao层操作数据库
获取语句执行平台用statement或者预编译对象PreparedStatement,编写SQL语句,在执行此SQL语句
时,根据需求是获取部分字段或者全部字段,是否有条件的查询,去调用executeQuery 还是executeUpdate
是否将SQL语句作为参数传进去,返回什么类型的值;然后就是用户登陆注册功能时,通过正则表达式对输入的
用户名、密码、手机号等的判断和异常反馈。部分代码过于繁琐,没有很好的利用封装的特性。还有就是对时间
格式的判断不是很熟练,对输入的时间格式进行转成date类型,通过SimpleDateFormat对时间进行操作,以后还要多
加练习。最后就是在创建整体数据库表时,没有进行分表创建,没能利用主外键的关系,导致后期在一个表中查询数据
时代码过于冗余。