Day4 Spring + Jdbc 练习:账户管理系统

需求

使用Spring实现一个基于命令行的账户管理系统。
功能点:

  1. 创建和删除账户;
  2. 账户余额查询、存入、取款;
  3. 用户间转账;
  4. 用户登录;
  5. 操作选项:
  • 未登录时:
  1. 登录
  2. 退出
  • 管理员账号:
  1. 退出
  2. 创建账户
  3. 删除账户
  4. 账户列表
  • 普通用户账号:
  1. 退出
  2. 查询余额
  3. 取款
  4. 存款
  5. 转账

技术点:

  1. 使用Spring注解;
  2. 使用Druid数据源;
  3. 使用JdbcTemplate操作SQL语句;

实现

1. 创建实体类、Dao和Service

######### 数据模型:Account类

@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class Account {

    private int id;
    private String name;
    private String password;
    private double money;
    private String role;

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

######### 数据库操作:AccountDao接口和AccountDaoImpl实现类

public interface AccountDao {

    boolean create(Account account);
    void update(Account account);
    void delete(int id);
    Account findById(int id);
    Account findByName(String name);
    Account accountLogin(String name, String password);
    List<Account> findAll();
}

@Repository
public class AccountDaoImpl implements AccountDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    /**
     * 创建新用户
     */
    @Override
    public boolean create(Account account) {
        String name = account.getName();
        // 判断用户是否已存在
        if (findByName(name) != null) {
            System.out.println("账户 " + name + " 已存在。");
            return false;
        }
        jdbcTemplate.update("insert into account(name, password, money) values(?, ?, ?)",
                name, account.getPassword(), account.getMoney());
        return true;
    }

    /**
     * 更新账号余额
     */
    @Override
    public void update(Account account) {
        jdbcTemplate.update("update account set money = ? where id = ?",
                account.getMoney(), account.getId());
    }

    /**
     * 删除用户
     */
    @Override
    public void delete(int id) {
        jdbcTemplate.update("delete from account where id = ?", id);
    }

    /**
     * account表字段和Account类映射关系类
     */
    static class AccountRowMapping implements RowMapper<Account> {
        @Override
        public Account mapRow(ResultSet rs, int rowNum) throws SQLException {
            int id = rs.getInt(1);
            String name = rs.getString(2);
            double money = rs.getDouble(3);
            String role = rs.getString(4);
            return new Account(id, name, "", money, role);
        }
    }

    /**
     * 根据id查找用户
     */
    @Override
    public Account findById(int id) {
        try {
            return jdbcTemplate.queryForObject("select id, name, money, role from account where id = ?",
                    new AccountDaoImpl.AccountRowMapping(), id);
        } catch (EmptyResultDataAccessException e) {
            return null;
        }
    }

    /**
     * 根据用户名查找用户
     */
    @Override
    public Account findByName(String name) {
        try {
            return jdbcTemplate.queryForObject("select id, name, money, role from account where name = ?",
                    new AccountDaoImpl.AccountRowMapping(), name);
        } catch (EmptyResultDataAccessException e) {
            return null;
        }
    }

    /**
     * 用户登录
     */
    @Override
    public Account accountLogin(String name, String password) {
        try {
            return jdbcTemplate.queryForObject("select id, name, money, role from account where name = ? and password = ?",
                    new AccountDaoImpl.AccountRowMapping(), name, password);
        } catch (EmptyResultDataAccessException e) {
            return null;
        }
    }

    /**
     * 返回用户列表
     */
    @Override
    public List<Account> findAll() {
        try {
            return jdbcTemplate.query("select id, name, money, role from account",
                    new AccountDaoImpl.AccountRowMapping());
        } catch (EmptyResultDataAccessException e) {
            return null;
        }
    }
}

######### 业务处理层:AccountService接口和AccountServiceImpl实现类

public interface AccountService {
    boolean createAccount(Account account);
    boolean deleteAccount(int id);
    void updateAccount(Account account);
    boolean saveMoney(Account account, double money);
    boolean takeMoney(Account account, double money);
    Account findById(int id);
    Account login(String name, String password);
    List<Account> list();
    boolean transfer(int fromId, int toId, double money);
}

@Service
public class AccountServiceImpl implements AccountService {

    @Autowired
    private AccountDao accountDao;

    /**
     * 创建账户
     * @return flag 是否创建成功
     */
    @Override
    public boolean createAccount(Account account) {
        if (account == null) {
            System.out.println("非法账户。");
            return false;
        }
        return accountDao.create(account);
    }

    /**
     * 更新账户信息(余额)
     */
    @Override
    public void updateAccount(Account account) {
        accountDao.update(account);
    }

    /**
     * 存钱
     */
    @Override
    public boolean saveMoney(Account account, double money) {
        if (account == null || money < 0) {
            return false;
        }
        account.setMoney(account.getMoney() + money);
        updateAccount(account);
        return true;
    }

    /**
     * 取钱
     */
    @Override
    public boolean takeMoney(Account account, double money) {
        if (account == null || money < 0) {
            return false;
        }
        if (account.getMoney() < money) {
            System.out.println("余额不足");
            return false;
        }
        account.setMoney(account.getMoney() - money);
        updateAccount(account);
        return true;
    }

    /**
     * 根据id查找用户
     */
    @Override
    public Account findById(int id) {
        return accountDao.findById(id);
    }

    /**
     * 登录
     * @return account 成功则返回账户
     */
    @Override
    public Account login(String name, String password) {
        // 登录,并返回账户信息
        return accountDao.accountLogin(name, password);
    }

    /**
     * 删除账户
     */
    @Override
    public boolean deleteAccount(int id) {
        if (id == 1) {
            System.out.println("超级管理员账户不能删除。");
        }
        // 判断待账户是否存在
        else if (accountDao.findById(id) == null) {
            System.out.println("ID为 " + id + " 的账户不存在。");
        } else {
            System.out.println("ID为 " + id + " 的账户删除成功。");
            accountDao.delete(id);
        }
        return true;
    }

    /**
     * 查看用户列表,只有管理员才有此操作
     */
    @Override
    public List<Account> list() {
        List<Account> accountList = accountDao.findAll();
        if (accountList == null || accountList.size() == 0) {
            System.out.println("没有用户。");
        } else {
            accountList.forEach(System.out::println);
        }
        return accountList;
    }

    /**
     * 转账操作
     * @param fromId 转出账户id
     * @param toId 转入账户id
     * @param money 转账金额
     */
    @Override
    public boolean transfer(int fromId, int toId, double money) {
        Account fromAccount = findById(fromId);
        Account toAccount = findById(toId);
        if (fromAccount == null || money < 0 ||
                money > fromAccount.getMoney() || toAccount == null) {
            return false;
        }
        fromAccount.setMoney(fromAccount.getMoney() - money);
        updateAccount(fromAccount);
        toAccount.setMoney(toAccount.getMoney() + money);
        updateAccount(toAccount);
        return true;
    }
}

######### 用于终端命令行操作的ClientAccountService类

  • 对AccountService做了一些封装,主要添加了从终端获取用户输入的功能;
  • 该类包含一个AccountService的成员属性;
/**
 * 对AccountService做一些封装,主要添加了从终端获取用户输入的功能
 * 该类包含一个AccountService的成员属性
 */
@Service
@Data
public class ClientAccountService {

    @Autowired
    private AccountService service;

    /**
     * 登录
     * @return account 成功则返回账户
     */
    public Account login() {
        Scanner scanner = new Scanner(System.in);
        System.out.print("请输入用户名:");
        String name = scanner.next();
        System.out.print("请输入密码:");
        String password = scanner.next();

        // 登录,并返回账户信息
        Account account = service.login(name, password);
        if (account == null) {
            System.out.println("用户名或密码有误,请重新输入。");
        } else {
            System.out.println("登录成功,欢迎 " + account.getName() + " !");
        }
        return account;
    }

    /**
     * 根据用户输入,创建账户
     * @return flag 是否创建成功
     */
    public boolean createAccount() {
        boolean flag = true;
        try {
            Scanner scanner = new Scanner(System.in);
            System.out.print("请输入用户名:");
            String name = scanner.next();
            System.out.print("请输入密码:");
            String password = scanner.next();
            System.out.print("请输入初始金额:");
            double money = scanner.nextDouble();
            Account account = new Account(0, name, password, money, "");
            flag = service.createAccount(account);
            // 创建失败,返回false
            if (!flag)
                return false;
            System.out.println("账户创建成功,账户信息:" + account);
        } catch (Exception e) {
            flag = false;
        }
        return flag;
    }

    /**
     * 删除账户
     */
    public boolean deleteAccount() {
        boolean flag = true;
        try {
            Scanner scanner = new Scanner(System.in);
            System.out.print("请输入待删除的账户ID:");
            int id = scanner.nextInt();
            service.deleteAccount(id);
        } catch (Exception e) {
            flag = false;
        }
        return flag;
    }

    /**
     * 存钱
     */
    public boolean saveMoney(Account account) {
        boolean flag = true;
        Scanner scanner = new Scanner(System.in);
        System.out.print("请输入存款金额:");
        try {
            double inputMoney = scanner.nextDouble();
            flag = service.saveMoney(account, inputMoney);
            if (flag)
                System.out.println("成功存入" + inputMoney + ",当前余额为:" + account.getMoney());
        } catch (Exception e) {
            flag = false;
        }
        return flag;
    }

    /**
     * 取钱
     */
    public boolean takeMoney(Account account) {
        boolean flag = true;
        Scanner scanner = new Scanner(System.in);
        System.out.print("请输入取款金额:");
        try {
            double inputMoney = scanner.nextDouble();
            flag = service.takeMoney(account, inputMoney);
            if (flag)
                System.out.println("成功取款" + inputMoney + ",当前余额为:" + account.getMoney());
        } catch (Exception e) {
            flag = false;
        }
        return flag;
    }

    /**
     * 转账操作
     */
    public boolean transfer(Account account) {
        boolean flag = true;
        Scanner scanner = new Scanner(System.in);
        System.out.print("请输入转出金额:");
        try {
            double inputMoney = scanner.nextDouble();
            // 判断余额是否充足
            if (inputMoney > account.getMoney()) {
                System.out.println("余额不足,当前余额为:" + account.getMoney());
                return false;
            }
            System.out.print("请输入转账账户ID:");
            int toId = scanner.nextInt();
            // 判断转出账户是否存在
            if (service.findById(toId) == null) {
                System.out.println("ID为:" + toId + "的账户不存在。");
                return false;
            }

            // 转账,更新数据库信息
            flag = service.transfer(account.getId(), toId, inputMoney);
            if (flag) {
                // 更新余额
                account.setMoney(account.getMoney() - inputMoney);
                System.out.println("转账成功,当前余额为:" + account.getMoney());
            }
        } catch (Exception e) {
            flag = false;
        }
        return flag;
    }
}
2. 创建数据库表

添加一个账户表:account

create table account
(
    id       int auto_increment 		primary key,
    name     varchar(64)                not null,
    password varchar(64)                not null,
    money    double      default 0      null,
    role     varchar(32) default '普通用户' null,
    constraint account_name_uindex
        unique (name)
) comment '账户信息表';

INSERT INTO test.account (id, name, password, money, role) VALUES (1, 'admin', 'admin', 0, '管理员');
3. 创建数据源
  1. jdbc配置文件:jdbc.properties
jdbc.jdbcUrl=jdbc:mysql://localhost:3306/test?serverTimezone=Asia/Shanghai
jdbc.username=root
jdbc.password=123456
jdbc.driverClass=com.mysql.cj.jdbc.Driver
  1. 配置类
@Configuration  // 表示当前类为一个配置类
@PropertySource("com/bailiban./day4/account_system/config/jdbc.properties") // 设置配置文件路径
public class JdbcConfig {

    // 从jdbc配置文件获取数据库连接属性
    @Value("${jdbc.jdbcUrl}")
    private String jdbcUrl;
    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;
    @Value("${jdbc.driverClass}")
    private String driverClass;

    /**
     * 创建数据源bean
     */
    @Bean("dataSource")
    public DataSource getDataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUrl(jdbcUrl);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        dataSource.setDriverClassName(driverClass);
        return dataSource;
    }

    /**
     * 创建JdbcTemplate,用于执行SQL语句;
     * @param dataSource 数据源参数,自动获取 @Bean("dataSource")
     */
    @Bean
    public JdbcTemplate getJdbcTemplate(DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }
}
4. 编写客户端类

成员变量:

	@Autowired
    private ClientAccountService service;

    private boolean isLogin = false;
    private Account account = null;
菜单选项
/**
     * 创建操作选项,分三种情况;
     * - 未登录时:
     *  1. 登录
     *  2. 退出
     * - 管理员账号:
     *  1. 退出
     *  2. 创建账户
     *  3. 删除账户
     *  4. 账户列表
     * - 普通用户账号:
     *  1. 退出
     *  2. 查询余额
     *  3. 取款
     *  4. 存款
     *  5. 转账
     */
    private String getClientInfo() {
        return (!isLogin ? "******欢迎使用BLB账户管理系统,请选择:******\r\n" :
                        "-----------------------------------------\r\n请选择:\r\n") +
                (!isLogin ? "\t1. 登录 \r\n\t2. 退出 \r\n" : "\t1. 退出\r\n") +
                (!isLogin ? "" : account.getRole().equals("管理员") ?
                        ("\t2. 创建账户\r\n" + "\t3. 删除账户\r\n" + "\t4. 账户列表\r\n") :
                        ("\t2. 查询余额\r\n" + "\t3. 取款\r\n" + "\t4. 存款\r\n" +
                                "\t5. 转账\r\n")) +
                "-----------------------------------------\r\n>> ";
    }
主方法
	/**
     * 账户管理系统运行入口函数
     */
    public void run() {
        // while循环,用户可以重复操作
        while (true) {
            boolean flag = true;
            Scanner scanner = new Scanner(System.in);
            // 打印操作选项
            System.out.print(getClientInfo());
            try {
                // 从终端输入获取操作选项
                int step = scanner.nextInt();
                // 判断是否为退出操作
                if (!isQuit(step)) {
                    // 登录系统
                    if (!isLogin && step == 1) {
                        login();
                    } else {
                        // 根据用户权限,执行管理员操作,或者普通用户操作
                        flag = account.getRole().equals("管理员") ? doAdmin(step) : doNormal(step);
                    }
                } else {
                    // 退出系统
                    System.out.println("~~Bye~~");
                    return;
                }
            } catch (Exception e) {
                flag = false;
            }
            if (!flag) {
                System.out.println("输入有误。");
            }
        }
    }
管理员操作
	/**
     * 管理员操作
     * @param step 操作选项
     * @return flag 操作是否成功
     */
    private boolean doAdmin(int step) {
        boolean flag = true;
        switch (step) {
            case 2: // 2. 创建账户
                flag = service.createAccount();
                break;
            case 3: // 3. 删除账户
                flag = service.deleteAccount();
                break;
            case 4: // 4. 账户列表
                service.getService().list();
                break;
            default: // 其他输入为非法选项
                flag = false;
        }
        return flag;
    }
普通用户操作
	/**
     * 普通用户操作
     * @param step 操作选项
     * @return flag 操作是否成功
     */
    private boolean doNormal(int step) {
        boolean flag = true;
        Scanner scanner = new Scanner(System.in);
        double inputMoney = 0;  // 定义用户输入的金额
        try {
            switch (step) {
                case 2: // 2. 查询余额
                    System.out.println("账户余额为:" + account.getMoney());
                    break;
                case 3: // 3. 取款
                    flag = service.takeMoney(account);
                    break;
                case 4: // 4. 存款
                    flag = service.saveMoney(account);
                    break;
                case 5: // 5. 转账
                    flag = service.transfer(account);
                    break;
                default:  // 其他输入为非法选项
                    flag = false;
            }
        } catch (Exception e) {
            flag = false;
        }
        
        return flag;
    }
完整类
@Component
@Data
public class Client {

    @Autowired
    private ClientAccountService service;

    private boolean isLogin = false;
    private Account account = null;

    /**
     * 创建操作选项,分三种情况;
     * - 未登录时:
     *  1. 登录
     *  2. 退出
     * - 管理员账号:
     *  1. 退出
     *  2. 创建账户
     *  3. 删除账户
     *  4. 账户列表
     * - 普通用户账号:
     *  1. 退出
     *  2. 查询余额
     *  3. 取款
     *  4. 存款
     *  5. 转账
     */
    private String getClientInfo() {
        return (!isLogin ? "******欢迎使用BLB账户管理系统,请选择:******\r\n" :
                        "-----------------------------------------\r\n请选择:\r\n") +
                (!isLogin ? "\t1. 登录 \r\n\t2. 退出 \r\n" : "\t1. 退出\r\n") +
                (!isLogin ? "" : account.getRole().equals("管理员") ?
                        ("\t2. 创建账户\r\n" + "\t3. 删除账户\r\n" + "\t4. 账户列表\r\n") :
                        ("\t2. 查询余额\r\n" + "\t3. 取款\r\n" + "\t4. 存款\r\n" +
                                "\t5. 转账\r\n")) +
                "-----------------------------------------\r\n>> ";
    }

    /**
     * 账户管理系统运行入口函数
     */
    public void run() {
        // while循环,用户可以重复操作
        while (true) {
            boolean flag = true;
            Scanner scanner = new Scanner(System.in);
            // 打印操作选项
            System.out.print(getClientInfo());
            try {
                // 从终端输入获取操作选项
                int step = scanner.nextInt();
                // 判断是否为退出操作
                if (!isQuit(step)) {
                    // 登录系统
                    if (!isLogin && step == 1) {
                        login();
                    } else {
                        // 根据用户权限,执行管理员操作,或者普通用户操作
                        flag = account.getRole().equals("管理员") ? doAdmin(step) : doNormal(step);
                    }
                } else {
                    // 退出系统
                    System.out.println("~~Bye~~");
                    return;
                }
            } catch (Exception e) {
                flag = false;
            }
            if (!flag) {
                System.out.println("输入有误。");
            }
        }
    }

    /**
     * 普通用户操作
     * @param step 操作选项
     * @return flag 操作是否成功
     */
    private boolean doNormal(int step) {
        boolean flag = true;
        Scanner scanner = new Scanner(System.in);
        double inputMoney = 0;  // 定义用户输入的金额
        try {
            switch (step) {
                case 2: // 2. 查询余额
                    System.out.println("账户余额为:" + account.getMoney());
                    break;
                case 3: // 3. 取款
                    flag = service.takeMoney(account);
                    break;
                case 4: // 4. 存款
                    flag = service.saveMoney(account);
                    break;
                case 5: // 5. 转账
                    flag = service.transfer(account);
                    break;
                default:  // 其他输入为非法选项
                    flag = false;
            }
        } catch (Exception e) {
            flag = false;
        }
        
        return flag;
    }

    /**
     * 管理员操作
     * @param step 操作选项
     * @return flag 操作是否成功
     */
    private boolean doAdmin(int step) {
        boolean flag = true;
        switch (step) {
            case 2: // 2. 创建账户
                flag = service.createAccount();
                break;
            case 3: // 3. 删除账户
                flag = service.deleteAccount();
                break;
            case 4: // 4. 账户列表
                service.getService().list();
                break;
            default: // 其他输入为非法选项
                flag = false;
        }
        return flag;
    }

    /**
     * 账户登录
     * @return 是否登录成功
     */
    private boolean login() {
        account = service.login();
        isLogin = account != null;
        return isLogin;
    }

    /**
     * 判断当前是否为退出操作
     * @param step 操作选项
     * @return true 退出
     */
    private boolean isQuit(int step) {
        // 当已登录时,step-1为退出选项;
        // 当未登录时,step-2为退出选项;
        return isLogin && step == 1 || !isLogin && step == 2;
    }

    public static void main(String[] args) {
        Client client = new AnnotationConfigApplicationContext(
                "com.bailiban.day4.account_system").getBean(Client.class);
        client.run();
    }
}

测试

管理员操作
******欢迎使用BLB账户管理系统,请选择:******
	1. 登录 
	2. 退出 
-----------------------------------------
>> 1
请输入用户名:admin
请输入密码:admin

登录成功,欢迎 admin !
-----------------------------------------
请选择:
	1. 退出
	2. 创建账户
	3. 删除账户
	4. 账户列表
-----------------------------------------
>> 4
Account{id=1, name='admin', money=0.0}
-----------------------------------------
请选择:
	1. 退出
	2. 创建账户
	3. 删除账户
	4. 账户列表
-----------------------------------------
>> 2
请输入用户名:Jim
请输入密码:Jim
请输入初始金额:1000
账户创建成功,账户信息:Account{id=0, name='Jim', money=1000.0}
-----------------------------------------
请选择:
	1. 退出
	2. 创建账户
	3. 删除账户
	4. 账户列表
-----------------------------------------
>> 2
请输入用户名:Tom
请输入密码:Tom
请输入初始金额:50000
账户创建成功,账户信息:Account{id=0, name='Tom', money=50000.0}
-----------------------------------------
请选择:
	1. 退出
	2. 创建账户
	3. 删除账户
	4. 账户列表
-----------------------------------------
>> 2
请输入用户名:Lily
请输入密码:LiLy
请输入初始金额:6000
账户创建成功,账户信息:Account{id=0, name='Lily', money=6000.0}
-----------------------------------------
请选择:
	1. 退出
	2. 创建账户
	3. 删除账户
	4. 账户列表
-----------------------------------------
>> 4
Account{id=1, name='admin', money=0.0}
Account{id=10, name='Jim', money=1000.0}
Account{id=11, name='Tom', money=50000.0}
Account{id=12, name='Lily', money=6000.0}
-----------------------------------------
请选择:
	1. 退出
	2. 创建账户
	3. 删除账户
	4. 账户列表
-----------------------------------------
>> 3
请输入待删除的账户ID:11
ID为 11 的账户删除成功。
-----------------------------------------
请选择:
	1. 退出
	2. 创建账户
	3. 删除账户
	4. 账户列表
-----------------------------------------
>> 4
Account{id=1, name='admin', money=0.0}
Account{id=10, name='Jim', money=1000.0}
Account{id=12, name='Lily', money=6000.0}
-----------------------------------------
请选择:
	1. 退出
	2. 创建账户
	3. 删除账户
	4. 账户列表
-----------------------------------------
>> 1
~~Bye~~

普通用户操作
******欢迎使用BLB账户管理系统,请选择:******
	1. 登录 
	2. 退出 
-----------------------------------------
>> 1
请输入用户名:Jim
请输入密码:Jim

登录成功,欢迎 Jim !
-----------------------------------------
请选择:
	1. 退出
	2. 查询余额
	3. 取款
	4. 存款
	5. 转账
-----------------------------------------
>> 2
账户余额为:1000.0
-----------------------------------------
请选择:
	1. 退出
	2. 查询余额
	3. 取款
	4. 存款
	5. 转账
-----------------------------------------
>> 3
请输入取款金额:500
成功取款500.0,当前余额为:500.0
-----------------------------------------
请选择:
	1. 退出
	2. 查询余额
	3. 取款
	4. 存款
	5. 转账
-----------------------------------------
>> 4
请输入存款金额:1000
成功存入1000.0,当前余额为:1500.0
-----------------------------------------
请选择:
	1. 退出
	2. 查询余额
	3. 取款
	4. 存款
	5. 转账
-----------------------------------------
>> 5
请输入转出金额:100
请输入转账账户ID:12
转账成功,当前余额为:1400.0
-----------------------------------------
请选择:
	1. 退出
	2. 查询余额
	3. 取款
	4. 存款
	5. 转账
-----------------------------------------
>> 2
账户余额为:1400.0
-----------------------------------------
请选择:
	1. 退出
	2. 查询余额
	3. 取款
	4. 存款
	5. 转账
-----------------------------------------
>> 1
~~Bye~~

posted @ 2019-12-22 21:35  cheng_18  阅读(343)  评论(0编辑  收藏  举报