1.项目需求
中国移动,中国联通,中国电信是国内3大通信运营商,每个运营商都提供了不同的品牌套餐来应对不同的用户群,比如北京移动主要有全球通,神州行,动感地带等3大品牌套餐,每种套餐的内容和费用不同,嗖嗖移动是一个假定的通信运营商,提供了话痨套餐,网虫套餐,超人套餐,各种套餐所包含的服务内容及费用如下表:
| 品牌套餐 | 话痨套餐 | 网虫套餐 | 超人套餐 |
|———-|——|——|——|
| 通话时长(分钟) | 600 | 0 | 300 |
| 上网流量 | 0 | 20 | 10 |
| 短信条数(条) | 100 | 0 | 50 |
| 费用(元/月) | 58 | 68 | 78 |
如实际使用中超出套餐内包含的通话时长,短信条数和上网流量,则按一下规则计费:
超出的通话: 0.2元/分
超出的短信:0.1元/条
超出的上网流量:0.1元/MB
2.主要功能
一级菜单:1.用户登录 2.用户注册 3.使用嗖嗖 4.话费充值 5.资费说明 6.退出系统
当登录成功后会进入二级菜单
二级菜单: 1.本月账单查询 2.套餐余量查询 3.打印消费详单 4.套餐变更 5.办理退网
图片示例:

3.使用嗖嗖
功能分析
1) 模拟嗖嗖用户使用卡的过程,选择该功能后,输入当前卡号,通过验证后,可随机进入如下表的6个场景,要求所进入的场景的服务类型是该卡所属套餐支持的(如网虫套餐只能进入服务类型为"上网"的场景)
| 序号 | 服务类型 | 描述 |
|—-|——|————————–|
| 0 | 通话 | 问候客户,谁知其如此难缠,通话90分钟 |
| 1 | 通话 | 询问妈妈身体状况,本地通话30分钟 |
| 2 | 短信 | 参与环境保护实施方案问卷调查,发送短信5条 |
| 3 | 短信 | 同时朋友本人已换手机号码,发送短信50条 |
| 4 | 上网 | 和女朋友微信视频聊天,使用流量1GB |
| 5 | 上网 | 晚上手机在线追剧,一不留神睡着了,使用流量2GB |
2) 模拟消费,进入场景之后,将按场景的描述要求消费套餐余量,如果套餐余量不足,则需要按套餐外的费用规则扣费,成功消费后,添加一条消费记录
4.项目使用的技术
面向对象的思想
封装,继承,多态,接口的使用
异常处理的合理使用
集合框架的使用
I/O 操作实现对文件的写
MySQL数据
JDBC操作数据库
5.思路分析
刚开始面对这个项目,你可能不知道从何开始写起,我们可以先搭建好一个三层架构,然后再开始往里面填充,逐步完善。这里我们需要对一些方法进行封装。一共包括三层,dao层,服务层,显示层,我们需要用两个接口约束dao层与服务层的方法行为,另外我们需要封装一个工具类用来处理sql语句。此外你还需要在数据库内建好你所需要的表格
6.部分代码展示
展示两个dao 层的方法:
package soso.dao.impl;
import soso.dao.SosoDao;
import soso.model.*;
import soso.until.JDBCUtil;
import java.sql.*;
import java.util.*;
import java.util.Date;
public class SosoDaoImpl implements SosoDao {
//注册功能
@Override
public int register(Userinfo userinfo) {
Scanner scanner = new Scanner(System.in);
System.out.println("----可选择的卡号----");
String sql="SELECT * FROM tb_card WHERE status=0";
List<Tb_card> tbCards = JDBCUtil.executeQuery(sql, Tb_card.class);
for (Tb_card tbCard : tbCards) {
System.out.println(tbCard);
}
int id=scanner.nextInt();
//电话号码
String cardNumber = tbCards.get(id - 1).getCardNumber();
userinfo.setCard_number(cardNumber);
String sql1="SELECT * FROM tb_serpackage_type";
List<Tc_type> tcTypes = JDBCUtil.executeQuery(sql1, Tc_type.class);
for (Tc_type tcType : tcTypes) {
System.out.println(tcType);
}
System.out.println("请选择套餐:");
//套餐类型
int b=scanner.nextInt();
userinfo.setSer_package(b);
System.out.println("请输入姓名:");
String name=scanner.next();
userinfo.setUsername(name);
System.out.println("请输入密码:");
String pw=scanner.next();
userinfo.setPassword(pw);
//查询套餐详情
String sql2="select * from tb_serpackage";
List<Set_meal> setMeals = JDBCUtil.executeQuery(sql2, Set_meal.class);
double amount;
while (true){
System.out.println("请输入预存话费金额:");
amount=scanner.nextDouble();
double amount1=amount-setMeals.get(b-1).getPrice();
if (amount1<0){
System.out.println("您预存话费不足以支付本月套餐费用,请重新输入:");
}else {
System.out.println("充值成功!");
userinfo.setMoney(amount1);
break;
}
}
System.out.println("注册成功:卡号:"+userinfo.getCard_number()+",用户名:"+userinfo.getUsername()
+",当前余额:"+userinfo.getMoney()+"元");
System.out.println(tcTypes.get(b-1).getName()+"通话时长:"+setMeals.get(b-1).getTalk_time()+"分钟/月");
//插入用户信息
String sql3="insert into `tb_mobole_card`(`card_number`,`username`,`password`,`ser_package`,`money`) values" +
" (?,?,?,?,?)";
//插入充值记录
String sql4="INSERT into tb_recharge_record (`amount`,`recharge_date`,`card_number`) values " +
"(?,?,?)";
JDBCUtil.executeUpdate(sql4,amount,new Date(),cardNumber);
//插入余量,余额表 包括套餐类型,名字,号码,余额
insert(b,name,cardNumber,userinfo.getMoney());
//返回值
return JDBCUtil.executeUpdate(sql3,userinfo.getCard_number(),userinfo.getUsername(),
userinfo.getPassword(),userinfo.getSer_package(),userinfo.getMoney());
}
public void insert(int option,String name,String cardNumber,Double amount){
if (option==1){
String sql5="INSERT INTO margin (username,card_number,type, talk_time,sms_count, flow, money) " +
"VALUES (?,?,1,600,100,0,?)";
JDBCUtil.executeUpdate(sql5,name,cardNumber,amount);
System.out.println("成功插入套餐1的余量,余额");
} else if (option==2) {
String sql6="INSERT INTO margin (username,card_number,type, talk_time,sms_count, flow, money) " +
"VALUES (?,?,2,0,0,20480,?)";
JDBCUtil.executeUpdate(sql6,name,cardNumber,amount);
System.out.println("成功插入套餐2的余量,余额");
} else if (option==3) {
String sql7="INSERT INTO margin (username,card_number,type, talk_time,sms_count, flow, money) " +
"VALUES (?,?,3,300,50,10240,?)";
JDBCUtil.executeUpdate(sql7,name,cardNumber,amount);
System.out.println("成功插入套餐3的余量,余额");
}else {
System.out.println("输入的套餐号不对!");
}
}
这里所展示的是注册功能,里面调用了一个方法,它是将你选择的套餐添加到余量表中,为了方便以后的查询。
@Override
public int recharge() {
Scanner scanner = new Scanner(System.in);
List<Userinfo> tbCards=null;
int count;
while (true){
System.out.println("*********话费充值*********");
System.out.println("请输入要充值卡号:");
String num=scanner.next();
String sql="SELECT * FROM tb_mobole_card WHERE card_number=?";
tbCards = JDBCUtil.executeQuery(sql,Userinfo.class, num);
if (tbCards.size()==1){
break;
}else {
System.out.println("输入的号码错误,请重新输入");
}
}
while (true){
System.out.println("请输入充值金额:");
Double money=scanner.nextDouble();
if(money>0){
//插入充值记录
String sql1="INSERT into tb_recharge_record (`amount`,`recharge_date`,`card_number`) values " +
"(?,?,?)";
count = JDBCUtil.executeUpdate(sql1, money, new Date(), tbCards.get(0).getCard_number());
//将充值金额添加到用户余额
String sql2="UPDATE tb_mobole_card SET money=money+? WHERE card_number=?";
JDBCUtil.executeUpdate(sql2,money,tbCards.get(0).getCard_number());
//查询卡中余额
String sql3="SELECT * FROM tb_mobole_card WHERE card_number=?";
List<Userinfo> userinfos = JDBCUtil.executeQuery(sql3, Userinfo.class, tbCards.get(0).getCard_number());
Double balance=userinfos.get(0).getMoney();
System.out.println("【友情提示】:充值成功,卡上余额:"+balance+"元");
break;
}
else {
System.out.println("输入金额小于0,请重新输入");
}
}
return count;
}
这里展示的充值功能,先输入手机号码,判断是否输入错误,然后再输入金额数值,判断是否够套餐所需要的费用,再两者相减,得到余额。
这里简单的说明一下使用嗖嗖的代码,首先输入你的手机号码,然后模拟使用环境,判断是否超出套餐余额,如果没有超出。则扣除套餐余额,否则按超出套餐外的规则计费,由于要重复使用一些功能,例如,插入消费记录,修改余量余额表,我们可以将它们分别封装成两个方法,然后按照不同的扣费方式进行调用,这样有利于维护和增加代码的可读性。
后面的服务层和显示层就是分别逐层调用dao层的方法,这里就不过多赘述。
7.总结
这个项目,让我体会到了封装的重要性,对于那些要重复运用的代码,应当进行封装,以便于调用和维护,现在通过对三层架构的学习,让我对项目有了一个整体的思路和框架,可以慢慢的对项目,进行填充完善。通过对数据库sql语句的学习,让我们的代码变得更加简洁。在数据库建完表格后,实现增删改查,就只需要几行代码就解决了。由于这个项目是在控制台实现输入输出,所以显得繁琐,但是它可以让你的逻辑思维变得更加清晰。
原文链接: https://blog.csdn.net/2302_78593467/article/details/140937781