实验简介
通过前面一个利用文本文件重构WoniuATM的实验可以看到,我们完全可以利用一个文本文件来永久保存用户信息,但是实现过程相对复杂,而且程序的健壮性并不高。所以,本实验将带大家利用MySQL数据库来保存用户信息,并结合JDBC操作完成用户注册,登录,账户管理等功能,借助数据库管理系统的完善功能及SQL语句在查询和更新上的便利,在简化代码功能的基础上,提升程序的健壮性。
实验目的
1.掌握数据库持久化及JDBC的具体应用,解决实际问题。
2.加深对数据库操作的理解,并在后续学习中继续应用。
3.通过重构同一个接口,利用不同的代码实现相同的功能,进而对接口有深入理解。
实验流程
1.先来看看数据表结构及数据。
上述表使用场景较多,也包括后续的一些实验。而在本实验中,我们只需要首先关注“用户名”,“密码”和“余额”三列即可,其它内容可暂时忽略。另外一方面,类“UserManager”和“AccountManager”中的方法接口名及参数均保持与上一个实验中的完全一致,只是实现的代码不一样而已。
2.实现基于数据库的公共类。
该类的功能几乎与文本文件操作的公共类一致,但是由于有JDBC的存在,我们操作数据库的代码功能更加简洁:
package com.woniuxy.atm.four;
import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet;
public class DatabaseHandler { // 声明数据库驱动程序类 private static String driverClassName = "com.mysql.jdbc.Driver"; // 定义数据库连接字符串 private static String url = "jdbc:mysql://localhost:3306/learn?"+ "user=root&password=&useUnicode=true&characterEncoding=UTF8"; // 建议与数据库之间的连接 public Connection getConnection() { Connection conn = null; try { Class.forName(driverClassName).newInstance(); conn = DriverManager.getConnection(url); } catch (Exception e) { e.printStackTrace(); } return conn; } // 通过用户名获取到用户信息,并保存到一个字符串数组中 public String[] getUserInfo(String username) { String sql = "select username,balance from user where username=?"; String userInfo[] = new String[2]; try { PreparedStatement ps = this.getConnection().prepareStatement(sql); ps.setString(1, username); ResultSet rs = ps.executeQuery(); rs.next(); userInfo[0] = rs.getString("username"); userInfo[1] = String.valueOf(rs.getDouble("balance")); } catch (Exception e) { e.printStackTrace(); } return userInfo; } // 直接操作数据库更新某个用户名的余额 public void updateBalance(String username, double money) { String sql = "update user set balance=balance+? where username=?"; try { PreparedStatement ps = this.getConnection().prepareStatement(sql); ps.setDouble(1, money); ps.setString(2, username); ps.executeUpdate(); } catch (Exception e) { e.printStackTrace(); } } } |
3.检查用户名是否存在。
此处,我们将该方法修改为返回一个boolean值,所以在其它接口调用时也会做些调整:
// 定义类成员变量handler,用于整个UserManager类中其它方法的调用 DatabaseHandler handler = new DatabaseHandler();
// 检查用户名是否存在: true: 存在, false: 不存在 public boolean checkUserExist(String username) { boolean isUserExist = false; String sql = "select count(*) from user where username=?"; try { PreparedStatement ps = this.handler.getConnection().prepareStatement(sql); ps.setString(1, username); ResultSet rs = ps.executeQuery(); rs.next(); if (rs.getInt(1) > 0) { isUserExist = true; } }catch (Exception e) { e.printStackTrace(); } return isUserExist; } |
4.完成用户的注册功能。
public void register() { Scanner sc = new Scanner(System.in); System.out.println("请输入用户名:"); String username = sc.next(); if (this.checkUserExist(username)) { System.out.println("你注册的用户名已经存在,请重新输入."); this.register(); } else { System.out.println("请输入密码:"); String password = sc.next(); System.out.println("你输入你的余额:"); double balance = sc.nextDouble(); String sql = "insert into user(username, password, balance) values (?,?,?)"; try { PreparedStatement ps = this.handler.getConnection().prepareStatement(sql); ps.setString(1, username); ps.setString(2, password); ps.setDouble(3, balance); int number = ps.executeUpdate(); System.out.println(number); this.ui.mainMenu(); } catch (Exception e) { e.printStackTrace(); } } } |
5.完成用户的登录功能。
// 为了后续操作方便,为UserManager定义一个静态变量,将当前登录成功的用户名记录起来 public static String loggedUsername = "";
public void login() { Scanner sc = new Scanner(System.in); System.out.println("请输入用户名:"); String username = sc.next(); System.out.println("请输入密码:"); String password = sc.next(); if (this.doLogin(username, password)) { System.out.println("恭喜你,登录成功."); UserManager.loggedUsername = username; this.ui.subMenu(); } else { System.out.println("抱歉,登录失败."); this.login(); } }
private boolean doLogin(String username, String password) { boolean isLoginOk = false; String sql = "select count(*) from user where username=? and password=?"; try { PreparedStatement ps = this.handler.getConnection().prepareStatement(sql); ps.setString(1, username); ps.setString(2, password); ResultSet rs = ps.executeQuery(); rs.next(); if (rs.getInt(1) == 1) { isLoginOk = true; } } catch (Exception e) { e.printStackTrace(); } return isLoginOk; } |
6.完成用户的转账功能。
public void transfer() { // 向某一个已经存在的用户转一笔钱,自己的账户钱会减少,对方账户钱会增加: 插桩 Scanner sc = new Scanner(System.in); System.out.println("请输入对方账户:"); String toUsername = sc.next(); if (um.checkUserExist(toUsername)) { System.out.println("请输入转账金额:"); double money = sc.nextDouble(); this.handler.updateBalance(toUsername, money); this.handler.updateBalance(UserManager.loggedUsername, -money); System.out.println("恭喜你,转账成功."); this.ui.subMenu(); } else { System.out.println("你输入的目标账户不存在."); this.transfer(); } } |
思考练习
1.在转账过程中,我们并没有对其转账金额的有效性进行检验,请完善此功能。
2.请继续利用JDBC操作数据库完成用户的存取款,查询余额等功能。
3.请利用数据库管理用户的手机号码,并实现修改密码,修改手机号码等功能。
4.请实现利用手机号码加密码的方式实现用户登录和转账等功能。
5.请为AccountManager类添加操作流水记录功能,并保存起来。