一.准备工作
1.user.user_info表增加account_money(账户金额)字段(真是的业务场景一般是建一张user_account的表,这里为了简单,博客都是以技术讲解为主,业务简单化做支撑).
2.user.user_info表实体映射也增加accountMoney字段.
package com.ccm.server.user.dao.mysql.domain;
import lombok.Data;
import java.util.Date;
/**
* @Description user_info表实体类映射
* @Author ccm
* @CreateTime 2020/08/05 15:19
*/
@Data
public class UserInfo {
private Long userId;
private String username;
private String password;
private BigDecimal accountMoney;
private Date updateTime;
private Date createTime;
}
二.server-user服务中开发用户扣款接口
1.控制层
(1).AccountController
package com.ccm.server.user.controller;
import com.ccm.common.exception.result.ResultSet;
import com.ccm.server.user.service.AccountService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@Validated
@Api(tags = "账户")
@RestController
@RequestMapping(value = "account")
public class AccountController {
@Autowired
private AccountService accountService;
@ApiOperation(value = "扣款")
@PutMapping(value = "deduction")
public ResultSet deduction(@ApiParam(hidden = true) @RequestHeader(name = "ccm-userId") Long userId,
@ApiParam(value = "金额") @RequestParam BigDecimal amountOfMoney) {
accountService.deduction(userId,amountOfMoney);
return ResultSet.success();
}
}
2.业务层
(1).AccountService
package com.ccm.server.user.service;
/**
* @Description 账户业务层
* @Author ccm
* @CreateTime 2020/08/19 11:51
*/
public interface AccountService {
/**
* @Description 扣款
* @Author zhouzhiwu
* @CreateTime 2020/8/19 13:32
* @Params [userId, amountOfMoney]
* @Return void
*/
void deduction(Long userId, BigDecimal amountOfMoney);
}
(2).AccountServiceImpl
package com.ccm.server.user.service.impl;
import com.ccm.common.exception.CustomerException;
import com.ccm.server.user.dao.mysql.domain.UserInfo;
import com.ccm.server.user.dao.mysql.mapper.UserInfoMapper;
import com.ccm.server.user.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* @Description 账户业务层实现
* @Author ccm
* @CreateTime 2020/08/19 11:52
*/
@Service
public class AccountServiceImpl implements AccountService {
@Autowired
private UserInfoMapper userInfoMapper;
@Override
@Transactional(rollbackFor = Exception.class)
public void deduction(Long userId, BigDecimal amountOfMoney) {
//查看账户余额是否满足扣款
UserInfo userInfo = userInfoMapper.selectByUserIdForUpdate(userId);
if(userInfo == null) {
throw new CustomerException("用户不存在");
}
if(amountOfMoney.doubleValue() > userInfo.getAccountMoney().doubleValue()) {
throw new CustomerException("账户余额不足");
}
//扣款
userInfoMapper.deductionByUserId(userId,amountOfMoney);
}
}
3.持久层
(1).UserInfoMapper
package com.ccm.server.user.dao.mysql.mapper;
import com.ccm.server.user.dao.mysql.domain.UserInfo;
import org.apache.ibatis.annotations.Param;
/**
* @Description user_info表mapper
* @Author ccm
* @CreateTime 2020/08/05 15:20
*/
public interface UserInfoMapper {
UserInfo selectByUserIdForUpdate(@Param("userId")Long userId);
int deductionByUserId(@Param("userId") Long userId, @Param("amountOfMoney")BigDecimal amountOfMoney);
}
(2).UserInfoMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.ccm.server.user.dao.mysql.mapper.UserInfoMapper" >
<update id="deductionByUserId">
update user_info set account_money = (account_money - #{amountOfMoney}) where user_id = #{userId}
</update>
<select id="selectByUserIdForUpdate" resultType="com.ccm.server.user.dao.mysql.domain.UserInfo">
select * from user_info where user_id = #{userId}
</select>
</mapper>
三.接口测试
1.启动gateway网关和server-user微服务.
2.打开gateway网关的swagger界面.
3.接口测试.
查看数据库,扣款成功
您的点赞、收藏、转发和关注是我持续创作的动力!
源码地址:https://gitee.com/chouchimoo/ccm-mall.git(本章节代码分支:zj-32)