spring boot + mybatis 模拟银行系统余额查询、转账、存取钱功能实现


实现银行系统的余额查询在我们之前写的token认证登陆功能完成的基础上实现,token认证登陆功能代码地址:https://github.com/yeyuting-1314/selectFuPan_tokenAndRedisfengzhuagn.git

银行系统余额查询、转账、入账、出账功能项目代码地址:https://github.com/yeyuting-1314/tokenLogin1.0.git

一、准备工作

新建一个数据库,数据库名字是tokenLogin,数据库内新建两张表,第一张是用户账户信息表,第二张是转账、入账、出账记录表,分别如下所示:

1. sys_user用户账户信息表:

CREATE TABLE tokenLogin.sys_user(
    `id` bigint NOT NULL comment 'ID ',
    `username` varchar(50) comment '用户名',
    `password` varchar(50) comment '密码',
    PRIMARY KEY (`id`)
);


insert into tokenLogin.sys_user values('1' , 'admmin' , '1')
insert into tokenLogin.sys_user values('2' , 'superadmmin' , '11')
insert into tokenLogin.sys_user values('3' , 'user' , '111')

alter table tokenLogin.sys_user add column account double default null;

接着对account进行赋值,赋值完成后表内容如下:

 2. 转账记录表:

CREATE TABLE tokenLogin.trasf_record(
    `id` int NOT NULL AUTO_INCREMENT, 
    `username` varchar(50) default null,
    `account_time` TIMESTAMP DEFAULT now() , /*交易时间,默认是几率生成的时间,也就是交易操作完成的时间*/
    `old_account` double default null, /*原账户的余额*/
    `new_account` double default null, /*交易后账户最新余额*/
    `target_account` varchar(50) default null ,  /*交易对方账户*/
    `account_type` varchar(50) default null , /*交易类型*/
    PRIMARY KEY (`id`)
);


alter table tokenLogin.trasf_record add column transaction_amount double default null after old_account ; /*在原账户余额和交易后账户余额中间插入交易余额*/

创建一张空表即可,后面产生交易的时候将数据插入,实现资金追溯。

 3. 常量设置:在转账记录表中,有一个字段account_type , 这个字段无非有两个结果,要么是入账类型,要么是出账类型,所以这里我们进行常量设置。

在constants包下面新建TransactionType类,类下内容如下:

/**
 * @author yeyuting
 * @create 2021/2/18
 */
public class   TransactionType {
    public static final String SAVEMONEY = "入账" ;
    public static final String WITHDRAWMONEY = "出账" ;
}

这样一来,准备工作就做好了,现在我们依次来实现账户余额查询、转账、入账和出账记录。

二、账户余额查询

1. 首先控制层创建余额查询接口:

 @GetMapping("/selectByUserName")
    public Result selectByUserName(@RequestParam("userName") String username){
        return Results.successWithData(userService.selectByUserName(username) , BaseEnums.SUCCESS.code()) ;
    }

2. service层进行数据传递:

//UserService类:
public User selectByUserName(String username)  ; 

//UserServiceImpl类:
//查询金额
    public User selectByUserName(String username) {
        return userMapper.selectByUserName(username) ;
    }

3. mapper层,将参数进行传递并和数据库打交道:

UserMapper.java:

public User selectByUserName(String username) ;

userMapper.xml:


    <select id="selectByUserName" resultType="User">
        select * from sys_user where username = #{userName}
    select>

4. 进行登陆操作,访问LoginCheck接口,生成对应的token,将token塞到余额查询接口的头信息中,过拦截器,进而顺利执行接口代码逻辑。

 

4. postman前端模拟:

 这样一来,最简单的账户余额查询就实现了。

三、转账功能实现:

1. controller层创建转账接口:

 @PostMapping("/transferAccount")
    public Result transferAccount (@RequestParam("accountMoney") Double accountMoney ,
                                   @RequestParam("targetAccount") String targetAccount , HttpServletRequest request){
        return Results.successWithData(userService.transferAccount(accountMoney , targetAccount , request) , BaseEnums.SUCCESS.code()) ;

    }

2. service层实现:

service接口:

//转账
    public String  transferAccount(Double accountMoney , String targetAccount , HttpServletRequest request) ;

serviceImpl实现:

 //转账
    public String transferAccount(Double accountMoney , String targetAccount , HttpServletRequest request){
        Jedis jedis = jedisUtil.getSource() ;
        String token = request.getHeader("token") ;
        String userName = jedis.get(token) ;
        User user = userMapper.selectByName(userName) ;
        double nowAccountMoney = user.getAccount() ;
        if(accountMoney > nowAccountMoney){
            return "余额不足" ;
        }
        User user1 = userMapper.selectByName(targetAccount) ;
        if (user1.equals(null)){
            return "对方账户不存在" ;
        }
        //转出账户余额更新
        boolean result = userMapper.updateAccountOut(accountMoney , userName) ;
        //转入账户余额更新
        boolean result1 = userMapper.updateAccountIn(accountMoney , user1.getUserName()) ;
        if ((result == false)||(result1 == false) ){
            return "转账操作失败" ;
        }
        //转账记录生成------------
        //String accountType = TransactionType.WITHDRAWMONEY ;
        //出账记录生成
        boolean insertReult = userMapper.accountOutInsert(userName ,user.getAccount() ,  accountMoney , targetAccount , TransactionType.WITHDRAWMONEY ) ;
        //入账记录生成
        //String accountType1 = TransactionType.SAVEMONEY ;
        boolean insertReult1 = userMapper.accountInInsert(user1.getUserName() , user1.getAccount() , accountMoney , user.getUserName() , TransactionType.SAVEMONEY ) ;

        if((insertReult == false) || (insertReult1 == false)){
            return "转账记录生成失败" ;
        }

        return "转账成功!" ;
    }

service实现中每一行代码都有详细的讲解,总的来说,就是要实现出账方账户余额相应减少,入账方账户余额相应增加,同时生成对应的转账记录。

3. mapper层实现:

//转出更新
    public boolean updateAccountOut (Double accountMoney , String userName) ;
    //转入更新
    public boolean updateAccountIn (Double accountMoney , String userName) ;

    //转出记录插入
    public boolean accountOutInsert(String userName ,Double account , Double accountMoney , String targetAccount , String accountType) ;

    //转入记录插入
    public boolean accountInInsert(String userName ,Double account , Double accountMoney , String targetAccount , String accountType) ;
<update id="updateAccountOut">
        update sys_user set account = (account - #{accountMoney}) where username = #{userName}
    update>

    <update id="updateAccountIn">
        update sys_user set account = (account + #{accountMoney}) where username = #{userName}
    update>

    <insert id="accountOutInsert">
        insert into trasf_record
        ( username , old_account ,transaction_amount , new_account , target_account , account_type )
        values
        ( #{userName} ,#{account} , #{accountMoney} , (#{account} - #{accountMoney}) , #{targetAccount} , #{accountType})
    insert>

    <insert id="accountInInsert">
        insert into trasf_record
        (username , old_account ,transaction_amount , new_account , target_account , account_type )
        values
        (#{userName} ,#{account} , #{accountMoney} , (#{account} + #{accountMoney}) , #{targetAccount} , #{accountType})
    insert>

4. postman前端模拟:

 将上面生成的token塞到转账接口头信息中,访问数据库:

 数据库信息刷新:

 这样一来,转账功能也就实现了,在充分理解了转账功能后,入账出账功能就迎刃而解了。接下来继续实现账户入账和出账功能。

四、入账功能

 1. controller层:

//存钱
    @PostMapping("/saveMoney")
    public Result saveMoney (@RequestParam("accountMoney") Double accountMoney , HttpServletRequest request){
        return  Results.successWithData(userService.saveMoney(accountMoney , request) , BaseEnums.SUCCESS.code()) ;
    }

2. service层:

service接口:

 //存钱
    public String saveMoney(Double accountMoney , HttpServletRequest request) ;

serviceImpl实现:

//存钱
    public String saveMoney(Double accountMoney , HttpServletRequest request){
        Jedis jedis = jedisUtil.getSource() ;
        String token = request.getHeader("token") ;
        String userName = jedis.get(token) ;
        User user = userMapper.selectByName(userName) ;
        //存入余额更新
        boolean result = userMapper.updateAccountIn(accountMoney , userName) ;
        if(result = false){
            return "存入失败" ;
        }
        //存入记录生成
        boolean insertResult = userMapper.accountInInsert(userName ,user.getAccount() , accountMoney , userName , TransactionType.SAVEMONEY) ;
        if((insertResult == false)){
            return "入账记录生成失败" ;
        }
        return "成功存入" + accountMoney + "元!"  ;
    }

3. mapper层和转账公用一套代码。

4. postman前端实现:

和转账一样,要记得将token塞进头信息中。

 执行后结果如下:

 数据库刷新结果如下:

 

 五、出账功能

1. controller层:

//取钱
    @PostMapping("withdrawMoney")
    public Result withdrawMoney (@RequestParam("accountMoney") Double accountMoney , HttpServletRequest request){
        return  Results.successWithData(userService.withdrawMoney(accountMoney , request) , BaseEnums.SUCCESS.code()) ;
    }

2. service层:

service接口:

//取钱
    public String withdrawMoney(Double accountMoney , HttpServletRequest request) ;

serviceImpl具体实现:

//取钱
    public String withdrawMoney(Double accountMoney , HttpServletRequest request){
        Jedis jedis = jedisUtil.getSource() ;
        String token = request.getHeader("token") ;
        String userName = jedis.get(token) ;
        User user = userMapper.selectByName(userName) ;
        double nowAccountMoney = user.getAccount() ;
        if(accountMoney > nowAccountMoney){
            return "余额不足" ;
        }
        boolean result = userMapper.updateAccountOut(accountMoney , userName) ;
        if(result = false){
            return "取钱失败" ;
        }
        //出账记录生成
        boolean insertResult = userMapper.accountOutInsert(userName ,user.getAccount() , accountMoney , userName , TransactionType.WITHDRAWMONEY) ;
        if((insertResult == false)){
            return "出账记录生成失败" ;
        }
        return "成功取出" + accountMoney + "元!"  ;
    }

3. mapper层和转账公用一套代码。

4. postman前端实现:

和转账一样,要记得将token塞进头信息中。

 

 这样一来,出账功能也就实现了。

待解决问题:

1. redis暂未实现redis缓存对象,因此每次访问redis只是为了拿到token和对应的value,并未真正的利用到redis,因此,后期要将对象完整的存入到redis中,便于后期数据的获取。

2. 这里的转账记录表还可以做成索引表,每个用户单列一张表出来,更加的浅显易懂,但是任务量过大,需商榷后再决定是否将整表分开。

至此,结束。

相关