项目目的:
通过MySQL和JDBC实现基本的移动业务(包括新用户注册,本月账单查询,套餐余量查询,打印消费详情,套餐变更,办理退网,话费充值,查看消费记录,查看话费说明等功能 )
1. 项目需求
中国移动,中国联通,中国电信是国内3大通信运营商,每个运营商都提供了不同的品牌套餐来应对不同的用户群,比如北京移动主要有全球通,神州行,动感地带等3大品牌套餐,每种套餐的内容和费用不同,嗖嗖移动是一个假定的通信运营商,提供了话痨套餐,网虫套餐,超人套餐,各种套餐所包含的服务内容及费用如下表:
品牌套餐 | 话痨套餐 | 网虫套餐 | 超人套餐 |
---|---|---|---|
通话时长(分钟) | 600 | 0 | 300 |
上网流量 | 0 | 20 | 10 |
短信条数(条) | 100 | 0 | 50 |
费用(元/月) | 58 | 68 | 78 |
如实际使用中超出套餐内包含的通话时长,短信条数和上网流量,则按一下规则计费:
-
超出的通话: 0.2元/分
-
超出的短信:0.1元/条
-
超出的上网流量:0.1元/MB
功能:
1.1项目层次结构:
1.2功能需求:
菜单级别 | 功能 | 描述 |
---|---|---|
主菜单 | 用户登录 | 输入正确的手机号码和密码进入二级菜单列表 |
主菜单 | 用户注册 | 录入信息并开卡,用户输入的信息包括:选择卡号,选择套餐类型,输入用户名和密码,预存话费金额(预存话费金额必须满足以支付所选套餐的一个月的费用) |
主菜单 | 使用嗖嗖 | 输入正确的手机号码和密码之后,随机进入本号码所属套餐可以支持的一个场景,消费套餐余量或者话费余额,并记录消费信息.当话费余额不足时,抛出异常提醒用户充值 |
主菜单 | 话费充值 | 输入正确的用户名和密码之后,可为该卡号充值 |
主菜单 | 资费说明 | 提供各品牌套餐所包含的通话时长,上网流量,短信条数,月费用等 |
主菜单 | 退出系统 | 提出本系统 |
二级菜单 | 本月账单查询 | 可查询该卡号的套餐费用,实际消费金额,账户余额 |
二级菜单 | 套餐余量查询 | 可查询该卡号的套餐余量 |
二级菜单 | 打印消费详情 | 输入正确的卡号和密码后,可打印当前卡号用户的消费详单, 使用输出流把用户信息输出到文件 |
二级菜单 | 套餐变更 | 可变更为其他套餐类型,变更后话费余额需减去变更后的套餐费用,余额不足时需要给出信息提示,套餐变更后重新统计卡中实际消费数据以及当月消费金额 |
二级菜单 | 办理退网 | 输入正确的卡号和密码后,可以从已注册的号码列表中删除本号码,并退出系统 |
1.3项目效果简单演示:
2.功能实现主要代码:
2.1登录功能 :
在连接数据库后通过sql语句查询输入的账号密码是否在数据库中来进行登录判断
数据库查询代码:
public MoboleCard findMoboleCardByCardNumber(String CardNumber) throws SQLException {
String sql = "SELECT * FROM `tb_mobole_card` WHERE `card_number` = ?";
return qr.query(sql,new BeanHandler<MoboleCard>(MoboleCard.class),CardNumber);
}
2.2注册功能:
通过查询tb_card表中状态为0的卡号来展示出可供注册的卡号,在用户进行选择后选择想要的套餐,选择完成后将进行用户信息填写和录入
代码:
查询可用卡号:
@Override
public List<Card> findAllIsOK() throws SQLException {
String sql = "SELECT * FROM `tb_card` WHERE `status` = ? ";
return qr.query(sql,new BeanListHandler<Card>(Card.class),0);
}
用户信息录入(注册):
@Override
public boolean addMoboleCard(MoboleCard moboleCard) throws SQLException {
Connection con = JdbcUtil.getConnection();
String sql = "INSERT INTO `tb_mobole_card`(`card_number`,`username`,`password`,`ser_package`,`money`,`status`) VALUES(?,?,?,?,?,?)";
Object params[] = {
moboleCard.getCard_number(),moboleCard.getUsername(),moboleCard.getPassword(),
moboleCard.getSer_package(),moboleCard.getMoney(),moboleCard.getStatus()
};
int num = qr.update(con,sql,params);
JdbcUtil.release(con);
return num > 0 ? true : false;
}
2.3使用嗖嗖:
在用户输入要使用的手机号后,系统将对该手机号的状态进行查询,如果手机号的状态异常就会中止使用过程,如果手机号没有问题就会在六个使用场景中随机选出一个场景,如果用户的套餐不支持该场景的使用消耗就会通过相应的扣费规则进行扣费并且添加消费信息实现扣费
代码:
判断卡号是否存在:
System.out.println("请输入手机卡号:");
String cardNumber = scanner.nextLine();
try {
if(moboleCardService.findMoble(cardNumber) == null) {
System.out.println("用户不存在");
return;
}
使用场景及扣费:
Scene scene = new Scene();
if(sp.getName().equals("话痨套餐")){
int num = (int)(Math.random()*4)+1;
scene = situations[num];
if(mc.getReal_talk_time()>sp.getTalk_time()){
double money = 0.2*scene.getData();
}
System.out.println(scene.getDescription());
}
if(sp.getName().equals("网虫套餐")){
int num = (int)(Math.ceil(Math.random()))+4;
System.out.println(situations[num].getDescription());
}
if(sp.getName().equals("超人套餐")){
int num = (int)(Math.random()*5)+1;
System.out.println(situations[num].getDescription());
}
2.4话费充值:
在用户输入卡号后会对输入的卡号进行查询,在查询到数据后用户才能输入金额进行充值,在充值完成后会更新用户表中的金额信息以及在充值记录表中添加充值记录
代码:
查询和充值:
System.out.println("请输入您要充值的卡号:");
String cardNumber = sc.nextLine().trim();
MoboleCard card = moboleCardService.findMoble(cardNumber);
System.out.println(card);
if(card == null){
System.out.println("用户不存在!");
return;
}
System.out.println("请输入要充值的金额");
int money = sc.nextInt();
card.setMoney(card.getMoney()+money);
插入记录和更改账户信息(这一步应该用到事务来保证数据安全):
RechargeRecord record = new RechargeRecord(money,now,cardNumber);
if(moboleCardService.updateMoble(card)&&rechargeRecordService.addRecord(record))
System.out.println("充值成功!"+"卡上余额"+card.getMoney());
2.5资费说明:
查询套餐表并且输出每一个套餐的基本数据信息
代码:
public static void serPackagePrint(){
System.out.println("************套餐说明************");
System.out.println("序号\t套餐名称\t通话时长(分/月)\t短信条数(条/月)\t上网流量(GB/月)");
List<SerPackage> serPackageList = serPackageService.findAllSerPackage();
for(int i = 0 ; i < serPackageList.size();i++){
SerPackage serPackage = serPackageList.get(i);
System.out.println((i+1)+"\t"+serPackage.getName()+"\t"+serPackage.getTalk_time()
+"\t"+serPackage.getSms_count()+"\t"+(serPackage.getFlow()/1024));
}
}
2.6账户基本信息和记录查询代码:
余量查询:
Calendar cl = Calendar.getInstance();
int year = cl.get(Calendar.YEAR);
int month = cl.get(Calendar.MONTH)+1;
System.out.println("*************** 套餐余量查询 ***************");
System.out.println("你的卡号是:"+cardNumber+",套餐内剩余:");
SerPackage ser = serPackageService.findSerPackageByCardNumber(cardNumber);
MonthlyConsumptionRecords ms = null;
try {
ms = monthlyConsumptionRecordsService.getmonthlyconsumption(cardNumber,year,month);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
System.out.println("通话时长:"+(ser.getTalk_time()-ms.getReal_talk_time()));
System.out.println("短信条数:"+(ser.getSms_count()-ms.getReal_SMS_count()));
System.out.println("上网流量:"+((ser.getFlow()-ms.getReal_flow())/1024)+"G");
}
本月账单查询:
private static void QueryBills(String cardNumber) {
Calendar cl = Calendar.getInstance();
int year = cl.get(Calendar.YEAR);
int month = cl.get(Calendar.MONTH)+1;
System.out.println("*************** 本月账单查询 ***************");
System.out.println("您的卡号"+cardNumber+",当月账单:");
double SerpackagePrice = serPackageService.findSerPackageByCardNumber(cardNumber).getPrice();
System.out.println("套餐资费:"+SerpackagePrice);
double sumconsume = 0;
try {
sumconsume = SerpackagePrice+monthlyConsumptionRecordsService.getconsumamount(cardNumber,year,month);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
System.out.println("合计:"+sumconsume);
try {
System.out.println("账户余额:"+(moboleCardService.findMoble(cardNumber).getMoney()-sumconsume));
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
消费记录查询:
private static void QueryConsume(String cardNumber) throws SQLException {
boolean flag = true;
while (flag) {
System.out.println("*************** 消费详细查询 ***************");
Scanner sc = new Scanner(System.in);
System.out.println("请输入要查询的月份(1-12)");
int in = sc.nextInt();
List<ConsumeInfo> ci= consumeInfoService.getConsumeInfo(cardNumber,in);
if(ci.size() == 0){
System.out.println("本月无消费记录!");
flag = false;
break;
}
System.out.println("序号\t类型\t数据\t日期\t");
for (int i=0; i<ci.size(); i++){
System.out.println((i+1)+"\t"+ci.get(i).getType()+"\t"+ci.get(i).getConsum_data()+"\t"+ci.get(i).getConsume_date()+"\t");
}
}
2.7变更套餐:
在用户选择变更套餐选项后,系统会查询套餐表中的套餐名信息并且按序号输出套餐名,输出完成后需要用户选择想要的套餐,选择完毕后,系统将对用户信息进行判定,如果选择的套餐和用户信息的套餐一致,如果用户信息内的余额小于套餐的金额都会变更失败,如果都没有问题系统就会对用户信息的套餐进行更改,并且产生消费记录
代码:
private static void changeSerPacage(String cardNumber) {
try {
Scanner sc = new Scanner(System.in);
MoboleCard card = moboleCardService.findMoble(cardNumber);
SerPackage serPackage = serPackageService.findSerPackageByCardNumber(cardNumber);
System.out.println("*************** 套餐变更 ***************");
List<SerPackage> packages = serPackageService.findAllSerPackage();
for (int i = 0; i < packages.size(); i++) {
System.out.print((i+1)+"."+packages.get(i).getName()+" ");
}
System.out.print("请选择:");
int operation = sc.nextInt()-1;
SerPackage chosedpackage = packages.get(operation);
if (serPackage.getName().equals(chosedpackage.getName())) {
System.out.println("【友情提示】:您已经是该套餐的用户,无需更改");
return;
}
if(card.getMoney()<chosedpackage.getPrice()){
System.out.println("【友情提示】:对不起,您的余额不足以支付新套餐资费,请充值后办理变更套餐业务!");
return;
}
card.setMoney(card.getMoney()-chosedpackage.getPrice());
card.setSer_package(operation+1);
java.sql.Date consume_date = new java.sql.Date(new Date().getTime());
ConsumeInfo consumeInfo = new ConsumeInfo(cardNumber,"套餐变更", (int) chosedpackage.getPrice(),consume_date);
moboleCardService.changeSerPackage(card,consumeInfo);
System.out.println("【友情提示】:变更套餐成功!"+chosedpackage.getName()+":"+"通话时长:"
+chosedpackage.getTalk_time()+"分钟/月"+"短信条数:"+chosedpackage.getSms_count()+"条/月"
+"上网流量:"+(chosedpackage.getFlow()/1024)+"G/月"+"月租"+chosedpackage.getPrice()+"元/月");
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
2.8项目总代码:
链接:https://pan.baidu.com/s/1tetWgV_LdYqdT2iBVcQHMA?pwd=1234
提取码:1234
3项目总结以及心得
3.1遇到的问题:
在项目中,我也遇到了许多问题,比如Bean层的类的属性名和getter和setter方法的名称错误导致的无法读取数据库中的数据以至于不能查询到想要的结果;还有在编写sql语句时由于粗心导致的一些小错误。在对事务的理解和使用方面的一些问题导致我可能不能灵活地运用事务。对于时间运用方面我还存在一些问题,还有一点拖延的毛病,还有在做这次项目过程中我的程序设计大赛的项目进度也搁置了下来。
3.2本阶段的学习收获:
本阶段学习了MySQL和JDBC,将数据库和java编程结合起来,这些内容对我的挑战很大,也让我收获颇丰,在学习的过程中我学习并掌握了MySQL的基本语句,学会了使用java代码对数据库进行一系列的操作。在编程习惯上,我基本养成了写注释的习惯,并且以后也会注意保持。在学习心态上,我意识到了理论学习和实践操作上的区别,我也应该更加注重在学习知识后的练习巩固。