ylb-接口14购买理财产品

总览:
ylb-接口14购买理财产品_第1张图片
在api模块service包,Invest类下添加(投资理财产品, int 是投资的结果 , 1 投资成功):

package com.bjpowernode.api.service;

import com.bjpowernode.api.pojo.BidInfoProduct;

import java.math.BigDecimal;
import java.util.List;

public interface InvestService {

    /** 查询某个产品的投资记录 */
    List<BidInfoProduct> queryBidListByProductId(Integer productId,
                                                 Integer pageNo,
                                                 Integer pageSize);

    /*投资理财产品, int 是投资的结果 , 1 投资成功*/
    int investProduct(Integer uid, Integer productId, BigDecimal money);
}

实现这个接口方法,在dataservice模块service包下,补充InvestServiceImpl,(投资理财产品, int 是投资的结果 , 1 投资成功):
1、参数检查(用户ID是否存在,产品ID是否存在,金钱是否存在且购买金额大于100和100整数倍)
2、查询账号金额(accountMapper.selectByUidForUpdate(uid)),比较资金(ge),是否满足购买要求
3、检查产品是否可以购买(产品不能为空且还有卖;比较ge:产品剩余可投资总金额大于要投的钱,要投的钱在最小和最大一个人可以投资金额之间)
4、可以购买了,扣除账号资金(更新资金accountMapper.updateAvailableMoneyByInvest(uid, money))
5、扣除产品剩余可投资金额(productInfoMapper.updateLeftProductMoney(productId, money))
6、创建投资记录(bidInfoMapper.insertSelective(bidInfo))
7、判断产品是否卖完(判断产品剩余可卖金额是否为0),更新产品是满标状态(productInfoMapper.updateSelled(productId))

package com.bjpowernode.dataservice.service;

import com.bjpowernode.api.model.BidInfo;
import com.bjpowernode.api.model.FinanceAccount;
import com.bjpowernode.api.model.ProductInfo;
import com.bjpowernode.api.pojo.BidInfoProduct;
import com.bjpowernode.api.service.InvestService;
import com.bjpowernode.common.constants.YLBConstant;
import com.bjpowernode.common.util.CommonUtil;
import com.bjpowernode.dataservice.mapper.BidInfoMapper;
import com.bjpowernode.dataservice.mapper.FinanceAccountMapper;
import com.bjpowernode.dataservice.mapper.ProductInfoMapper;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@DubboService(interfaceClass = InvestService.class, version = "1.0")
public class InvestServiceImpl implements InvestService {

    @Resource
    private BidInfoMapper bidInfoMapper;

    @Resource
    private FinanceAccountMapper accountMapper;

    @Resource
    private ProductInfoMapper productInfoMapper;

    /**
     * 查询某个产品的投资记录
     */
    @Override
    public List<BidInfoProduct> queryBidListByProductId(Integer productId,
                                                        Integer pageNo,
                                                        Integer pageSize) {
        List<BidInfoProduct> bidList = new ArrayList<>();
        if (productId != null && productId > 0) {
            pageNo = CommonUtil.defaultPageNo(pageNo);
            pageSize = CommonUtil.defaultPageSize(pageSize);
            int offset = (pageNo - 1) * pageSize;
            bidList = bidInfoMapper.selectByProductId(productId, offset, pageSize);
        }
        return bidList;
    }

    /*投资理财产品, int 是投资的结果 , 1 投资成功*/
    @Transactional(rollbackFor = Exception.class)
    @Override
    public int investProduct(Integer uid, Integer productId, BigDecimal money) {
        int result = 0;//默认,参数不正确
        int rows = 0;
        //1参数检查
        if ((uid != null && uid > 0) && (productId != null && productId > 0)
                && (money != null && money.intValue() % 100 == 0 && money.intValue() >= 100)) {
            //2.查询账号金额
            FinanceAccount account = accountMapper.selectByUidForUpdate(uid);
            if (account != null) {
                if (CommonUtil.ge(account.getAvailableMoney(), money)) {
                    //资金满足购买要求
                    //3.检查产品是否可以购买
                    ProductInfo productInfo = productInfoMapper.selectByPrimaryKey(productId);
                    if (productInfo != null
                            && productInfo.getProductStatus() == YLBConstant.PRODUCT_STATUS_SELLING) {
                        if (CommonUtil.ge(productInfo.getLeftProductMoney(), money) &&
                                CommonUtil.ge(money, productInfo.getBidMinLimit()) &&
                                CommonUtil.ge(productInfo.getBidMaxLimit(), money)) {
                            //可以购买了 4. 扣除账号资金
                            rows = accountMapper.updateAvailableMoneyByInvest(uid, money);
                            if (rows < 1) {
                                throw new RuntimeException("投资更新账号资金失败");
                            }
                            //5.扣除产品剩余可投资金额
                            rows = productInfoMapper.updateLeftProductMoney(productId, money);
                            if (rows < 1) {
                                throw new RuntimeException("投资更新产品剩余金额失败");
                            }

                            //6.创建投资记录
                            BidInfo bidInfo = new BidInfo();
                            bidInfo.setBidMoney(money);
                            bidInfo.setBidStatus(YLBConstant.INVEST_STATUS_SUCC);
                            bidInfo.setBidTime(new Date());
                            bidInfo.setProdId(productId);
                            bidInfo.setUid(uid);
                            bidInfoMapper.insertSelective(bidInfo);

                            //7.判断产品是否卖完,更新产品是满标状态
                            ProductInfo dbProductInfo = productInfoMapper.selectByPrimaryKey(productId);
                            if( dbProductInfo.getLeftProductMoney().compareTo(new BigDecimal("0")) == 0 ){
                                rows  = productInfoMapper.updateSelled(productId);
                                if( rows < 1 ){
                                    throw new RuntimeException("投资更新产品满标失败");
                                }
                            }
                            //8.最后这是投资成功
                            result = 1;
                        }
                    } else {
                        result = 4;//理财产品不存在
                    }
                } else {
                    result = 3;//资金不足
                }
            } else {
                result = 2;//资金账号不存在
            }
        }
        return result;
    }
}

其中:
1、给uid的记录上锁(需要在dataservice模块mapper包下的FinanceAccountMapper接口添加方法,并在resources/mappers/FinanceAccountMapper.xml编写SQL语句):

    /*给uid的记录上锁*/
    FinanceAccount selectByUidForUpdate(@Param("uid") Integer uid);
  
  <select id="selectByUidForUpdate" resultMap="BaseResultMap">
    select <include refid="Base_Column_List" />
    from u_finance_account
    where uid = #{uid}
    for update
  select>

2、在common模块util包下,CommonUtil类添加一个方法比较金额(比较BigDecimal:ge),是否可以购买:

package com.bjpowernode.common.util;

import java.math.BigDecimal;
import java.util.regex.Pattern;

public class CommonUtil {

    /*处理pageNo*/
    public static int defaultPageNo(Integer pageNo) {
        int pNo = pageNo;
        if (pageNo == null || pageNo < 1) {
            pNo = 1;
        }
        return pNo;
    }

    /*处理pageSize*/
    public static int defaultPageSize(Integer pageSize) {
        int pSize = pageSize;
        if (pageSize == null || pageSize < 1) {
            pSize = 1;
        }
        return pSize;
    }

    /*手机号脱敏*/
    public static String tuoMinPhone(String phone) {
        String result = "***********";
        if (phone != null && phone.trim().length() == 11) {
            result = phone.substring(0,3) + "******" + phone.substring(9,11);
        }
        return result;
    }


    /*手机号格式 true:格式正确;false不正确*/
    public static boolean checkPhone(String phone){
        boolean flag = false;
        if( phone != null && phone.length() == 11 ){
            //^1[1-9]\\d{9}$
            flag = Pattern.matches("^1[1-9]\\d{9}$",phone);
        }
        return flag;


    }

    /*比较BigDecimal  n1 >=n2 :true ,false*/
    public static boolean ge(BigDecimal n1, BigDecimal n2){
        if( n1 == null || n2 == null){
            throw new RuntimeException("参数BigDecimal是null");
        }
        return  n1.compareTo(n2) >= 0;
    }
}

3、更新资金(需要在dataservice模块mapper包下的FinanceAccountMapper接口添加方法,并在resources/mappers/FinanceAccountMapper.xml编写SQL语句):

    /*更新资金*/
    int updateAvailableMoneyByInvest(@Param("uid") Integer uid, @Param("money") BigDecimal money);
  
  <update id="updateAvailableMoneyByInvest">
    update   u_finance_account set available_money = available_money - #{money}
    where uid = #{uid} and ( available_money - #{money} >=0 )
  update>

4、扣除产品剩余可投资金额(需要在dataservice模块mapper包下的ProductInfoMapper接口添加方法,并在resources/mappers/ProductInfoMapper.xml编写SQL语句):

    /*扣除产品剩余可投资金额*/
    int updateLeftProductMoney(@Param("id") Integer productId, @Param("money") BigDecimal money);
  
  <update id="updateLeftProductMoney">
    update b_product_info set left_product_money = left_product_money - #{money}
    where id = #{id} and ( left_product_money - #{money} >=0 )
  update>

5、更新产品为满标(需要在dataservice模块mapper包下的ProductInfoMapper接口添加方法,并在resources/mappers/ProductInfoMapper.xml编写SQL语句):

    /*更新产品为满标*/
    int updateSelled(@Param("id") Integer productId);
  
  <update id="updateSelled">
    update  b_product_info set product_status = 1 ,  product_full_time = now()
    where id = #{id}
  update>

在web模块controller包,InvestController类下添加(购买理财产品, 更新投资排行榜):
1、检查基本参数(用户ID是否存在,产品ID是否存在,金钱是否存在且购买金额大于100和100整数倍)
2、根据investResult结果判断
3、更新投资排行榜(modifyInvestRank(uid,money))

package com.bjpowernode.front.controller;

import com.bjpowernode.api.model.User;
import com.bjpowernode.common.constants.RedisKey;
import com.bjpowernode.common.util.CommonUtil;
import com.bjpowernode.front.view.RespResult;
import com.bjpowernode.front.view.invest.RankView;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * 有关投资功能
 */

@Api(tags = "投资理财产品")
@RestController
public class InvestController extends BaseController {

    /*投资排行榜*/
    @ApiOperation(value = "投资排行榜", notes = "显式投资金额最高的3位用户信息")
    @GetMapping("/v1/invest/rank")
    public RespResult showInvestRank() {
        //从redis查询数据
        Set<ZSetOperations.TypedTuple<String>> sets = stringRedisTemplate
                .boundZSetOps(RedisKey.KEY_INVEST_RANK).reverseRangeWithScores(0, 2);

        List<RankView> rankList = new ArrayList<>();
        //遍历set集合
        sets.forEach(tuple -> {
            //tuple.getValue();//手机号
            //tuple.getScore();//投资金额
            rankList.add(new RankView(CommonUtil.tuoMinPhone(tuple.getValue()), tuple.getScore()));
        });

        RespResult result = RespResult.ok();
        result.setList(rankList);
        return result;
    }



    /*购买理财产品, 更新投资排行榜*/
    @ApiOperation(value = "投资理财产品")
    @PostMapping("/v1/invest/product")
    public RespResult investProduct(
            @RequestHeader("uid") Integer uid,
            @RequestParam("productId") Integer productId,
            @RequestParam("money") BigDecimal money){
        RespResult result = RespResult.fail();
        //1.检查基本参数
        if( (uid != null && uid > 0) && (productId != null && productId > 0)
           &&( money != null && money.intValue() % 100 == 0 && money.intValue() >= 100)){
            int investResult = investService.investProduct(uid,productId,money);
            switch (investResult){
                case 0:
                    result.setMsg("投资数据不正确");
                    break;
                case 1:
                    result = RespResult.ok();
                    modifyInvestRank(uid,money);
                    break;
                case 2:
                    result.setMsg("资金账号不存在");
                    break;
                case 3:
                    result.setMsg("资金不足");
                    break;
                case 4:
                    result.setMsg("理财产品不存在");
                    break;
            }
        }
        return result;
    }

    /*更新投资排行榜*/
    private void modifyInvestRank(Integer uid,BigDecimal money){
        User user  = userService.queryById(uid);
        if(user != null){
            //更新redis中的投资排行榜
            String key = RedisKey.KEY_INVEST_RANK;
            stringRedisTemplate.boundZSetOps(key).incrementScore(
                              user.getPhone(),money.doubleValue());
        }
    }
}

其中:
1、在web模块controller包,InvestController内添加一个方法,更新redis中的投资排行榜(更新投资排行榜modifyInvestRank):
2、在api模块service包,UserService添加查询用户方法(userService.queryById(uid))

package com.bjpowernode.api.service;

import com.bjpowernode.api.model.User;
import com.bjpowernode.api.pojo.UserAccountInfo;

public interface UserService {

    /**
     * 根据手机号查询数据
     */
    User queryByPhone(String phone);

    /*用户注册*/
    int userRegister(String phone, String password);

    /*登录*/
    User userLogin(String phone, String pword);

    /*更新实名认证信息*/
    boolean modifyRealname(String phone, String name, String idCard);

    /*获取用户和资金信息*/
    UserAccountInfo queryUserAllInfo(Integer uid);

    /*查询用户*/
    User queryById(Integer uid);
}

3、在dataservice模块service包,UserService实现这个接口方法

package com.bjpowernode.dataservice.service;

import com.bjpowernode.api.model.FinanceAccount;
import com.bjpowernode.api.model.User;
import com.bjpowernode.api.pojo.UserAccountInfo;
import com.bjpowernode.api.service.UserService;
import com.bjpowernode.common.util.CommonUtil;
import com.bjpowernode.dataservice.mapper.FinanceAccountMapper;
import com.bjpowernode.dataservice.mapper.UserMapper;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;

@DubboService(interfaceClass = UserService.class,version = "1.0")
public class UserServiceImpl implements UserService {

    @Resource
    private UserMapper userMapper;

    @Resource
    private FinanceAccountMapper financeAccountMapper;

    @Value("${ylb.config.password-salt}")
    private String passwordSalt;

    @Override
    public User queryByPhone(String phone) {
        User user = null;
        if(CommonUtil.checkPhone(phone)){
            user = userMapper.selectByPhone(phone);
        }
        return user;
    }

    /*用户注册*/
    @Transactional(rollbackFor = Exception.class)
    @Override
    public synchronized int userRegister(String phone, String password) {
        int result = 0;//默认参数不正确
        if( CommonUtil.checkPhone(phone)
                && (password != null && password.length()==32)){

            //判断手机号在库中是否存在
            User queryUser = userMapper.selectByPhone(phone);
            if(queryUser == null){
                //注册密码的md5二次加密。 给原始的密码加盐(salt)
                String newPassword = DigestUtils.md5Hex( password + passwordSalt);

                //注册u_user
                User user = new User();
                user.setPhone(phone);
                user.setLoginPassword(newPassword);
                user.setAddTime(new Date());
                userMapper.insertReturnPrimaryKey(user);

                //获取主键user.getId()
                FinanceAccount account = new FinanceAccount();
                account.setUid(user.getId());
                account.setAvailableMoney(new BigDecimal("0"));
                financeAccountMapper.insertSelective(account);

                //成功result = 1
                result = 1;
            } else {
                //手机号存在
                result = 2;
            }
        }
        return result;
    }

    /*登录*/
    @Transactional(rollbackFor = Exception.class)
    @Override
    public User userLogin(String phone, String password) {

        User user = null;
        if( CommonUtil.checkPhone(phone) && (password != null && password.length() == 32)) {
            String newPassword = DigestUtils.md5Hex( password + passwordSalt);
            user = userMapper.selectLogin(phone,newPassword);
            //更新最后登录时间
            if( user != null){
                user.setLastLoginTime(new Date());
                userMapper.updateByPrimaryKeySelective(user);
            }
        }
        return user;
    }

    /*更新实名认证信息*/
    @Override
    public boolean modifyRealname(String phone, String name, String idCard) {
        int rows = 0;
        if(!StringUtils.isAnyBlank(phone,name,idCard)){
             rows  = userMapper.updateRealname(phone,name,idCard);
        }
        return rows > 0 ;
    }

    /*获取用户和资金信息*/
    @Override
    public UserAccountInfo queryUserAllInfo(Integer uid) {
        UserAccountInfo info = null;
        if( uid != null && uid > 0 ) {
            info  = userMapper.selectUserAccountById(uid);
        }
        return info ;
    }

    /*查询用户*/
    @Override
    public User queryById(Integer uid) {
        User user = null;
        if( uid != null && uid > 0 ){
            user = userMapper.selectByPrimaryKey(uid);
        }
        return user;
    }
}

你可能感兴趣的:(ylb,java)