嗖嗖移动业务大厅

1. 项目需求

中国移动,中国联通,中国电信是国内3大通信运营商,每个运营商都提供了不同的品牌套餐来应对不同的用户群,比如北京移动主要有全球通,神州行,动感地带等3大品牌套餐,每种套餐的内容和费用不同,嗖嗖移动是一个假定的通信运营商,提供了话痨套餐,网虫套餐,超人套餐,各种套餐所包含的服务内容及费用如下表:

如实际使用中超出套餐内包含的通话时长,短信条数和上网流量,则按一下规则计费:

* 超出的通话: 0.2元/分
* 超出的短信:0.1元/条
* 超出的上网流量:0.1元/MB

本任务实现的"嗖嗖移动业务大厅"提供了嗖嗖移动用户的常用功能,包括新用户注册,本月账单查询,套餐余量查询,打印消费详情,套餐变更,办理退网,话费充值,查看消费记录,查看话费说明等功能.另外,还可以模拟用户通话,上网,发送短信的场景进行相应的扣费并记录消费信息.各功能介绍如下表:

2. 项目使用的技术 

面向对象的思想
封装,继承,多态,接口的使用
异常处理的合理使用
集合框架的使用

MySQL数据
JDBC操作数据库

dao开发模式

数据访问对象(DAO):DAO是一个接口或抽象类,定义了对数据的基本操作方法,如增加、删除、修改、查询等。 数据访问对象实现类(DAO实现类):DAO实现类是对DAO接口的具体实现,负责实现具体的数据访问逻辑 实体对象(Entity):实体对象是业务逻辑层与数据访问层之间的数据传输对象。它通常对应于数据存储中的一张表或一个文档,包含了与业务相关的数据和属性。

数据访问对象(DAO):DAO是一个接口或抽象类,定义了对数据的基本操作方法,如增加、删除、修改、查询等。

数据访问对象实现类(DAO实现类):DAO实现类是对DAO接口的具体实现,负责实现具体的数据访问逻辑

实体对象(Entity):实体对象是业务逻辑层与数据访问层之间的数据传输对象。它通常对应于数据存储中的一张表或一个文档,包含了与业务相关的数据和属性。

queryRunner

package com.fs.soso.dao.impl;

import com.fs.soso.dao.CradDao;
import com.fs.soso.entity.Crad;
import com.fs.soso.utils.JDBCUtil;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

/**
 * @author hua
 * @version 1.0
 * @title CradDaoImpl
 * @description 电话号码Dao实现类
 * @create 2024/1/5 16:53
 */
public class CradDaoImpl implements CradDao {
    @Override
    public List<Crad> queryAll() {
        Connection conn = null;
        try {
            conn = JDBCUtil.getConnection();
            QueryRunner queryRunner=new QueryRunner();
            String sql ="select * from tb_card";
            List<Crad> crads = queryRunner.query(conn,sql,new BeanListHandler<Crad>(Crad.class));
            return crads;
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            JDBCUtil.close(conn);
        }
        return null;
    }

    @Override
    public Crad queryById(Integer id) {
        Connection conn = null;
        try {
            conn = JDBCUtil.getConnection();
            QueryRunner  queryRunner=new QueryRunner();
            String sql ="select * from tb_card where id = ?";
            Crad crad = queryRunner.query(conn,sql,new BeanHandler<Crad>(Crad.class),id);
            return crad;
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return null;
    }

    @Override
    public int insert(Crad crad) {
        Connection conn = null;
        try {
            conn = JDBCUtil.getConnection();
            QueryRunner  queryRunner=new QueryRunner();
            String sql ="insert into tb_card values(null,?,?)";
            return queryRunner.update(conn,sql,crad.getCardNumber(),crad.getStatus());
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return 0;
    }

    @Override
    public int updateByID(Crad crad) {
        Connection conn = null;
        try {
            conn = JDBCUtil.getConnection();
            QueryRunner  queryRunner=new QueryRunner();
            String sql ="update tb_card set cardNumber=?, status=? where id=?";
            return queryRunner.update(conn,sql,crad.getCardNumber(),crad.getStatus(),crad.getId());
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            JDBCUtil.close(conn);
        }
        return 0;
    }

    @Override
    public int deleteById(Integer id) {
        Connection conn = null;
        try {
            conn = JDBCUtil.getConnection();
            String sql ="delete from tb_card where id=?";
            QueryRunner  queryRunner=new QueryRunner();
            return queryRunner.update(conn,sql,id);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return 0;
    }

    @Override
    public int updateByCardNumber(String cardNumber) {
        Connection conn = null;
        try {
            conn = JDBCUtil.getConnection();
            QueryRunner  queryRunner=new QueryRunner();
            String sql ="update tb_card set status=0 where cardNumber=?";
            return queryRunner.update(conn,sql,cardNumber);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            JDBCUtil.close(conn);
        }
        return 0;
    }
}

QueryRunner在执行SQL操作后会自动关闭相关的资源,如Connection、Statement和ResultSet等。这样可以避免手动管理资源的繁琐工作,同时也减少了资源泄漏的风险。

ueryRunner提供了一组简化的API,使得执行SQL查询和更新操作变得更加简单。它封装了JDBC的底层细节,隐藏了大量的冗余代码,使得开发人员可以更专注于业务逻辑的实现。

Junit测试

package com.fs.soso.dao;

import com.fs.soso.constant.SystemConstant;
import com.fs.soso.dao.impl.CradDaoImpl;
import com.fs.soso.entity.Crad;
import org.junit.Test;

import java.util.*;

import static org.junit.Assert.*;

/**
 * @author hua
 * @version 1.0
 * @title CradDaoTest
 * @description
 * @create 2024/1/8 10:11
 */
public class CradDaoTest implements SystemConstant {
    CradDao cradDao=new CradDaoImpl();

    @Test
    public void queryAll() {
        List<Crad> crads=cradDao.queryAll();
        for (Crad crad:crads) {
            System.out.println(crad);
        }
    }

    @Test
    public void queryById() {
        Crad crad =cradDao.queryById(4);
        System.out.println(crad);
    }

    @Test
    public void insert() {
        Crad crad=new Crad("12345678910",SystemConstant.CRAD_NO_USED);
        int result = cradDao.insert(crad);
        System.out.println(result);
    }

    @Test
    public void updateByID() {
        Crad crad=new Crad("12345678910",SystemConstant.CRAD_USED);
        int result = cradDao.updateByID(crad);
        System.out.println(result);
    }

    @Test
    public void deleteById() {
        System.out.println((int)Math.random());
    }

}

简单易用:JUnit提供了一组简单易用的API,使得编写和运行单元测试变得更加容易。开发人员只需要编写一些简单的测试方法,就可以快速测试代码的正确性。

注解支持:JUnit支持使用注解来标记测试方法和测试类。开发人员可以使用@Test注解标记测试方法

自动化测试:JUnit可以自动运行测试方法,并生成测试报告。开发人员只需要编写测试方法,JUnit会自动运行这些方法,并输出测试结果和错误信息。

3.项目成果展示

实体类

package com.fs.soso.entity;

import java.util.Date;

/**
 * @author hua
 * @version 1.0
 * @title ConsumInfo
 * @description 消费信息类
 * @create 2024/1/5 16:06
 */
public class ConsumInfo extends Base{
    private String cardNumber;
    private String type;
    private Integer consumData;
    private Date consumeDate;

    public ConsumInfo() {
    }

    public ConsumInfo(String cardNumber, String type, Integer consumData, Date consumeDate) {
        this.cardNumber = cardNumber;
        this.type = type;
        this.consumData = consumData;
        this.consumeDate = consumeDate;
    }

    public String getCardNumber() {
        return cardNumber;
    }

    public void setCardNumber(String cardNumber) {
        this.cardNumber = cardNumber;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public Integer getConsumData() {
        return consumData;
    }

    public void setConsumData(Integer consumData) {
        this.consumData = consumData;
    }

    public Date getConsumeDate() {
        return consumeDate;
    }

    public void setConsumeDate(Date consumeDate) {
        this.consumeDate = consumeDate;
    }

    @Override
    public String toString() {
        return "ConsumInfo{" +
                "id=" + getId() +
                ", cardNumber='" + cardNumber + '\'' +
                ", type='" + type + '\'' +
                ", consumData=" + consumData +
                ", consumeDate=" + consumeDate +
                '}';
    }
}

dao层

package com.fs.soso.dao;

import com.fs.soso.entity.ConsumInfo;

import java.util.List;

/**
 * @author hua
 * @version 1.0
 * @title BaseDao
 * @description
 * @create 2024/1/9 10:31
 */
public interface BaseDao <T>{
    List<T> queryAll();

    /**
     * 根据主键查询
     * @param id
     * @return
     */
    T queryById(Integer id);

    /**
     * 添加
     * @param t
     * @return
     */
    int insert(T t);

    /**
     * 修改
     * @param t
     * @return
     */
    int updateByID(T t);

    /**
     * 根据主键删除
     * @param id
     * @return
     */
    int deleteById(Integer id);
}
package com.fs.soso.dao;

import com.fs.soso.entity.ConsumInfo;

import java.util.Date;
import java.util.List;

/**
 * @author hua
 * @version 1.0
 * @title ConsumInfoDao
 * @description 消费信息DAO类
 * @create 2024/1/5 16:38
 */
public interface ConsumInfoDao extends BaseDao<ConsumInfo>{
    List<ConsumInfo> queryByConsumeDate(String cardNumber,Date consumeDate);
    int deleteByCardNumber(String cardNumber);
}

dao实现类

package com.fs.soso.dao.impl;

import com.fs.soso.dao.ConsumInfoDao;
import com.fs.soso.entity.ConsumInfo;
import com.fs.soso.utils.DateUtil;
import com.fs.soso.utils.JDBCUtil;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler;

import java.sql.*;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.Date;

/**
 * @author hua
 * @version 1.0
 * @title ConsumInfoDaoImpl
 * @description 消费信息DAO实现类
 * @create 2024/1/5 16:52
 */
public class ConsumInfoDaoImpl implements ConsumInfoDao {
    @Override
    public List<ConsumInfo> queryAll() {
        return null;
    }

    @Override
    public ConsumInfo queryById(Integer id) {
        return null;
    }

    @Override
    public int insert(ConsumInfo consumInfo) {
        Connection conn = null;
        try {
            conn = JDBCUtil.getConnection();
            QueryRunner queryRunner=new QueryRunner();
            String date = DateUtil.getDate(new Date());
            String sql ="insert into tb_consuminfo values(null,?,?,?,?)";
            return queryRunner.update(conn,sql,consumInfo.getCardNumber(),
                    consumInfo.getType(),consumInfo.getConsumData(),
                    date);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            JDBCUtil.close(conn);
        }
        return 0;
    }

    @Override
    public int updateByID(ConsumInfo consumInfo) {
        Connection conn = null;
        QueryRunner queryRunner=new QueryRunner();
        try {
            conn = JDBCUtil.getConnection();
            String sql ="update tb_consuminfo set card_number=?,type=?,consum_data=?,consume_date=? where id=?";
            return queryRunner.update(sql,consumInfo.getCardNumber(),
                    consumInfo.getType(),consumInfo.getConsumData(),
                    consumInfo.getConsumeDate(),consumInfo.getId());
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            JDBCUtil.close(conn);
        }
        return 0;
    }

    @Override
    public int deleteById(Integer id) {
        Connection conn = null;
        PreparedStatement pstm = null;
        try {
            conn = JDBCUtil.getConnection();
            String sql ="delete from tb_consuminfo where id=?";
            pstm = conn.prepareStatement(sql);
            pstm.setObject(1,id);
            return pstm.executeUpdate();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return 0;
    }

    @Override
    public List<ConsumInfo> queryByConsumeDate(String cardNumber,Date consumeDate) {
        Connection conn = null;
        try {
            conn = JDBCUtil.getConnection();
            QueryRunner queryRunner=new QueryRunner();
            String sql ="select id,card_number cardNumber,type," +
                    "consum_data consumData,consume_date consumeDate from tb_consuminfo " +
                    "where card_number=? and YEAR(consume_date) = ? and MONTH(consume_date)=?";
            return queryRunner.query(conn,sql,new BeanListHandler<ConsumInfo>(ConsumInfo.class),
                    cardNumber,1900+consumeDate.getYear(),consumeDate.getMonth()+1);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            JDBCUtil.close(conn);
        }
        return null;
    }

    @Override
    public int deleteByCardNumber(String cardNumber) {
        Connection conn = null;
        try {
            conn = JDBCUtil.getConnection();
            QueryRunner queryRunner = new QueryRunner();
            String sql ="delete from tb_consuminfo where card_number=?";
            return queryRunner.update(conn,sql,cardNumber);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            JDBCUtil.close(conn);
        }
        return 0;
    }
}

嗖嗖服务类

/**
     * 办理退网
     * @param moboleCard 嗖嗖移动卡
     */
    public static void outMoboleCard(MoboleCard moboleCard){
        if(moboleCard.getMoney()<0){
            System.out.println("你有欠款"+moboleCard.getMoney()+",请充值后再退网");
        }else {
            // 删除id对应的嗖嗖移动卡对象
            MoboleCardDao moboleCardDao = new MoboleCardDaoImpl();
            moboleCardDao.deleteById(moboleCard.getId());
            // 解冻卡号对应的卡
            CradDao cradDao = new CradDaoImpl();
            cradDao.updateByCardNumber(moboleCard.getCardNumber());
            // 删除卡号对应的月账单
            MonthlyConsumptionRecordsDao monthlyConsumptionRecordsDao = new MonthlyConsumptionRecordsDaoImpl();
            monthlyConsumptionRecordsDao.deleteByCardNumber(moboleCard.getCardNumber());
            // 删除卡号对应的充值记录
            RechargeRecordDao rechargeRecordDao = new RechargeRecordDaoImpl();
            rechargeRecordDao.deleteByCardNumber(moboleCard.getCardNumber());
            // 删除卡号对应的消费记录
            ConsumInfoDao consumInfoDao = new ConsumInfoDaoImpl();
            consumInfoDao.deleteByCardNumber(moboleCard.getCardNumber());
            // 删除卡号对应的充值流量包记录
            FlowRechargeRecordDao flowRechargeRecordDao = new FlowRechargeRecordDaoImpl();
            flowRechargeRecordDao.deleteByCardNumber(moboleCard.getCardNumber());

            System.out.println("[友情提示] :卡号" + moboleCard.getCardNumber() + "办理退网成功! ");
        }
    }

4.创新点展示

    /**
     * 忘记密码
     */
    public static void forgetPassword(){
        System.out.println("*******忘记密码*******");
        System.out.println("请输入卡号:");
        String cardNumber = scanner.next();
        // 查询卡号对应的嗖嗖移动卡对象
        MoboleCardDao moboleCardDao = new MoboleCardDaoImpl();
        MoboleCard moboleCard = moboleCardDao.queryByCardNumber(cardNumber);
        if (moboleCard == null) {
            System.out.println("请输入正确的卡号");
        }else if (moboleCard.getStatus() == SystemConstant.MOBOLE_STATUS_FREEZE) {
            System.out.println("该号码已被冻结,请联系管理员");
        }else {
            System.out.println("请输入密码");
            String password = scanner.next();
            moboleCard.setPassword(password);
            moboleCardDao.updateByID(moboleCard);
            System.out.println("密码修改成功,请重新登录");
        }
    }
    /**
     * 申请解冻
     */
    public static void thaw(){
        System.out.println("*******申请解冻*******");
        System.out.println("请输入卡号");
        String cardNumber = scanner.next();
        // 查询卡号对应的嗖嗖移动卡对象
        MoboleCardDao moboleCardDao = new MoboleCardDaoImpl();
        MoboleCard moboleCard = moboleCardDao.queryByCardNumber(cardNumber);
        if (moboleCard == null) {
            System.out.println("请输入正确的卡号");
        } else {
            if (moboleCard.getMoney()<0){
                //解冻前不能欠款
                System.out.println("您有欠款"+moboleCard.getMoney()+"元,请充值后再解冻");
            }else  if(moboleCard.getStatus()==SystemConstant.MOBOLE_STATUS_NORMAL){
                //嗖嗖移动卡对象为正常
                System.out.println("您无需解冻");
            }else {
                //解冻嗖嗖移动卡对象
                moboleCard.setStatus(SystemConstant.MOBOLE_STATUS_NORMAL);
                moboleCardDao.updateByID(moboleCard);
                System.out.println("卡号"+moboleCard.getCardNumber()+"已解冻");
            }
        }
    }
/**
     * 购买流量
     * @param moboleCard 嗖嗖移动卡
     */
    public static void addFlow(MoboleCard moboleCard){
        System.out.println("序号\t套餐名称\t\t上网流量\t价格\t\t使用期限");
        // 查询所有流量包
        FlowPackageDao flowPackageDao=new FlowPackageDaoImpl();
        List<FlowPackage> flowPackages = flowPackageDao.queryAll();

        for (FlowPackage flowPackage:flowPackages) {
            System.out.println(flowPackage.getId()+"\t"+flowPackage.getName()
            +"\t"+flowPackage.getData()/1024+"GB\t\t"+flowPackage.getMoney()
            +"元\t"+flowPackage.getUseDay()+"天");
        }
        System.out.println("请选择套餐");
        int id=scanner.nextInt();
        FlowPackage flowPackage=new FlowPackage();

        List<FlowPackage> collect = flowPackages.stream()
                .filter(f -> f.getId() == id)
                .collect(Collectors.toList());
        if (collect.isEmpty()){
            System.out.println("没有该套餐");
        }else {
            flowPackage=collect.get(0);
        }
        // 插入一条流量包购买记录
        FlowRechargeRecordDao flowRechargeRecordDao=new FlowRechargeRecordDaoImpl();
        DateUtil.getPastDueDate(new Date(),flowPackage.getUseDay());
        FlowRechargeRecord flowRechargeRecord=new FlowRechargeRecord(
                flowPackage.getData(),new Date(),
                DateUtil.getPastDueDate(new Date(),flowPackage.getUseDay()),
                moboleCard.getCardNumber());
        flowRechargeRecordDao.insert(flowRechargeRecord);

        System.out.println("您已购买"+flowPackage.getName());
        // 插入一条消费记录
        ConsumInfoDao consumInfoDao=new ConsumInfoDaoImpl();
        ConsumInfo consumInfo =new ConsumInfo(moboleCard.getCardNumber(),"充值流量包",flowPackage.getData(),new Date());
        consumInfoDao.insert(consumInfo);
        // 扣除嗖嗖移动卡余额
        moboleCard.setMoney(moboleCard.getMoney()-flowPackage.getMoney());
        MoboleCardDao moboleCardDao=new MoboleCardDaoImpl();
        moboleCardDao.updateByCardNumber(moboleCard,moboleCard.getCardNumber());
    }

6.总结

亮点之处

采用了queryRunner,封装了JDBC的底层细节,隐藏了大量的冗余代码,自动关闭相关的资源,避免手动管理资源的繁琐工作

采用了Junit测试,使得编写和运行单元测试变得更加容易,保证了dao层代码的准确性

在原有的基础上添加了大量创新,使项目更加具有独特型,不可复制性

不足之处

不是很记得使用Java的三大要素,分明有重复的的代码,却不能记得自己封装。

总是不写注释,导致在修改的时候,要分析半天

soso服务类代码有点冗余,逻辑比较复杂,但我也不敢改

  • 28
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值