尚融宝25-投资列表展示以及实现充值功能

news/2024/11/30 2:50:54/

目录

一、展示投资列表

(一)需求

(二)后端

(三)前端

二、充值功能

(一)需求

1、需求描述

2、流程

(二)充值

1、后端

2、前端

(三)回调接口

1、定义回调接口

2、增加交易流水

(四)接口调用幂等性

1、接口幂等性原则

2、解决方案


一、展示投资列表

(一)需求

标的形成后,客户可在客户端看到标的列表,投资者可以通过点击标的了解详情并投资心仪标的

(二)后端

LendController中创建list方法

@Api(tags = "标的")
@RestController
@RequestMapping("/api/core/lend")
@Slf4j
public class LendController {@Resourceprivate 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>&gt;<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"><ahref="javascript:url('post_type','');"id="post_type_"class="active">不限</a></li><li class="n2"><ahref="javascript:url('post_type','car');"id="post_type_car">车易贷</a></li><li class="n3"><ahref="javascript:url('post_type','house');"id="post_type_house">房易贷</a></li><li class="n4"><ahref="javascript:url('post_type','bridge');"id="post_type_bridge">赎楼贷</a></li><li class="n5"><ahref="javascript:url('post_type','worth');"id="post_type_worth">债权贷</a></li></ul></dd></dl><dl><dt>年利率</dt><dd><ul><li class="n1"><ahref="javascript:url('borrow_interestrate','');"id="borrow_interestrate_"class="active">不限</a></li><li class="n2"><aid="borrow_interestrate_1"href="javascript:url('borrow_interestrate','1');">12%以下</a></li><li class="n3"><aid="borrow_interestrate_2"href="javascript:url('borrow_interestrate','2');">12%-14%</a></li><li class="n4"><aid="borrow_interestrate_3"href="javascript:url('borrow_interestrate','3');">14%-16%</a></li><li class="n5"><aid="borrow_interestrate_4"href="javascript:url('borrow_interestrate','4');">16%及以上</a></li></ul></dd></dl><dl><dt>期限</dt><dd><ul><li class="n1"><ahref="javascript:url('spread_month','');"id="spread_month_"class="active">不限</a></li><li class="n2"><aid="spread_month_1"href="javascript:url('spread_month','1');">1月以下</a></li><li class="n3"><aid="spread_month_2"href="javascript:url('spread_month','2');">1-3月</a></li><li class="n4"><aid="spread_month_3"href="javascript:url('spread_month','3');">3-6月</a></li><li class="n5"><aid="spread_month_4"href="javascript:url('spread_month','4');">6-12月</a></li><li class="n6"><aid="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"><ahref="javascript:url('repay_style','');"id="repay_style_"class="active">不限</a></li><li class="n2"><aid="repay_style_end"href="javascript:url('repay_style','end');">到期还本付息</a></li><li class="n2"><aid="repay_style_endmonth"href="javascript:url('repay_style','endmonth');">按月付息,到期还本</a></li><li class="n2"><aid="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">散标投资交易金额&nbsp;&nbsp;<span class="f20 bold">73.54亿元</span></li><li>累计赚取收益&nbsp;&nbsp;<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><NuxtLinkclass="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"><NuxtLinkclass="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")
@Slf4j
public class UserAccountController {@Resourceprivate 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

@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<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)
@Override
public 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));//增加交易流水//TODOreturn "success";
}

mapper

接口:UserAccountMapper

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

 XML:UserAccountMapper.xml

<update id="updateAccount">updateuser_accountsetamount = amount + #{amount},freeze_amount = freeze_amount + #{freezeAmount}whereuser_id = (select id from user_info where bind_code = #{bindCode})
</update>

 2、增加交易流水

增加枚举TransTypeEnum

@AllArgsConstructor
@Getter
public 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
@NoArgsConstructor
public class TransFlowBO {private String agentBillNo;private String bindCode;private BigDecimal amount;private TransTypeEnum transTypeEnum;private String memo;
}

 service

接口:TransFlowService

void saveTransFlow(TransFlowBO transFlowBO);

实现:TransFlowServiceImpl

@Resource
private UserInfoMapper userInfoMapper;@Override
public void saveTransFlow(TransFlowBO transFlowBO) {//获取用户基本信息 user_infoQueryWrapper<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

@Resource
private TransFlowService transFlowService;@Transactional(rollbackFor = Exception.class)
@Override
public 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",则尚融宝会发起重试

汇付宝中的相关代码如下:

@Slf4j
public 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;}@Overridepublic 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

@Override
public 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)
@Override
public 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"); //商户充值订单号}


http://www.ppmy.cn/news/56209.html

相关文章

数据结构学习记录——判断是否为同一颗二叉搜索树(题意理解、求解思路、程序搭建框架、具体函数的实现)

目录 题意理解 问题 描述 输入样例 输出样例 求解思路 建两棵二叉树 不建树 建一棵树 搜索树表示 程序框架搭建 如何建搜索树 如何判别 方法 查找函数 判断函数 其他函数 题意理解 给定一个插入序列就可以唯一确定一颗二叉搜索树。 但是&#xff0c;一颗给定…

82. Python split方法-分割字符串

82. split方法-分割字符串 文章目录 82. split方法-分割字符串1. 什么是split( )函数2. split( )方法的语法格式如下&#xff1a;3. 实操练习4. 列表索引取值知识回顾5. 用split方法分解网址提取有效信息6. 从地址信息中拆分省、市、区信息 1. 什么是split( )函数 split[splɪ…

vue相关知识导学

学习资料 Vue 相关源码地址&#xff1a; vue2.0 GitHub - vuejs/vue: This is the repo for Vue 2. For Vue 3, go to https://github.com/vuejs/coreVue3.0 GitHub - vuejs/core: &#x1f596; Vue.js is a progressive, incrementally-adoptable JavaScri…

Python 装饰器是怎么写的

其实我们已经创建了一个装饰器&#xff01; 一切皆对象&#xff0c;那是我的对象 现在我们修改下上一个装饰器&#xff0c;并编写一个稍微更有用点的程序&#xff1a; def a_new_decorator(a_func):def wrapTheFunction():print("I am doing some boring work before exe…

Python中的数据类型(python专栏002)

Python 中常用的数据类型包括&#xff1a; 数字类型&#xff1a;包括整型(int)、长整型(long)、浮点型(float)、复数型(complex)。字符串类型(str)&#xff1a;用于保存文本数据&#xff0c;可以使用单引号、双引号或三引号来定义字符串。列表类型(list)&#xff1a;可以保存多…

用ChatGPT通过WebSocket开发一个交互性的五子棋微信小程序(二)

文章目录 1 前言1.1 实现的原理1.2 如何与微信小程序联系 2 五子棋项目2.1 申请OpenAI的API2.2 调用API代码2.3 界面代码 3 同步五子棋到前端小程序3.1 WebSocket长连接3.2 获取实时下棋 4 讨论 1 前言 1.1 实现的原理 大体方向是将ChatGPT作为后端语言模型&#xff0c;然后将…

比较全的颜色RGB值对应表 8位 16位

实色效果英文名称R.G.B16色实色效果英文名称R.G.B16色Snow255 250 250#FFFAFAPaleTurquoise1187 255 255#BBFFFFGhostWhite248 248 255#F8F8FFPaleTurquoise2174 238 238#AEEEEEWhiteSmoke245 245 245#F5F5F5PaleTurquoise3150 205 205#96CDCDGainsboro220 220 220#DCDCDCPaleT…

Linux pthread线程操作 和 线程同步与互斥操作

在Linux系统中玩线程&#xff0c;使用pthread&#xff0c;这篇博客记录如何创建线程和使用线程和线程的同步与互斥。 还有一份nginx线程池的代码供大家阅读学习&#xff01; 目录 一、简介 什么是线程 线程的优点、缺点 线程的应用场合 二、线程的使用 1. 创建线程 - p…