34. 尚融宝充值
发布日期:2021-05-06 14:07:02 浏览次数:33 分类:精选文章

本文共 7213 字,大约阅读时间需要 24 分钟。

整体流程

标的产生后,平台展示标的,投资人就可以在平台投资标的,获取收益;投资人投资标的必须满足以下条件:

在这里插入图片描述

充值过程与绑定过程一致,也是在平台发送充值请求,跳转到资金托管平台,在资金托管平台完成充值,然后同步或异步返回或通知平台

相关数据库表

在这里插入图片描述

参考文档

参考《汇付宝商户账户技术文档》3.9用户充值

充值

需求

step1:用户在个人中心点击 “充值”

step2:尚融宝展示账户充值页面

在这里插入图片描述

step3:用户填写充值金额,点击“充值”按钮

step4:跳转到汇付宝页面(资金托管接口调用)

在这里插入图片描述

step5:汇付宝验证用户交易密码

在这里插入图片描述

后端

controller

UserAccountController.java

package com.indi.srb.core.controller.api;@Api(tags = "用户账户")@RestController@RequestMapping("/api/core/userAccount")@Slf4jpublic class UserAccountController {       @Resource    private UserAccountService userAccountService;    @ApiOperation("账户充值")    @PostMapping("/auth/commitCharge/{chargeAmt}")    public R recharge(            @PathVariable BigDecimal chargeAmt,            HttpServletRequest request) {           String token = request.getHeader("token");        Long userId = JwtUtils.getUserId(token);        String formStr = userAccountService.commitCharge(chargeAmt, userId);        return R.ok().setData("formStr", formStr);    }}

service

UserAccountService.java

String commitCharge(BigDecimal chargeAmt, Long userId);

UserAccountServiceImpl.java

@Resource    private UserInfoMapper userInfoMapper;    	@Override    public String commitCharge(BigDecimal chargeAmt, Long userId) {           // 判断用户绑没绑定        UserInfo userInfo = userInfoMapper.selectById(userId);        String bindCode = userInfo.getBindCode();        Assert.notEmpty(bindCode, ResponseEnum.USER_NO_BIND_ERROR);        // 组装表单        Map
map = new HashMap<>(); map.put("agentId", HfbConst.AGENT_ID); map.put("agentBillNo", LendNoUtils.getNo()); map.put("bindCode", bindCode); map.put("chargeAmt", chargeAmt); map.put("feeAmt", new BigDecimal(0)); map.put("notifyUrl", HfbConst.RECHARGE_NOTIFY_URL); map.put("returnUrl", HfbConst.RECHARGE_RETURN_URL); map.put("timestamp", RequestHelper.getTimestamp()); map.put("sign", RequestHelper.getSign(map)); String formStr = FormHelper.buildForm(HfbConst.RECHARGE_URL, map); return formStr; }

前端

template

pages/user/recharge.vue

script

pages/user/recharge.vue

ajax远程调用:远程服务器必修开放跨域访问权限

form表单远程调用:不受跨域控制、缺点需要组装表单

充值回调

需求

step7:异步回调(1)账户金额更改(2)添加交易流水

step8:用户点击“返回平台”,返回尚融宝

在这里插入图片描述

接口幂等性原则

什么是接口幂等性

接口幂等性就是用户对于同一操作发起的一次请求或者多次请求的结果是一致的,不会因为多次调用而产生了副作用。

举个最简单的例子,那就是支付,用户购买商品后支付,支付扣款成功,但是返回结果的时候网络异常,此时钱已经扣了,用户再次点击按钮,此时会进行第二次扣款,返回结果成功,用户查询余额返发现多扣钱了,流水记录也变成了两条...这就没有保证接口的幂等性

存在的问题

当回调重试时,金额和流水会重复增加

在这里插入图片描述

解决方案

1、设置唯一索引

设置了唯一索引后,即使回调重复执行,遇到唯一索引,就会抛出异常,从而使事务回滚,这是保底方案,我们要尽量避免程序进入到这一步。

在这里插入图片描述

2、判断流水是否存在

判断流水如果存在,则从业务方法中直接退出

TransFlowService.java

boolean isSaveTransFlow(String agentBillNo);

后端UserAccount

controller

UserAccountController.java

@ApiOperation("充值回调")    @PostMapping("/notify")    public String notify(HttpServletRequest request){           // 获取返回来的回调参数        Map
paramMap = RequestHelper.switchMap(request.getParameterMap()); log.info("用户充值异步回调:"+ JSON.toJSONString(paramMap)); // 校验签名 if(RequestHelper.isSignEquals(paramMap)){ // 判断返回结果 // 充值成功 if ("0001".equals(paramMap.get("resultCode"))){ return userAccountService.notify(paramMap); }else{ log.info("充值失败:"+JSON.toJSONString(paramMap)); // 如果想让汇付宝发起失败重试的话,则返回非success字段,如果不需要重试,则返回success // 此处返回success,是因为汇付宝那边已经充值失败了,所以根本就不需要重试,再重试也是失败,所以直接给用户返回错误信息即可。 return "success"; } }else{ // 此处可能是因为服务器签名错误、或者是请求超时, // 验证签名的时候,汇付宝那边会发过一个时间戳过来,这个时间戳一般都是实时的,这边接收之后发现是好几分钟之前的, // 这就可能是请求被别人拦截了,然后模拟了一个请求,给发过来了,时间花费较长,可能就会导致请求超时 // 所以需要发起汇付宝重试 log.info("充值签名错误:"+JSON.toJSONString(paramMap)); return "fail"; } }

service

UserAccountService.java

String notify(Map
paramMap);

UserAccountServiceImpl.java

@Resource    private TransFlowService transFlowService;    @Transactional(rollbackFor = Exception.class)	@Override    public String notify(Map
paramMap) { // 能进入到这,就说明充值成功了 log.info("充值成功:" + JSONObject.toJSONString(paramMap)); String agentBillNo = (String) paramMap.get("agentBillNo"); if (transFlowService.haveTransFlow(agentBillNo)) { log.warn("幂等性返回"); return "success"; } String bindCode = (String) paramMap.get("bindCode"); String chargeAmt = (String) paramMap.get("chargeAmt"); // 根据绑定协议查到用户id,然后更新账户余额、冻结金额、 baseMapper.updateAccount(bindCode, new BigDecimal(chargeAmt), new BigDecimal(0)); // 增加交易流水 TransFlowBO transFlowBO = new TransFlowBO( agentBillNo, bindCode, new BigDecimal(chargeAmt), TransTypeEnum.RECHARGE, TransTypeEnum.RECHARGE.getTransTypeName() ); transFlowService.saveTransFlow(transFlowBO); return "success"; }

mapper

UserAccountMapper.java

void updateAccount(@Param("bindCode") String bindCode,                       @Param("amount") BigDecimal amount,                       @Param("freezeAmount") BigDecimal freezeAmount);

UserAccountMapper.xml

update user_account set amount = amount + #{amount}, freeze_amount = freeze_amount + #{freezeAmount} where user_id = (select user_id from user_bind where bind_code = #{bindCode})

后端TransFlow

bo

TransFlowBO.java

@Data@NoArgsConstructor@AllArgsConstructorpublic class TransFlowBO {       private String agentBillNo; // 商户充值订单号    private String bindCode;    // 绑定协议    private BigDecimal amount;  // 充值金额    private TransTypeEnum transTypeEnum;    // 交易类型    private String memo;    // 备注}

service

TransFlowService.java

void saveTransFlow(TransFlowBO transFlowBO);    boolean isSaveTransFlow(String agentBillNo);

TransFlowServiceImpl.java

@Resource    private UserInfoMapper userInfoMapper;    @Override    public void saveTransFlow(TransFlowBO transFlowBO) {           QueryWrapper
queryWrapper = new QueryWrapper<>(); queryWrapper.eq("bind_code", transFlowBO.getBindCode()); UserInfo userInfo = userInfoMapper.selectOne(queryWrapper); TransFlow transFlow = new TransFlow(); transFlow.setUserId(userInfo.getId()); transFlow.setUserName(userInfo.getName()); transFlow.setTransNo(transFlowBO.getAgentBillNo()); transFlow.setTransType(transFlowBO.getTransTypeEnum().getTransType()); transFlow.setTransTypeName(transFlowBO.getTransTypeEnum().getTransTypeName()); transFlow.setTransAmount(transFlowBO.getAmount()); transFlow.setMemo(transFlowBO.getMemo()); baseMapper.insert(transFlow); } @Override public boolean isSaveTransFlow(String agentBillNo) { QueryWrapper
queryWrapper = new QueryWrapper<>(); queryWrapper.eq("trans_No", agentBillNo); Integer count = baseMapper.selectCount(queryWrapper); return count > 0; }
上一篇:leetcode练习1(两数之和:哈希遍历)
下一篇:33. 尚融宝汇付宝回调流程

发表评论

最新留言

留言是一种美德,欢迎回访!
[***.207.175.100]2025年03月27日 20时07分55秒