位置: IT常识 - 正文
目录
一、展示投资列表
(一)需求
(二)后端
(三)前端
二、充值功能
(一)需求
1、需求描述
2、流程
(二)充值
1、后端
2、前端
(三)回调接口
1、定义回调接口
2、增加交易流水
(四)接口调用幂等性
1、接口幂等性原则
2、解决方案
推荐整理分享尚融宝25-投资列表展示以及实现充值功能(尚融资本),希望有所帮助,仅作参考,欢迎阅读内容。
文章相关热门搜索词:尚融宝盈(宁波)投资中心(有限合伙),尚融资本是不是骗局,尚融商城是真的吗,尚融资本是不是骗局,尚融公司,尚融资本怎么样,尚融资本是不是骗局,尚融宝项目,内容如对您有帮助,希望把文章链接给更多的朋友!
标的形成后,客户可在客户端看到标的列表,投资者可以通过点击标的了解详情并投资心仪标的
(二)后端LendController中创建list方法
@Api(tags = "标的")@RestController@RequestMapping("/api/core/lend")@Slf4jpublic class LendController { @Resource private LendService lendService; @ApiOperation("获取标的列表") @GetMapping("/list") public R list() { List<Lend> lendList = lendService.selectList(); return R.ok().data("lendList", lendList); }}(三)前端pages/lend/index.vue
脚本
此处使用了服务器端渲染
<template> <!--列表--> <div class="page-filter wrap"> <div class="breadcrumbs"> <a href="index.html">首页</a>><span class="cur">散标投资列表</span> </div> <div class="invest-filter" data-target="sideMenu"> <div class="filter-inner clearfix"> <div class="filter-item"> <div class="hd"> <h3>筛选投资项目</h3> <label> <input id="filterMulti" name="multiple_choice" type="checkbox" /> 多选</label > </div> <div class="bd"> <dl> <dt>项目类型</dt> <dd> <ul> <li class="n1"> <a href="javascript:url('post_type','');" id="post_type_" class="active" >不限</a > </li> <li class="n2"> <a href="javascript:url('post_type','car');" id="post_type_car" >车易贷</a > </li> <li class="n3"> <a href="javascript:url('post_type','house');" id="post_type_house" >房易贷</a > </li> <li class="n4"> <a href="javascript:url('post_type','bridge');" id="post_type_bridge" >赎楼贷</a > </li> <li class="n5"> <a href="javascript:url('post_type','worth');" id="post_type_worth" >债权贷</a > </li> </ul> </dd> </dl> <dl> <dt>年利率</dt> <dd> <ul> <li class="n1"> <a href="javascript:url('borrow_interestrate','');" id="borrow_interestrate_" class="active" >不限</a > </li> <li class="n2"> <a id="borrow_interestrate_1" href="javascript:url('borrow_interestrate','1');" >12%以下</a > </li> <li class="n3"> <a id="borrow_interestrate_2" href="javascript:url('borrow_interestrate','2');" >12%-14%</a > </li> <li class="n4"> <a id="borrow_interestrate_3" href="javascript:url('borrow_interestrate','3');" >14%-16%</a > </li> <li class="n5"> <a id="borrow_interestrate_4" href="javascript:url('borrow_interestrate','4');" >16%及以上</a > </li> </ul> </dd> </dl> <dl> <dt>期限</dt> <dd> <ul> <li class="n1"> <a href="javascript:url('spread_month','');" id="spread_month_" class="active" >不限</a > </li> <li class="n2"> <a id="spread_month_1" href="javascript:url('spread_month','1');" >1月以下</a > </li> <li class="n3"> <a id="spread_month_2" href="javascript:url('spread_month','2');" >1-3月</a > </li> <li class="n4"> <a id="spread_month_3" href="javascript:url('spread_month','3');" >3-6月</a > </li> <li class="n5"> <a id="spread_month_4" href="javascript:url('spread_month','4');" >6-12月</a > </li> <li class="n6"> <a id="spread_month_5" href="javascript:url('spread_month','5');" >12月及以上</a > </li> </ul> </dd> </dl> <dl class="repayment"> <dt>还款方式</dt> <dd> <ul> <li class="n1"> <a href="javascript:url('repay_style','');" id="repay_style_" class="active" >不限</a > </li> <li class="n2"> <a id="repay_style_end" href="javascript:url('repay_style','end');" >到期还本付息</a > </li> <li class="n2"> <a id="repay_style_endmonth" href="javascript:url('repay_style','endmonth');" >按月付息,到期还本</a > </li> <li class="n2"> <a id="repay_style_month" href="javascript:url('repay_style','month');" >等额本息</a > </li> </ul> </dd> </dl> </div> </div> <div class="common-problem"> <h3>常见问题</h3> <ul> <li><a href="#">什么是债权贷?</a></li> <li><a href="#">关于"债权贷"产品的说明</a></li> <li><a href="#">金融理财收费标准</a></li> <li><a href="#">债权贷和房易贷、车易贷有什么区别?</a></li> </ul> </div> </div> </div> <div class="invest-list mrt30 clearfix"> <div class="hd"> <h3>投资列表</h3> <div class="count"> <ul> <li class="line"> 散标投资交易金额 <span class="f20 bold" >73.54亿元</span > </li> <li> 累计赚取收益 <span class="f20 bold">2.52亿元</span> </li> </ul> </div> </div> <div class="bd"> <div class="invest-table clearfix"> <div class="title clearfix"> <ul> <li class="col-330">借款标题</li> <li class="col-180"> <a href="javascript:url('order','account_up');" class="" >借款金额</a > </li> <li class="col-110"> <a href="javascript:url('order','apr_up');" class="">年利率</a> </li> <li class="col-150"> <a href="javascript:url('order','period_up');" class="" >借款期限</a > </li> <li class="col-150">还款方式</li> <li class="col-120"> <a href="javascript:url('order','scale_up');" class="" >借款进度</a > </li> <li class="col-120-t">操作</li> </ul> </div> <!------------投资列表--------------> <div class="item" v-for="lend in lendList" :key="lend.id"> <ul> <li class="col-330 col-t"> <NuxtLink :to="'/lend/' + lend.id" target="_blank"> <i class="icon icon-zhai"></i> </NuxtLink> <NuxtLink class="f18" :to="'/lend/' + lend.id" :title="lend.title" target="_blank" > {{ lend.title }} </NuxtLink> </li> <li class="col-180"> <span class="f20 c-333"> {{ lend.amount }}元 </span> </li> <li class="col-110 relative"> <span class="f20 c-orange"> {{ lend.lendYearRate * 100 }}% </span> </li> <li class="col-150"> <span class="f20 c-333">{{ lend.period }}个月</span> </li> <li class="col-150">{{ lend.params.returnMethod }}</li> <li class="col-120"> <div class="circle"> <div class="left progress-bar"> <!-- <div :class=" 'progress-bgPic progress-bfb' + Math.floor((lend.investAmount / lend.amount) * 10) " > --> <div :class=" 'progress-bgPic progress-bfb' + Math.floor((lend.investAmount / lend.amount) * 10) " > <div class="show-bar"> {{ (lend.investAmount / lend.amount) * 100 }}% </div> </div> </div> </div> </li> <li class="col-120-2"> <NuxtLink class="ui-btn btn-gray" :to="'/lend/' + lend.id" target="_blank" > {{ lend.params.status }} </NuxtLink> </li> </ul> </div> <!------------投资列表--------------> </div> </div> </div> </div></template><script>import '~/assets/css/index.css'import '~/assets/css/detail.css'export default { async asyncData({ $axios }) { console.log('服务器端获取远程数据。。。。。。。。。。。。。。。。') let response = await $axios.$get('/api/core/lend/list') return { lendList: response.data.lendList, } },}</script>二、充值功能(一)需求1、需求描述标的产生后,平台展示标的,投资人就可以在平台投资标的,获取收益;投资人投资标的必须满足以下条件:
充值过程与绑定过程一致,也是在平台发送充值请求,跳转到资金托管平台(汇付宝),在资金托管平台(汇付宝)完成充值,然后同步或异步返回或通知平台
操作表:user_account(用户账户表) ====> trans_flow(交易流水表)
用户输入充值后,点击确认,此时我们需要有一个方法返回一个表单且需自动提交(携带汇付宝需要的参数且不能让客户看到表单,因此需要自动提交),然后汇付宝会调用我们的回调方法,在回调方法中,我们需要更新用户账户表并在交易流水表中产生一个记录
汇付宝携带参数说明
2、流程
step1:用户在个人中心点击 “充值”
step2:尚融宝展示账户充值页面
step3:用户填写充值金额,点击“充值”按钮
step4:跳转到汇付宝页面(资金托管接口调用)
step5:汇付宝验证用户交易密码
step6:汇付宝修改账号资金余额(更新user_account记录中的amount的值,这一步汇付宝做)
step7:异步回调
(1)账户金额更改
(2)添加交易流水
step8:用户点击“返回平台”,返回尚融宝
(二)充值1、后端controller
UserAccountController
@Api(tags = "会员账户")@RestController@RequestMapping("/api/core/userAccount")@Slf4jpublic class UserAccountController { @Resource private UserAccountService userAccountService; @ApiOperation("充值") @PostMapping("/auth/commitCharge/{chargeAmt}") public R commitCharge( @ApiParam(value = "充值金额", required = true) @PathVariable BigDecimal chargeAmt, HttpServletRequest request) { String token = request.getHeader("token"); Long userId = JwtUtils.getUserId(token); String formStr = userAccountService.commitCharge(chargeAmt, userId); return R.ok().data("formStr", formStr); }}service
接口:UserAccountService
String commitCharge(BigDecimal chargeAmt, Long userId);实现:UserAccountServiceImpl
@Resourceprivate UserInfoMapper userInfoMapper;@Overridepublic String commitCharge(BigDecimal chargeAmt, Long userId) { UserInfo userInfo = userInfoMapper.selectById(userId); String bindCode = userInfo.getBindCode(); //判断账户绑定状态 Assert.notEmpty(bindCode, ResponseEnum.USER_NO_BIND_ERROR); Map<String, Object> paramMap = new HashMap<>(); paramMap.put("agentId", HfbConst.AGENT_ID); paramMap.put("agentBillNo", LendNoUtils.getNo()); paramMap.put("bindCode", bindCode); paramMap.put("chargeAmt", chargeAmt); paramMap.put("feeAmt", new BigDecimal("0")); paramMap.put("notifyUrl", HfbConst.RECHARGE_NOTIFY_URL);//检查常量是否正确 paramMap.put("returnUrl", HfbConst.RECHARGE_RETURN_URL); paramMap.put("timestamp", RequestHelper.getTimestamp()); String sign = RequestHelper.getSign(paramMap); paramMap.put("sign", sign); //构建充值自动提交表单 String formStr = FormHelper.buildForm(HfbConst.RECHARGE_URL, paramMap); return formStr;}2、前端pages/user/recharge.vue
methods: { commitCharge() { this.$alert( '<div style="size: 18px;color: red;">您即将前往汇付宝充值</div>', '前往汇付宝资金托管平台', { dangerouslyUseHTMLString: true, confirmButtonText: '立即前往', callback: (action) => { if (action === 'confirm') { this.$axios .$post( '/api/core/userAccount/auth/commitCharge/' + this.chargeAmt ) .then((response) => { document.write(response.data.formStr) }) } }, } ) },},(三)回调接口1、定义回调接口controller
UserAccountController中创建回调方法
@ApiOperation(value = "用户充值异步回调")@PostMapping("/notify")public String notify(HttpServletRequest request) { Map<String, Object> 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)); return "success"; } } else { log.info("用户充值异步回调签名错误:" + JSON.toJSONString(paramMap)); return "fail"; }}service
接口:UserAccountService
String notify(Map<String, Object> paramMap);实现:UserAccountServiceImpl
@Transactional(rollbackFor = Exception.class)@Overridepublic String notify(Map<String, Object> paramMap) { log.info("充值成功:" + JSONObject.toJSONString(paramMap)); String bindCode = (String)paramMap.get("bindCode"); //充值人绑定协议号 String chargeAmt = (String)paramMap.get("chargeAmt"); //充值金额 //优化 baseMapper.updateAccount(bindCode, new BigDecimal(chargeAmt), new BigDecimal(0)); //增加交易流水 //TODO return "success";}mapper
接口:UserAccountMapper
void updateAccount( @Param("bindCode")String bindCode, @Param("amount")BigDecimal amount, @Param("freezeAmount")BigDecimal freezeAmount);XML:UserAccountMapper.xml
<update id="updateAccount"> update user_account set amount = amount + #{amount}, freeze_amount = freeze_amount + #{freezeAmount} where user_id = (select id from user_info where bind_code = #{bindCode})</update> 2、增加交易流水增加枚举TransTypeEnum
@AllArgsConstructor@Getterpublic enum TransTypeEnum { RECHARGE(1,"充值"), INVEST_LOCK(2,"投标锁定"), INVEST_UNLOCK(3,"放款解锁"), CANCEL_LEND(4,"撤标"), BORROW_BACK(5,"放款到账"), RETURN_DOWN(6,"还款扣减"), INVEST_BACK(7,"出借回款"), WITHDRAW(8,"提现"), ; private Integer transType ; private String transTypeName; public static String getTransTypeName(int transType) { for (TransTypeEnum obj : TransTypeEnum.values()) { if (transType == obj.getTransType().intValue()) { return obj.getTransTypeName(); } } return ""; }}创建BO对象
@Data@AllArgsConstructor@NoArgsConstructorpublic class TransFlowBO { private String agentBillNo; private String bindCode; private BigDecimal amount; private TransTypeEnum transTypeEnum; private String memo;}service
接口:TransFlowService
void saveTransFlow(TransFlowBO transFlowBO);实现:TransFlowServiceImpl
@Resourceprivate UserInfoMapper userInfoMapper;@Overridepublic void saveTransFlow(TransFlowBO transFlowBO) { //获取用户基本信息 user_info QueryWrapper<UserInfo> userInfoQueryWrapper = new QueryWrapper<>(); userInfoQueryWrapper.eq("bind_code", transFlowBO.getBindCode()); UserInfo userInfo = userInfoMapper.selectOne(userInfoQueryWrapper); //存储交易流水数据 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);}完整的回调函数notify
@Resourceprivate TransFlowService transFlowService;@Transactional(rollbackFor = Exception.class)@Overridepublic String notify(Map<String, Object> paramMap) { log.info("充值成功:" + JSONObject.toJSONString(paramMap)); String bindCode = (String)paramMap.get("bindCode"); //充值人绑定协议号 String chargeAmt = (String)paramMap.get("chargeAmt"); //充值金额 //优化 baseMapper.updateAccount(bindCode, new BigDecimal(chargeAmt), new BigDecimal(0)); //增加交易流水 String agentBillNo = (String)paramMap.get("agentBillNo"); //商户充值订单号 TransFlowBO transFlowBO = new TransFlowBO( agentBillNo, bindCode, new BigDecimal(chargeAmt), TransTypeEnum.RECHARGE, "充值"); transFlowService.saveTransFlow(transFlowBO); return "success";}(四)接口调用幂等性1、接口幂等性原则接口幂等性就是用户对于同一操作发起的一次请求或者多次请求的结果是一致的,不会因为多次调用而产生了副作用。
举个最简单的例子,那就是支付,用户购买商品后支付,支付扣款成功,但是返回结果的时候网络异常,此时钱已经扣了,用户再次点击按钮,此时会进行第二次扣款,返回结果成功,用户查询余额返发现多扣钱了,流水记录也变成了两条...这就没有保证接口的幂等性
回调重试
汇付宝向尚融宝发起回调,如果没有收到正确的响应 "success",则尚融宝会发起重试
汇付宝中的相关代码如下:
@Slf4jpublic class NotifyThread implements Runnable { private int count = 1; private String notifyUrl; private Map<String, Object> paramMap; public NotifyThread(){} public NotifyThread(String notifyUrl, Map<String, Object> paramMap) { this.notifyUrl = notifyUrl; this.paramMap = paramMap; } @Override public void run() { task(); } private void task() { String result = SignUtil.sendRequest(paramMap,notifyUrl); log.info(notifyUrl + ":" + result + " count:" + count); if(!"success".equals(result)) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } //ScheduledTask.queue.offer(new NotifyVo(notifyUrl, paramMap)); count++; if(count <= 5) { task(); log.info("失败重试:" + JSON.toJSONString(this)); } } }}存在的问题:当回调重试时,金额和流水会重复增加
2、解决方案
① 设置唯一索引
设置了唯一索引后,即使回调重复执行,遇到唯一索引,就会抛出异常,从而使事务回滚。
但很显然,我们不能光靠报错回滚数据库事务来防止接口幂等性
② 判断流水是否存在
判断流水如果存在,则从业务方法中直接退出
接口:TransFlowService
boolean isSaveTransFlow(String agentBillNo);实现:TransFlowServiceImpl
@Overridepublic boolean isSaveTransFlow(String agentBillNo) { QueryWrapper<TransFlow> queryWrapper = new QueryWrapper(); queryWrapper.eq("trans_no", agentBillNo); int count = baseMapper.selectCount(queryWrapper); if(count > 0) { return true; } return false;}调用 :UserAccountServiceImpl
@Transactional(rollbackFor = Exception.class)@Overridepublic void notify(Map<String, Object> paramMap) { log.info("充值成功:" + JSONObject.toJSONString(paramMap)); //判断交易流水是否存在 String agentBillNo = (String)paramMap.get("agentBillNo"); //商户充值订单号 boolean isSave = transFlowService.isSaveTransFlow(agentBillNo); if(isSave){ log.warn("幂等性返回"); return; } ...... //增加交易流水 //agentBillNo = (String)paramMap.get("agentBillNo"); //商户充值订单号}上一篇:CSS实现背景图片模糊——毛玻璃效果 | 浅谈CSS属性 filter、backdrop-filter(css实现背景图片变透明)
下一篇:10分钟学会python对接【OpenAI API篇】(10分钟学会万用表)
友情链接: 武汉网站建设