Java 模拟实现简易的ATM系统

前言

        本次,我将分享自己在学习Java过程中的一个小项目——一个简易的ATM系统。尽管它功能简单且存在诸多可以改进之处,但它承载了我从零开始构建一个小型应用系统的喜悦与挑战。

项目需求

        实现简易版的ATM系统功能,包括登录,取款,存款,转账,查询余额,修改密码等功能。

实现步骤

1.数据库设计

        设计一张account表,其中包含id(账户),name(姓名),password(密码),money(账户金额)四个属性,id和password用于登录账户

对应entity类:

public class Account {
    private Integer id;//账户
    private String name;//姓名
    private String password;//密码
    private BigDecimal money;//账户余额

    public Account(Integer id, String name, String password, BigDecimal money) {
        this.id = id;
        this.name = name;
        this.password = password;
        this.money = money;
    }

    public Account() {

    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public BigDecimal getMoney() {
        return money;
    }

    public void setMoney(BigDecimal money) {
        this.money = money;
    }

    @Override
    public String toString() {
        return "Account{" + "id=" + id + ", name='" + name + '\'' + ", password='" + password + '\'' + ", money=" + money + '}';
    }
}

2.各功能实现

        2.1登录功能

要求:

        输入卡号及密码后,与数据库中信息进行比对,若卡号和密码都匹配则登陆成功,反之提示卡号或密码不正确。

        2.2菜单界面

        2.3取款功能

要求:

        1.取款金额大于0

        2.单次取款限制金额最大为20000

        3.取款金额不能大于账户余额

        2.4存款功能

要求:

        1.存款金额大于0

        2.单次存款金额上限为50000

        2.5转账功能

要求:

        1.转账金额大于0

        2.不可以向自己转账

        3.转账金额不可大于账户余额

        4.需要验证密码来确认转账

        2.6余额查询功能

要求:输入密码进行验证,密码正确后方可查询余额

        2.7修改密码

要求:

        1.输入原密码进行验证

        2.输入新密码,并再次输入新密码,验证两次密码是否一致

3.编码实现

        3.1 代码结构

        分别创建entity包,Dao包,service包,util包,以提高代码的复用性,结构如图:

        3.2 数据库的连接

        在util包中定义Dbutil类,用如下方法实现数据库的连接:
        静态初始化块:
                1.在类加载时执行一次,读取配置文件db.properties中的数据库连接信息。
                2.使用Properties类来加载配置文件,并从中获取数据库驱动、URL、用户名和密码。

        获取数据库连接方法:
                1.通过调用DriverManager.getConnection(url, user, password)方法来建立与数据库的实际连接。
                2.如果成功建立连接,则返回Connection对象;如果失败,则捕获SQLException并打印堆栈跟踪信息,最后返回null。
        关闭所有资源:
                1.接受三个参数:结果集(ResultSet)、预编译语句(PreparedStatement)和数据库连接(Connection)。
                2.检查每个参数是否为null,如果不为null则尝试关闭它们。
                3.如果在关闭过程中发生异常,会抛出一个运行时异常

public class Dbutils {
    private static String driver;
    private static String url;
    private static String user;
    private static String password;

    //  注册驱动
    static {
        try {
            Properties properties = new Properties();
            InputStream is = Dbutils.class.getClassLoader().getResourceAsStream("db.properties");
            properties.load(is);
            is.close();

            driver = properties.getProperty("driver");
            url = properties.getProperty("url");
            user = properties.getProperty("user");
            password = properties.getProperty("password");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    //  获取连接
    public static Connection getConnection() {
        try {
            return DriverManager.getConnection(url, user, password);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    //  释放资源
    public static void closeAll(ResultSet rs, PreparedStatement pstat, Connection conn) {
        try {
            if (rs != null) {
                rs.close();
            }
            if (pstat != null) {
                pstat.close();
            }
            if (conn != null) {
                conn.close();
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
}

        3.3 Dao封装:提高数据操作代码的重用性

        在Dao包下创建AccountDao接口

public interface AccountDao {
    // 卡号和密码查询
    Account selectByIdAndPassword(int id, String password);

    // 查询余额
    BigDecimal selectMoney(int id);

    //更新取款
    void updateWithdrawMoney(int id, BigDecimal m);

    //更新存款
    void updateDepositMoney(int id, BigDecimal m);

    //修改密码
    void updateChangePwd(int id, String password);
}

         在Dao包下建立impl子包,并创建AccountDaoImpl类,用于实现AccountDao接口

public class AccountDaoImpl implements AccountDao {
    // 卡号和密码查询
    public Account selectByIdAndPassword(int id, String password) {
        Connection conn = null;
        PreparedStatement pstat = null;
        ResultSet rs = null;
        try {
            conn = Dbutils.getConnection();
            if (conn != null) {
                pstat = conn.prepareStatement("select id,name,password,money from account where id=? and password=?;");
            } else {
                System.out.println("数据库连接失败!");
            }
            pstat.setObject(1, id);
            pstat.setObject(2, password);
            rs = pstat.executeQuery();
            if (rs.next()) {
                id = rs.getInt("id");
                String name = rs.getString("name");
                password = rs.getString("password");
                BigDecimal money = rs.getBigDecimal("money");
                Account account = new Account(id, name, password, money);
                return account;
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            Dbutils.closeAll(rs, pstat, conn);
        }
        return null;
    }

    // 询余额
    public BigDecimal selectMoney(int id) {
        Connection conn = null;
        PreparedStatement pstat = null;
        ResultSet rs = null;
        BigDecimal money = null;
        try {
            conn = Dbutils.getConnection();
            if (conn != null) {
                pstat = conn.prepareStatement("select money from account where id=?;");
            } else {
                System.out.println("数据库连接失败!");
            }
            pstat.setObject(1, id);
            rs = pstat.executeQuery();
            if (rs.next()) {
                money = rs.getBigDecimal("money");
            } else {
                throw new RuntimeException("查询失败!");
            }
            return money;
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            Dbutils.closeAll(rs, pstat, conn);
        }
    }

    //更新取款
    public void updateWithdrawMoney(int id, BigDecimal m) {
        Connection conn = null;
        PreparedStatement pstat = null;
        try {
            conn = Dbutils.getConnection();
            if (conn != null) {
                pstat = conn.prepareStatement("update account set money = money - ? where id = ?;");
            } else {
                System.out.println("数据库连接失败!");
            }
            pstat.setObject(1, m);
            pstat.setObject(2, id);
            pstat.executeUpdate();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            Dbutils.closeAll(null, pstat, conn);
        }
    }

    //更新存款
    public void updateDepositMoney(int id, BigDecimal m) {
        Connection conn = null;
        PreparedStatement pstat = null;
        try {
            conn = Dbutils.getConnection();
            if (conn != null) {
                pstat = conn.prepareStatement("update account set money = money + ? where id = ?;");
            } else {
                System.out.println("数据库连接失败!");
            }
            pstat.setObject(1, m);
            pstat.setObject(2, id);
            pstat.executeUpdate();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            Dbutils.closeAll(null, pstat, conn);
        }
    }

    //修改密码
    public void updateChangePwd(int id, String password) {
        Connection conn = null;
        PreparedStatement pstat = null;
        try {
            conn = Dbutils.getConnection();
            if (conn != null) {
                pstat = conn.prepareStatement("update account set password=? where id=?");
            } else {
                System.err.println("数据库连接失败!");
            }
            pstat.setObject(1, password);
            pstat.setObject(2, id);
            pstat.executeUpdate();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            Dbutils.closeAll(null, pstat, conn);
        }
    }
}

        3.4 Service封装:提高业务功能代码的重用性

        在DService包下创建AccountService接口

public interface AccountService {
    // 登录
    Account login(int id, String password);

    // 取款
    void withdrawMoney(int id, BigDecimal m);

    // 存款
    void depositMoney(int id, BigDecimal m);

    // 转账
    void transferAccounts(int fromId, int toId, BigDecimal m);

    // 修改密码
    void changePwd(int id, String password);

    // 查询余额
    BigDecimal selectBalance(int id);
}

        在Service包下建立impl子包,并创建AccountServiceImpl类,用于实现AccountService接口

public class AccountServiceImpl implements AccountService {
    // 登录
    public Account login(int id, String password) {
        AccountDao accountDao = new AccountDaoImpl();
        Account account = accountDao.selectByIdAndPassword(id, password);
        if (id != account.getId() || !password.equals(account.getPassword())) {
            throw new RuntimeException("卡号或密码不正确!");
        }
        return account;
    }

    // 取款
    public void withdrawMoney(int id, BigDecimal m) {
        AccountDao accountDao = new AccountDaoImpl();
        // 取款金额必须大于0
        if (m.compareTo(new BigDecimal(0)) <= 0) {
            throw new RuntimeException("取款金额必须大于零!");
        }
        // 一次最多取款20000
        if (m.compareTo(new BigDecimal("20000")) > 0) {
            throw new RuntimeException("单次取款限制两万元!");
        }
        // 取款数目必须小于等于账户余额
        BigDecimal balance = accountDao.selectMoney(id);
        if (balance.compareTo(m) > 0) {
            accountDao.updateWithdrawMoney(id, m);
            System.out.println("取款交易成功!");
        } else {
            throw new RuntimeException("余额不足,无法完成交易!");
        }
    }

    // 存款
    public void depositMoney(int id, BigDecimal m) {
        AccountDao accountDao = new AccountDaoImpl();
        // 存款金额必须大于0
        if (m.compareTo(new BigDecimal(0)) < 0) {
            throw new RuntimeException("存款金额必须大于零!");
        }
        // 一次最多存款50000
        if (m.compareTo(new BigDecimal("50000")) > 0) {
            throw new RuntimeException("单次存款限制五万元!");
        }
        accountDao.updateDepositMoney(id, m);
        System.out.println("存款交易成功!");
    }

    // 转账
    public void transferAccounts(int fromId, int toId, BigDecimal m) {
        AccountDao accountDao = new AccountDaoImpl();
        // 转账金额必须大于0
        if (m.compareTo(new BigDecimal(0)) <= 0) {
            throw new RuntimeException("转账金额必须大于零!");
        }
        // 不能给自己转账
        if (fromId == toId) {
            throw new RuntimeException("无法给自己转账!");
        }
        // 转账数目必须小于等于账户余额
        BigDecimal balance = accountDao.selectMoney(fromId);
        if (balance.compareTo(m) >= 0) {
            accountDao.updateWithdrawMoney(fromId, m);
            accountDao.updateDepositMoney(toId, m);
            System.out.println("转账交易成功!");
        } else {
            throw new RuntimeException("余额不足,无法完成交易!");
        }
    }

    // 修改密码
    public void changePwd(int id, String password) {
        AccountDao accountDao = new AccountDaoImpl();
        accountDao.updateChangePwd(id, password);
        System.out.println("密码已成功修改!");
    }

    // 查询余额
    public BigDecimal selectBalance(int id) {
        AccountDao accountDao = new AccountDaoImpl();
        BigDecimal balance = accountDao.selectMoney(id);
        System.out.println("查询成功,账户余额为:" + balance + "元");
        return null;
    }
}

        3.5main函数部分

        用于菜单选择以及各功能的方法调用

public class ATMSystem {
    public static void main(String[] args) {
        AccountService accountService = new AccountServiceImpl();
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入卡号:");
        int id = sc.nextInt();
        System.out.println("请输入密码:");
        String password = sc.next();

        try {
            boolean flag = true;
            Account account = accountService.login(id, password);
            System.out.println("登陆成功,欢迎!" + account.getName());
            do {
                System.out.println("-----1.取款 - 2.存款 - 3.转账 - 4.余额查询 - 5.修改密码 - 0.退出-----");
                System.out.println("\t\t\t\t\t" + "请选择您所需要办理的业务:");
                int input = sc.nextInt();
                switch (input) {
                    case 1:  // 取款
                        try {
                            System.out.println("请输入取款金额:");
                            BigDecimal m = sc.nextBigDecimal();
                            accountService.withdrawMoney(account.getId(), m);
                        } catch (Exception e) {
                            System.err.println(e.getMessage());
                        }
                        break;
                    case 2:  // 存款
                        try {
                            System.out.println("请输入存款金额:");
                            BigDecimal m = sc.nextBigDecimal();
                            accountService.depositMoney(account.getId(), m);
                        } catch (Exception e) {
                            System.err.println(e.getMessage());
                        }
                        break;
                    case 3:  // 转账
                        try {
                            System.out.println("请输入收款方卡号:");
                            int toId = sc.nextInt();
                            System.out.println("请输入转账金额:");
                            BigDecimal amount = sc.nextBigDecimal();
                            System.out.println("请输入密码进行验证!");
                            String pwd1 = sc.next();
                            if (pwd1.equals(account.getPassword())) {
                                accountService.transferAccounts(id, toId, amount);
                            } else {
                                throw new RuntimeException("密码输入错误,验证失败!");
                            }
                        } catch (RuntimeException e) {
                            System.err.println(e.getMessage());
                        }
                        break;
                    case 4:  // 余额查询
                        try {
                            System.out.println("请输入密码进行验证!");
                            String pwd2 = sc.next();
                            if (pwd2.equals(account.getPassword())) {
                                accountService.selectBalance(id);
                            } else {
                                throw new RuntimeException("密码输入错误,验证失败!");
                            }
                        } catch (RuntimeException e) {
                            System.err.println(e.getMessage());
                        }
                        break;
                    case 5:  // 修改密码
                        try {
                            // 输入原密码进行验证
                            System.out.println("请输入原密码进行验证!");
                            String oldPwd = sc.next();
                            if (!oldPwd.equals(account.getPassword())) {
                                throw new RuntimeException("原密码输入不正确!");
                            }
                            System.out.println("请输入新密码:");
                            String newPwd = sc.next();
                            System.out.println("请再次输入新密码:");
                            String reNewPwd = sc.next();
                            //比较两次输入新密码的一致性
                            if (newPwd.equals(reNewPwd)) {
                                accountService.changePwd(id, newPwd);
                            } else {
                                throw new RuntimeException("两次密码输入不一致!");
                            }
                        } catch (RuntimeException e) {
                            System.err.println(e.getMessage());
                        }
                        break;
                    case 0:  // 退出系统
                        flag = false;
                        break;
                    default:// 其他错误输入处理
                        System.out.println("请按正确格式重新输入!");
                        break;
                }
            } while (flag);
            System.out.println("已退出,欢迎下次使用!");
        } catch (Exception e) {
            System.err.println(e.getMessage());
        }
    }
}

结语

        通过这篇博客,我希望能够梳理自己的学习路径,同时记录自己的学习历程。该ATM系统功能有限,仍需优化,仅供参考!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值