当前位置:网站首页>Payment module implementation
Payment module implementation
2022-07-31 22:09:00 【Fairy to carry】
目录
Payment module interface implementation
2.The business realization that generates the order
4.User and course information for remote calls
Payment generates a QR code interface for WeChat payment
1.控制层,Returns a collection of QR codes
Follow-up actions after payment
场景:
课程分为免费课程和付费课程,如果是免费课程可以直接观看,如果是付费观看的课程,用户需下单支付后才可以观看
2.付费课程流程
2.1如果是付费课程,在用户选择课程,进入到课程详情页面时候,会显示 “立即购买”
2.2 点击“立即购买”,会生成课程的订单,跳转到订单页面
2.3点击“去支付”,会跳转到支付页面,生成微信扫描的二维码
使用微信扫描支付后,会跳转回到课程详情页面,同时显示“立即观看”
Payment module interface implementation
1.Import dependencies and configuration files and be explicitsqlTable about ideas
<dependencies>
<dependency>
<groupId>com.github.wxpay</groupId>
<artifactId>wxpay-sdk</artifactId>
<version>0.0.3</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
</dependencies>
1.2Two tables and one order table,当支付成功,The order status is sent to change,And insert new data into the payment log table
1.3配置文件
# 服务端口
server.port=8007
# 服务名
spring.application.name=service-order
# mysql数据库连接
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/guli?serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=root
#返回json的全局时间格式
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT+8
#配置mapper xml文件的路径
mybatis-plus.mapper-locations=classpath:com/atguigu/orderservice/mapper/xml/*.xml
#mybatis日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
# nacos服务地址
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
#开启熔断机制
feign.hystrix.enabled=true
# 设置hystrix超时时间,默认1000ms
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=3000
创建订单
1.编写控制层(创建订单)
思路:很简单,Something like order is definitely about users and classes,Therefore, the order should be based on the courseid和用户idCreate an order to return to the orderid(利用了feign的远程调用)
/**
* 1.生成订单的方法
*/
@GetMapping("createOrder/{courseId}")
public R saveOrder(@PathVariable String courseId, HttpServletRequest request){
//1.生成订单号
String orderNo=orderService.createOrders(courseId,JwtUtils.getMemberIdByJwtToken(request));
return R.ok().data("orderId",orderNo);
}
2.The business realization that generates the order
思路:1.The first is through the useridRemotely call the user module to get user information,Then the course module is similar——>2.创建Order对象,向里面添加数据,然后进行插入,返回订单号(This defines a time classOrderNoUtil根据时间生成)
/**
* 1.生成订单的方法,By calling both remotelyfeign方法(Course information and character information)结合到Ordermiddle order
* @param courseId
* @param memberId
* @return
*/
@Override
public String createOrders(String courseId, String memberId) {
//1.通过远程调用根据用户id获取用户信息
UcenterMemberOrder userInfoOrder = ucenterClient.getUserInfoOrder(memberId);
//2.通过远程调用根据课程id获取课程信息
CourseWebVoOrder courseInfoOrder = eduClient.getCourseInfoOrder(courseId);
//3.创建order对象,向orderSet the required data in the object
Order order = new Order();
order.setOrderNo(OrderNoUtil.getOrderNo());
order.setCourseId(courseId); //课程id
order.setCourseTitle(courseInfoOrder.getTitle());
order.setCourseCover(courseInfoOrder.getCover());
order.setTeacherName(courseInfoOrder.getTeacherName());
order.setTotalFee(courseInfoOrder.getPrice());
order.setMemberId(memberId);
order.setMobile(userInfoOrder.getMobile());
order.setNickname(userInfoOrder.getNickname());
order.setStatus(0);//订单状态(0:未支付 1:已支付)
order.setPayType(1);//支付类型 微信1
baseMapper.insert(order);//插入
return order.getOrderNo();
}
3.订单号生成类
package com.atguigu.eduorder.utils;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 订单号工具类
*
* @author qy
* @since 1.0
*/
public class OrderNoUtil {
/**
* 获取订单号
* @return
*/
public static String getOrderNo() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
String newDate = sdf.format(new Date());
String result = "";
Random random = new Random();
for (int i = 0; i < 3; i++) {
result += random.nextInt(10);
}
return newDate + result;
}
}
4.User and course information for remote calls
用户:通过request对里面tokenParse to get the userid然后根据id获取用户信息
/**
* 3.根据token获取用户信息
*/
@GetMapping("getMemberInfo")
public R getMemberInfo(HttpServletRequest request){
//getMemberIdByJwtToken根据请求头中的token得到用户信息(token得到userid->取出信息)
String memberId = JwtUtils.getMemberIdByJwtToken(request);
//根据用户id查询用户信息
UcenterMember member = memberService.getById(memberId);
return R.ok().data("userInfo",member);
}
/**
* 2.根据课程id查询课程基本信息
*/
@GetMapping("getCourseInfo/{courseId}")
public R getCourseInfo(@PathVariable String courseId){
CourseInfoVo courseInfoVo=courseService.getCourseInfo(courseId);
return R.ok().data("courseInfo",courseInfoVo);
}
根据订单id查询订单信息
/**
* 2.根据订单id查询订单信息
*/
@GetMapping("getOrderInfo/{orderId}")
public R getOrderInfo(@PathVariable String orderId){//订单id查询
QueryWrapper<Order> wrapper = new QueryWrapper<>();
wrapper.eq("order_no",orderId);
Order order = orderService.getOne(wrapper);
return R.ok().data("item",order);
}
Decide whether to purchase the course
思路:根据课程id和人物idThere are also course status judgments,Then query if based on these conditions>0代表已经支付
@GetMapping("isBuyCourse/{courseId}/{memberId}")
public boolean isBuyCourse(@PathVariable String courseId,@PathVariable String memberId){
QueryWrapper<Order> wrapper = new QueryWrapper<>();
wrapper.eq("course_id",courseId);
wrapper.eq("member_id",memberId);
wrapper.eq("status",1);
int count = orderService.count(wrapper);
if(count>0){
//代表已经支付
return true;
}else{
return false;
}
}
Payment generates a QR code interface for WeChat payment
1.控制层,Returns a collection of QR codes
/**
* 1.Generate a QR code interface for WeChat payment
*/
@GetMapping("createNative/{orderNo}")
public R createNative(@PathVariable String orderNo) {
//1.The returned information contains the address of the QR code and other information
Map map = payLogService.createNative(orderNo);
System.out.println("*****返回二维码map集合****:"+map);
return R.ok().data(map);
}
2.业务实现层
2.1首先根据订单id查询订单信息
2.2然后我们在map设置二维码参数
2.3Generated according to the fixed address provided by WeChatHttpClient
2.4因为我们httpClientThe request sent when requiredxml格式,所以需要将map转一下
2.5Send a request and get the result returned by the request,然后将结果转为map格式
2.6前面只是将map数据给到http生成对应二维码,We also have some hints,So define a final resultmap,将之前的map二维码地址,The status code and the price of the order and related data are encapsulated into the result set,然后返回
/**
* 1.Return the QR code address
* @param orderNo
* @return
*/
@Override
public Map createNative(String orderNo) {
try {
//1.根据订单id获取订单信息
QueryWrapper<Order> wrapper = new QueryWrapper<>();
wrapper.eq("order_no", orderNo);
Order order = orderService.getOne(wrapper);
//2.使用map设置二维码需要的参数
HashMap map = new HashMap();
map.put("appid","wx74862e0dfcf69954");
map.put("mch_id", "1558950191");
map.put("nonce_str", WXPayUtil.generateNonceStr());//随机生成一个二维码
map.put("body", order.getCourseTitle());
map.put("out_trade_no", orderNo);//二维码标识订单号
map.put("total_fee", order.getTotalFee().multiply(new BigDecimal("100")).longValue()+"");//价格
map.put("spbill_create_ip", "127.0.0.1");
map.put("notify_url", "http://guli.shop/api/order/weixinPay/weixinNotify\n");
map.put("trade_type", "NATIVE");
//3.发送httpclient请求,传递参数按照xml格式,微信支付提供固定地址
HttpClient client = new HttpClient("https://api.mch.weixin.qq.com/pay/unifiedorder");
//设置参数,我们的商户key会对这些map参数进行加密->将map根据key进行加密并且传送到请求中去
client.setXmlParam(WXPayUtil.generateSignedXml(map,"T6m9iK73b0kn9g5v426MKfHQH7X8rKwb"));
client.setHttps(true);
//执行请求发送
client.post();
//4.得到发送请求返回的结果,返回的内容是xml格式返回的(之前传参数也是xml格式)
String content = client.getContent();
//5.再把xml转为map
Map<String,String>resultMap=WXPayUtil.xmlToMap(content);
//6.前面的map只是为了给到http生成二维码,需要转为xml格式,现在我们这个结果resultMap就是二维码了
//还需要一些关于订单的提示信息
Map res = new HashMap<>();
res.put("out_trade_no", orderNo);
res.put("course_id", order.getCourseId());
res.put("total_fee", order.getTotalFee());
res.put("result_code", resultMap.get("result_code"));//状态码
res.put("code_url", resultMap.get("code_url"));//二维码地址
return res;
} catch (Exception e) {
throw new GuliException(20001,"生成二维码失败");
}
}
Follow-up actions after payment
1.控制层
思路:1.After payment, you need to check the payment status(Parameters in the QR code),如果状态SUCCESS,Just add our payment record to the payment table——>2.And after the payment is successful, the status of the order table must be modified,表示已经支付
/**
* 2.查询订单状态
* @param orderNo
* @return
*/
@GetMapping("queryPayStatus/{orderNo}")
public R queryPayStatus(@PathVariable String orderNo){
Map<String,String>map= payLogService.queryPayStatus(orderNo);
System.out.println("Returns the QR code status:"+map);
//1.根据查询出来的订单状态进行判断
if(map==null){
return R.error().message("支付出错了...");
}
//2.如果返回的map不为空,Get order status from here
if(map.get("trade_state").equals("SUCCESS")){//支付成功
//3.Add a record to the payment table,And update the status of the order table
payLogService.updateOrdersStatus(map);
return R.ok();
}
return R.ok().code(25000).message("支付中");
}
2.业务层
1.Still the same ideaorderNo查询订单支付状态queryPayStatus()
,Package order number WeChatid密钥,然后设置httpClient发送请求,and use merchantskey进行加密——>2.Then the content returned after the request is converted tomap返回——>3.根据返回map中getThe status determines whether to add payment records and update order statusupdateOrdersStatus()方法
/**
* 1.查询订单支付状态
* @param orderNo
* @return
*/
@Override
public Map<String, String> queryPayStatus(String orderNo) {
//1.封装参数
try {
HashMap map = new HashMap();
map.put("appid", "wx74862e0dfcf69954");
map.put("mch_id", "1558950191");
map.put("out_trade_no", orderNo);
map.put("nonce_str", WXPayUtil.generateNonceStr());
//2.设置请求,利用xml进行请求
HttpClient client = new HttpClient("https://api.mch.weixin.qq.com/pay/orderquery");
client.setXmlParam(WXPayUtil.generateSignedXml(map,"T6m9iK73b0kn9g5v426MKfHQH7X8rKwb"));
client.setHttps(true);
client.post();
//3.返回第三方的数据
String xml = client.getContent();
Map<String, String> resultMap = WXPayUtil.xmlToMap(xml);//将xml转为map数据
return resultMap;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
Add payment records and update order status after successful payment
1.从map中获取订单号,Then get the order data according to the order number,修改订单状态(Remember to judge the state first to improve efficiency)——>2.Then set the payment record in the payment record table
/**
* 2.添加支付记录和更新订单状态
* @param map
*/
@Override
public void updateOrdersStatus(Map<String, String> map) {
//1.从map中获取订单号
String orderNo = map.get("out_trade_no");
//2.根据订单号查询订单信息
QueryWrapper<Order> wrapper = new QueryWrapper<>();
wrapper.eq("order_no",orderNo);
Order order = orderService.getOne(wrapper);
//3.Update the order status of the order table
if(order.getStatus().intValue()==1){
return;//Description paid
}
order.setStatus(1);
orderService.updateById(order);
//4.向支付表中添加支付记录
PayLog payLog = new PayLog();
payLog.setOrderNo(orderNo);
payLog.setPayTime(new Date());
payLog.setPayType(1);//支付类型 1wx
payLog.setTotalFee(order.getTotalFee());//总金额(分)
payLog.setTradeState(map.get("trade_state"));//支付状态
payLog.setTransactionId(map.get("transaction_id"));//账单流水号
payLog.setAttr(JSONObject.toJSONString(map));
baseMapper.insert(payLog);//插入到支付日志表
}
边栏推荐
- 如何减少软件设计和实现之间鸿沟
- 架构实战营模块八作业
- SiC MOSFET的短路特性及保护
- Basic configuration of OSPFv3
- Qualcomm cDSP simple programming example (to query Qualcomm cDSP usage, signature), RK3588 npu usage query
- VOT2021比赛简介
- focus on!Haitai Fangyuan joins the "Personal Information Protection Self-discipline Convention"
- 基于STM32 环形队列来实现串口接收数据
- "The core concept of" image classification and target detection in the positive and negative samples and understanding architecture
- 【公开课预告】:超分辨率技术在视频画质增强领域的研究与应用
猜你喜欢
Redis Overview: Talk to the interviewer all night long about Redis caching, persistence, elimination mechanism, sentinel, and the underlying principles of clusters!...
What's wrong with the sql syntax in my sql
leetcode: 6135. The longest ring in the graph [inward base ring tree + longest ring board + timestamp]
Short-circuit characteristics and protection of SiC MOSFETs
[Intensive reading of the paper] iNeRF
ThreadLocal
Quick Start Tutorial for flyway
Memblaze发布首款基于长存颗粒的企业级SSD,背后有何新价值?
高通cDSP简单编程例子(实现查询高通cDSP使用率、签名),RK3588 npu使用率查询
useragent online lookup
随机推荐
登录业务实现(单点登录+微信扫码+短信服务)
Redis Overview: Talk to the interviewer all night long about Redis caching, persistence, elimination mechanism, sentinel, and the underlying principles of clusters!...
PCB叠层设计
The principle of ReentrantLock (to be continued)
Count characters in UTF-8 string function
二叉树非递归遍历
useragent online lookup
Document management and tools in the development process
Collation of knowledge points in Ningbo University NBU IT project management final exam
The old music player WinAmp released version 5.9 RC1: migrated to VS 2019, completely rebuilt, compatible with Win11
Pytest初体验
Student management system on the first day: complete login PyQt5 + MySQL5.8 exit the operation logic
【Yugong Series】July 2022 Go Teaching Course 025-Recursive Function
Qualcomm cDSP simple programming example (to query Qualcomm cDSP usage, signature), RK3588 npu usage query
利用反射实现一个管理对象信息的简单框架
linux查看redis版本命令(linux查看mysql版本号)
Returns a zero-length array or empty collection, do not return null
Go1.18 upgrade function - Fuzz test from scratch in Go language
Pytorch lstm time series prediction problem stepping on the pit "recommended collection"
Efficient Concurrency: A Detailed Explanation of Synchornized's Lock Optimization