一、环境搭建
1、引入依赖
<!--微信支付-->
<dependency>
<groupId>com.github.wxpay</groupId>
<artifactId>wxpay-sdk</artifactId>
<version>0.0.3</version>
</dependency>
<!--fastjson-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.70</version>
</dependency>

2、数据库

# Host: localhost (Version 5.7.19)
# Date: 2019-11-18 15:49:50
# Generator: MySQL-Front 6.1 (Build 1.26)
#
# Structure for table "t_order"
#
CREATE TABLE `t_order` (
`id` char(19) NOT NULL DEFAULT '',
`order_no` varchar(20) NOT NULL DEFAULT '' COMMENT '订单号',
`course_id` varchar(19) NOT NULL DEFAULT '' COMMENT '课程id',
`course_title` varchar(100) DEFAULT NULL COMMENT '课程名称',
`course_cover` varchar(255) DEFAULT NULL COMMENT '课程封面',
`teacher_name` varchar(20) DEFAULT NULL COMMENT '讲师名称',
`member_id` varchar(19) NOT NULL DEFAULT '' COMMENT '会员id',
`nickname` varchar(50) DEFAULT NULL COMMENT '会员昵称',
`mobile` varchar(11) DEFAULT NULL COMMENT '会员手机',
`total_fee` decimal(10,2) DEFAULT '0.01' COMMENT '订单金额(分)',
`pay_type` tinyint(3) DEFAULT NULL COMMENT '支付类型(1:微信 2:支付宝)',
`status` tinyint(3) DEFAULT NULL COMMENT '订单状态(0:未支付 1:已支付)',
`is_deleted` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '逻辑删除 1(true)已删除, 0(false)未删除',
`gmt_create` datetime NOT NULL COMMENT '创建时间',
`gmt_modified` datetime NOT NULL COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `ux_order_no` (`order_no`),
KEY `idx_course_id` (`course_id`),
KEY `idx_member_id` (`member_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单';
#
# Data for table "t_order"
#
INSERT INTO `t_order` VALUES ('1195693605513891841','1195693605555834880','18','Java精品课程','http://guli-file.oss-cn-beijing.aliyuncs.com/cover/2019/03/06/866e9aca-b530-4f71-a690-72d4a4bfd1e7.jpg','晴天','1','小三1231','13700000001',1,NULL,0,0,'2019-11-16 21:22:25','2019-11-16 21:22:25'),('1195694200178118657','1195694200186507264','18','Java精品课程','http://guli-file.oss-cn-beijing.aliyuncs.com/cover/2019/03/06/866e9aca-b530-4f71-a690-72d4a4bfd1e7.jpg','晴天','1','小三1231','13700000001',1,NULL,0,0,'2019-11-16 21:24:47','2019-11-16 21:24:47'),('1196264007411744769','1196264005255872512','1192252213659774977','java基础课程:test','https://guli-file-190513.oss-cn-beijing.aliyuncs.com/cover/default.gif','晴天','1','小三1231','13700000001',1,NULL,1,0,'2019-11-18 11:09:00','2019-11-18 11:10:14'),('1196265495278174209','1196265495273979904','18','Java精品课程','http://guli-file.oss-cn-beijing.aliyuncs.com/cover/2019/03/06/866e9aca-b530-4f71-a690-72d4a4bfd1e7.jpg','晴天','1','小三1231','13700000001',1,NULL,0,0,'2019-11-18 11:14:54','2019-11-18 11:14:54');
#
# Structure for table "t_pay_log"
#
CREATE TABLE `t_pay_log` (
`id` char(19) NOT NULL DEFAULT '',
`order_no` varchar(20) NOT NULL DEFAULT '' COMMENT '订单号',
`pay_time` datetime DEFAULT NULL COMMENT '支付完成时间',
`total_fee` decimal(10,2) DEFAULT '0.01' COMMENT '支付金额(分)',
`transaction_id` varchar(30) DEFAULT NULL COMMENT '交易流水号',
`trade_state` char(20) DEFAULT NULL COMMENT '交易状态',
`pay_type` tinyint(3) NOT NULL DEFAULT '0' COMMENT '支付类型(1:微信 2:支付宝)',
`attr` text COMMENT '其他属性',
`is_deleted` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '逻辑删除 1(true)已删除, 0(false)未删除',
`gmt_create` datetime NOT NULL COMMENT '创建时间',
`gmt_modified` datetime NOT NULL COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_order_no` (`order_no`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='支付日志表';
#
# Data for table "t_pay_log"
#
INSERT INTO `t_pay_log` VALUES ('1194498446013001730','1194498300579704832','2019-11-13 14:13:17',1,'4200000469201911130676624386','SUCCESS',1,'{\"transaction_id\":\"4200000469201911130676624386\",\"nonce_str\":\"2Lc23ILl231It53M\",\"trade_state\":\"SUCCESS\",\"bank_type\":\"CFT\",\"openid\":\"oNpSGwR-QGG5DaZtDkh2UZlsFDQE\",\"sign\":\"5404850AA3ED0E844DE104651477F07A\",\"return_msg\":\"OK\",\"fee_type\":\"CNY\",\"mch_id\":\"1473426802\",\"cash_fee\":\"1\",\"out_trade_no\":\"1194498300579704832\",\"cash_fee_type\":\"CNY\",\"appid\":\"wx8397f8696b538317\",\"total_fee\":\"1\",\"trade_state_desc\":\"支付成功\",\"trade_type\":\"NATIVE\",\"result_code\":\"SUCCESS\",\"attach\":\"\",\"time_end\":\"20191113141314\",\"is_subscribe\":\"N\",\"return_code\":\"SUCCESS\"}',0,'2019-11-13 14:13:17','2019-11-13 14:13:17'),('1195253787449430017','1195253049260314624','2019-11-15 16:14:44',1,'4200000454201911150981874895','SUCCESS',1,'{\"transaction_id\":\"4200000454201911150981874895\",\"nonce_str\":\"MAM5UM4Xhv1lItvO\",\"trade_state\":\"SUCCESS\",\"bank_type\":\"CFT\",\"openid\":\"oNpSGwR-QGG5DaZtDkh2UZlsFDQE\",\"sign\":\"7DBDCAF4A078B30BB3EF073E6A238C20\",\"return_msg\":\"OK\",\"fee_type\":\"CNY\",\"mch_id\":\"1473426802\",\"cash_fee\":\"1\",\"out_trade_no\":\"1195253049260314624\",\"cash_fee_type\":\"CNY\",\"appid\":\"wx8397f8696b538317\",\"total_fee\":\"1\",\"trade_state_desc\":\"支付成功\",\"trade_type\":\"NATIVE\",\"result_code\":\"SUCCESS\",\"attach\":\"\",\"time_end\":\"20191115161440\",\"is_subscribe\":\"N\",\"return_code\":\"SUCCESS\"}',0,'2019-11-15 16:14:44','2019-11-15 16:14:44'),('1196264321397342210','1196264005255872512','2019-11-18 11:10:14',1,'4200000453201911184025781554','SUCCESS',1,'{\"transaction_id\":\"4200000453201911184025781554\",\"nonce_str\":\"D1dHexCLIFIxAAg2\",\"trade_state\":\"SUCCESS\",\"bank_type\":\"CFT\",\"openid\":\"oNpSGwR-QGG5DaZtDkh2UZlsFDQE\",\"sign\":\"C9F5CA1EE49EA7891736D73BEB423962\",\"return_msg\":\"OK\",\"fee_type\":\"CNY\",\"mch_id\":\"1473426802\",\"cash_fee\":\"1\",\"out_trade_no\":\"1196264005255872512\",\"cash_fee_type\":\"CNY\",\"appid\":\"wx8397f8696b538317\",\"total_fee\":\"1\",\"trade_state_desc\":\"支付成功\",\"trade_type\":\"NATIVE\",\"result_code\":\"SUCCESS\",\"attach\":\"\",\"time_end\":\"20191118111011\",\"is_subscribe\":\"N\",\"return_code\":\"SUCCESS\"}',0,'2019-11-18 11:10:14','2019-11-18 11:10:14');

3、代码生成器生成代码





4、application.yml
server:
port: 8006 #微服务端口号为8001
spring:
application:
name: service-order #服务名
profiles:
active: dev #环境设置 dev表示构建阶段,test表示测试阶段,prod表示发布阶段
datasource: #数据源
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/gulischool?serverTimeZone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true
username: root
password: 123456
jackson: #我们的时区是东八区,应该加8个小时,时区显示格式也需要改成我们想要的
date-format: yyyy-MM-DD HH:mm:ss
time-zone: GMT+8
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848 #nacos
feign:
client:
config:
default:
connect-timeout: 10000 #设置超时限制,必须超过10000ms才报错
read-timeout: 10000 #设置Feign服务熔断机制的最大超时限制
hystrix:
enabled: true #开启熔断机制
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 6000 #设置hystri超时时间 默认1000ms(10s)
mybatis-plus:
mapper-locations: classpath:com/yzpnb/order_service/mapper/xml/*.xml #配置mapper xml文件的路径
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #mybatis日志
5、启动类
package com.yzpnb.order_service;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
@ComponentScan(basePackages={"com.yzpnb"})//这样它会将所有com.yzpnb包下内容扫描,而不只是扫描子文件或同级文件
@EnableDiscoveryClient //nacos注册
@MapperScan("com.yzpnb.order_service.mapper")
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class,args);
}
}
二、后端
| 所需接口 |
|---|
| 生成订单(用户点击购买按钮) |
| 根据订单id查询订单信息 |
| 生成微信支付二维码 |
| 查询订单支付状态接口 |
1、生成订单
| 分析 |
|---|
| 我们需要根据课程id获取课程信息 |
| 根据用户id获取用户信息 |
| 需要使用Feign |

1、编写根据课程id获取课程详细信息的接口
@ApiOperation("根据课程id获取课程信息")
@GetMapping("selectCourseAllInfoVoApiById")
public CourseAllInfoVo selectCourseAllInfoVoApiById(@ApiParam(name = "id",value = "课程id")
@RequestParam(value = "id") String id){
CourseAllInfoVo courseAllInfoVo = eduCourseService.selectCourseAllInfoVo(id);
return courseAllInfoVo;
}

2、复制对应实体类

3、编写feign接口

4、编写生成订单和根据订单id查询订单的接口
package com.yzpnb.order_service.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.yzpnb.common_utils.JwtUtils;
import com.yzpnb.common_utils.Result;
import com.yzpnb.order_service.entity.TOrder;
import com.yzpnb.order_service.entity.educourse.CourseAllInfoVo;
import com.yzpnb.order_service.entity.ucenter.UcenterMember;
import com.yzpnb.order_service.feign.FeignToEduServiceClient;
import com.yzpnb.order_service.feign.FeignToUcenterClient;
import com.yzpnb.order_service.service.TOrderService;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;
/**
* <p>
* 订单 前端控制器
* </p>
*
* @author testjava
* @since 2020-06-06
*/
@RestController
@RequestMapping("/order_service/t-order")
@CrossOrigin
public class TOrderController {
@Autowired
private TOrderService tOrderService;
@Autowired
private FeignToEduServiceClient feignToEduServiceClient;
@Autowired
private FeignToUcenterClient feignToUcenterClient;
@ApiOperation("根据课程id和用户id创建订单,返回订单id")
@PostMapping("createOrder/{courseId}")
public Result createOrder(@ApiParam(name = "courseId",value = "课程id")
@PathVariable(value = "courseId") String courseId,
HttpServletRequest request){
//1、获取用户id
String memberId = JwtUtils.getMemberIdByJwtToken(request);
//2、根据课程id获取课程信息
CourseAllInfoVo courseAllInfoVo = feignToEduServiceClient.selectCourseAllInfoVoApiById(courseId);
//3、根据用户id获取用户信息
UcenterMember ucenterMember = feignToUcenterClient.selectById(memberId);
//4、随机生成订单号
SimpleDateFormat sd=new SimpleDateFormat("yyyyMMddHHmmss");
Random random=new Random();
String orderNo="";
for(int i=0;i<=3;i++){
orderNo += random.nextInt(10);
}
orderNo=sd.format(new Date())+orderNo;
//4、创建订单
TOrder order=new TOrder();
order.setOrderNo(orderNo);//订单号
order.setCourseId(courseId);//课程id
order.setCourseTitle(courseAllInfoVo.getTitle());//课程标题
order.setCourseCover(courseAllInfoVo.getCover());//课程封面
order.setTeacherName(courseAllInfoVo.getTeacherName());//讲师姓名
order.setTotalFee(courseAllInfoVo.getPrice());//课程价格
order.setMemberId(memberId);//用户id
order.setMobile(ucenterMember.getMobile());//用户电话
order.setNickname(ucenterMember.getNickname());//用户昵称
order.setStatus(0);//订单状态,默认未支付
order.setPayType(1);//支付类型默认为1,微信支付
tOrderService.save(order);
return Result.ok().data("orderId",orderNo);
}
@ApiOperation("根据订单id获取订单信息")
@GetMapping("selectOrderById/{orderId}")
public Result selectOrderById(@PathVariable String orderId) {
QueryWrapper<TOrder> wrapper = new QueryWrapper<>();
wrapper.eq("order_no",orderId);
TOrder order = tOrderService.getOne(wrapper);
return Result.ok().data("item", order);
}
}

5、测试
| 涉及到HttpClient,就不要想着用swagger测试了,请直接跳到前端的1、订单页面整合中测试 |
|---|
2、生成微信支付二维码
1、前戏
| 和上次的微信二维码登陆一样,这功能也需要企业认证,我们还是蹭尚硅谷的进行学习 |
|---|
weixin:
pay:
# 关联的公众号appid
appid: wx74862e0dfcf69954
# 商户号
partner: 1558950191
# 商户key
partnerkey: T6m9iK73b0kn9g5v426MKfHQH7X8rKwb
# 回调地址
notifyurl: http://guli.shop/api/order/weixinPay/weixinNotify
2、controller
package com.yzpnb.order_service.controller;
import com.yzpnb.common_utils.Result;
import com.yzpnb.order_service.service.TPayLogService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
/**
* <p>
* 支付日志表 前端控制器
* </p>
*
* @author testjava
* @since 2020-06-06
*/
@RestController
@RequestMapping("/order_service/t-pay-log")
@CrossOrigin
public class TPayLogController {
@Autowired
private TPayLogService tPayLogServicee;
/**
* 生成二维码
*
* @return
*/
@ApiOperation("根据订单号生成支付二维码")
@GetMapping("createNative/{orderNo}")
public Result createNative( @ApiParam(name = "orderNo",value = "订单号")
@PathVariable String orderNo) {
Map map = tPayLogServicee.createNative(orderNo);
return Result.ok().data(map);
}
}

3、工具类
| 引入依赖 |
|---|
<!--apache HttpClient-->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.12</version>
</dependency>

| 工具类,用来将字符串转换为Xml文件 |
|---|
package com.yzpnb.order_service.utils;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.*;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContextBuilder;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.text.ParseException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/**
* http请求客户端
*
* @author qy
*
*/
public class HttpClient {
private String url;
private Map<String, String> param;
private int statusCode;
private String content;
private String xmlParam;
private boolean isHttps;
public boolean isHttps() {
return isHttps;
}
public void setHttps(boolean isHttps) {
this.isHttps = isHttps;
}
public String getXmlParam() {
return xmlParam;
}
public void setXmlParam(String xmlParam) {
this.xmlParam = xmlParam;
}
public HttpClient(String url, Map<String, String> param) {
this.url = url;
this.param = param;
}
public HttpClient(String url) {
this.url = url;
}
public void setParameter(Map<String, String> map) {
param = map;
}
public void addParameter(String key, String value) {
if (param == null)
param = new HashMap<String, String>();
param.put(key, value);
}
public void post() throws ClientProtocolException, IOException {
HttpPost http = new HttpPost(url);
setEntity(http);
execute(http);
}
public void put() throws ClientProtocolException, IOException {
HttpPut http = new HttpPut(url);
setEntity(http);
execute(http);
}
public void get() throws ClientProtocolException, IOException {
if (param != null) {
StringBuilder url = new StringBuilder(this.url);
boolean isFirst = true;
for (String key : param.keySet()) {
if (isFirst)
url.append("?");
else
url.append("&");
url.append(key).append("=").append(param.get(key));
}
this.url = url.toString();
}
HttpGet http = new HttpGet(url);
execute(http);
}
/**
* set http post,put param
*/
private void setEntity(HttpEntityEnclosingRequestBase http) {
if (param != null) {
List<NameValuePair> nvps = new LinkedList<NameValuePair>();
for (String key : param.keySet())
nvps.add(new BasicNameValuePair(key, param.get(key))); // 参数
http.setEntity(new UrlEncodedFormEntity(nvps, Consts.UTF_8)); // 设置参数
}
if (xmlParam != null) {
http.setEntity(new StringEntity(xmlParam, Consts.UTF_8));
}
}
private void execute(HttpUriRequest http) throws ClientProtocolException,
IOException {
CloseableHttpClient httpClient = null;
try {
if (isHttps) {
SSLContext sslContext = new SSLContextBuilder()
.loadTrustMaterial(null, new TrustStrategy() {
// 信任所有
public boolean isTrusted(X509Certificate[] chain,
String authType)
throws CertificateException {
return true;
}
}).build();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
sslContext);
httpClient = HttpClients.custom().setSSLSocketFactory(sslsf)
.build();
} else {
httpClient = HttpClients.createDefault();
}
CloseableHttpResponse response = httpClient.execute(http);
try {
if (response != null) {
if (response.getStatusLine() != null)
statusCode = response.getStatusLine().getStatusCode();
HttpEntity entity = response.getEntity();
// 响应内容
content = EntityUtils.toString(entity, Consts.UTF_8);
}
} finally {
response.close();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
httpClient.close();
}
}
public int getStatusCode() {
return statusCode;
}
public String getContent() throws ParseException, IOException {
return content;
}
}

4、service
package com.yzpnb.order_service.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.wxpay.sdk.WXPayUtil;
import com.yzpnb.order_service.entity.TOrder;
import com.yzpnb.order_service.entity.TPayLog;
import com.yzpnb.order_service.mapper.TPayLogMapper;
import com.yzpnb.order_service.service.TOrderService;
import com.yzpnb.order_service.service.TPayLogService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yzpnb.order_service.utils.HttpClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
/**
* <p>
* 支付日志表 服务实现类
* </p>
*
* @author testjava
* @since 2020-06-06
*/
@Service
public class TPayLogServiceImpl extends ServiceImpl<TPayLogMapper, TPayLog> implements TPayLogService {
@Autowired
private TOrderService tOrderService; //引入订单接口
/**
* 根据订单号获取支付二维码
* @param orderNo
* @return
*/
@Override
public Map createNative(String orderNo) {
try {
//根据订单id获取订单信息
QueryWrapper<TOrder> wrapper = new QueryWrapper<>();
wrapper.eq("order_no",orderNo);
TOrder order = tOrderService.getOne(wrapper);
Map m = new HashMap();
//1、设置支付参数
m.put("appid", "wx74862e0dfcf69954"); //关联公众号
m.put("mch_id", "1558950191"); //商户号
m.put("nonce_str", WXPayUtil.generateNonceStr()); //微信官方提供工具类,帮我们生成随机字符串,让我们每个二维码都不一样
m.put("body", order.getCourseTitle()); //主体,一般写课程名称什么的,表示订单名称
m.put("out_trade_no", orderNo); //二维码唯一标识,这里我直接填订单号
m.put("total_fee", order.getTotalFee().multiply(new BigDecimal("100")).longValue()+"");//订单价格,改成圆角分的Long类型,并转为字符串
m.put("spbill_create_ip", "127.0.0.1"); //支付ip地址,一般写你的项目域名yzpnb.XXXX,这里做本地测试,所以写127.0.0.1
m.put("notify_url", "http://guli.shop/api/order/weixinPay/weixinNotify\n");//回调地址
m.put("trade_type", "NATIVE");//生成支付类型,NATIAE表示根据价格生成二维码
//2、HTTPClient来根据URL访问第三方接口并且传递参数,发送httpclient请求,传递参数xml格式,传入微信支付提供的固定地址
HttpClient client = new HttpClient("https://api.mch.weixin.qq.com/pay/unifiedorder");
//client设置参数
client.setXmlParam(WXPayUtil.generateSignedXml(m, "T6m9iK73b0kn9g5v426MKfHQH7X8rKwb"));//使用了微信工具类,通过商户key对参数进行加密
client.setHttps(true);//我们访问https请求,默认不支持,将其设置为支持
client.post();//使用post发送http请求
//3、返回第三方的数据
String xml = client.getContent();//返回信息为xml格式信息
Map<String, String> resultMap = WXPayUtil.xmlToMap(xml);//通过微信工具类,将xml格式解析为map集合
//4、封装返回结果集
Map map = new HashMap<>();
map.put("out_trade_no", orderNo); //订单编号
map.put("course_id", order.getCourseId()); //课程id
map.put("total_fee", order.getTotalFee()); //总价格
map.put("result_code", resultMap.get("result_code")); //发送请求后状态码(微信返回的)
map.put("code_url", resultMap.get("code_url")); //二维码地址(微信返回的)
//微信支付二维码2小时过期,可采取2小时未支付取消订单
//redisTemplate.opsForValue().set(orderNo, map, 120, TimeUnit.MINUTES);
return map;
} catch (Exception e) {
e.printStackTrace();
return new HashMap<>();//请求二维码失败,返回空的map集合
}
}
}

3、查询支付状态,订单是否支付成功
| 如果支付成功,将订单表中支付状态改为1,日志表中增加记录(用于申诉等使用) |
|---|
1、controller
@ApiOperation("根据订单号查询支付状态,支付成功,添加订单日志")
@GetMapping("/queryPayStatus/{orderNo}")
public Result queryPayStatus(@PathVariable String orderNo) {
//调用查询接口,查询订单状态(不是我们的数据库状态,而是微信中支付状态,为了方便,还是返回map)
Map<String, String> map = tPayLogServicee.queryPayStatus(orderNo);
if (map == null) {//没有值,表示没有支付,出错
return Result.error().message("支付出错");
}
if (map.get("trade_state").equals("SUCCESS")) {//获取微信返回数据中支付状态,如果成功
//更改订单状态,改订单状态为1,并添加日志
tPayLogServicee.updateOrderStatus(map);
return Result.ok().message("支付成功");
}
return Result.ok().code(25000).message("支付中");
}
### 2、service
/**
* 根据订单号查询订单支付状态(微信)
* @param orderNo
* @return
*/
@Override
public Map<String, String> queryPayStatus(String orderNo) {
try {
//1、封装参数
Map m = new HashMap<>();
m.put("appid", "wx74862e0dfcf69954"); //公众号
m.put("mch_id", "1558950191"); //商户号
m.put("out_trade_no", orderNo); //二维码唯一标识,这里我直接填订单号
m.put("nonce_str", WXPayUtil.generateNonceStr()); //微信官方提供工具类,帮我们生成随机字符串
//2、设置请求
//HTTPClient来根据URL访问第三方接口并且传递参数,发送httpclient请求,传递参数xml格式,传入微信支付提供的固定地址
HttpClient client = new HttpClient("https://api.mch.weixin.qq.com/pay/orderquery");
client.setXmlParam(WXPayUtil.generateSignedXml(m, "T6m9iK73b0kn9g5v426MKfHQH7X8rKwb"));//使用了微信工具类,通过商户key对参数进行加密
client.setHttps(true);//我们访问https请求,默认不支持,将其设置为支持
client.post();//使用post发送http请求
//3、返回第三方的数据
String xml = client.getContent();//返回信息为xml格式信息
//4、转成Map
Map<String, String> resultMap = WXPayUtil.xmlToMap(xml);//通过微信工具类,将xml格式解析为map集合
//5、返回
return resultMap;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 更改订单状态,改订单状态为1,并添加日志
* @param map
*/
@Override
public void updateOrderStatus(Map<String, String> map) {
//获取订单id
String orderNo = map.get("out_trade_no");
//根据订单id查询订单信息
QueryWrapper<TOrder> wrapper = new QueryWrapper<>();
wrapper.eq("order_no",orderNo);
TOrder order = tOrderService.getOne(wrapper);
if(order.getStatus().intValue() == 1) return;//为1表示已经支付,不执行下面的操作
order.setStatus(1);//否则就设置为1
tOrderService.updateById(order);//修改订单状态
//记录支付日志
TPayLog payLog=new TPayLog();
payLog.setOrderNo(order.getOrderNo());//支付订单号
payLog.setPayTime(new Date());
payLog.setPayType(1);//支付类型
payLog.setTotalFee(order.getTotalFee());//总金额(分)
payLog.setTradeState(map.get("trade_state"));//支付状态
payLog.setTransactionId(map.get("transaction_id"));
payLog.setAttr(JSONObject.toJSONString(map));
baseMapper.insert(payLog);//插入到支付日志表
}

4、课程详情功能完善
| 查看课程详情的时候,判断用户是否已经购买课程 |
|---|
1、编写根据用户id和课程id查询订单信息接口
@ApiOperation("根据用户id和课程id查询订单信息,已经支付返回true,没有返回false")
@GetMapping("isBuyCourse")
public boolean isBuyCourse(@RequestParam(value = "memberid") String memberid,
@RequestParam(value = "courseid") String courseid) {
//订单状态是1表示支付成功
int count = tOrderService.count(new QueryWrapper<TOrder>().eq("member_id", memberid).eq("course_id", courseid).eq("status", 1));
if(count>0) {
return true;
} else {
return false;
}
}

2、service-edu中远程调用接口

3、编写查询是否被购买接口
//根据id查询课程详情信息
@Autowired
private FeignToOrderClient feignToOrderClient;
@ApiOperation("根据id查询课程详情,并判断课程十分被购买")
@GetMapping("getCourseInfo/{id}")
public Result getCourseInfo(@PathVariable(value = "id") String id, HttpServletRequest request) {
//课程查询课程基本信息
CourseApiInfoVo courseApiInfoVo = eduCourseService.selectCourserApiInfoVoById(id);
//查询课程里面大纲数据
List<ChapterVo> chapterVideoList = eduChapterService.selectChapterVideoByCourseId(id);
//远程调用,判断课程是否被购买
boolean buyCourse = feignToOrderClient.isBuyCourse(JwtUtils.getMemberIdByJwtToken(request), id);
Map<String , Object> map=new HashMap<>();
map.put("courseFrontInfo",courseApiInfoVo);
map.put("chapterVideoList",chapterVideoList);
map.put("isbuy",buyCourse);
return Result.ok().data(map);
}

4、测试

三、前端
1、订单页面整合
1、修改课程详情页面代码,实现点击购买,跳转页面

2、编写订单动态路由页面


2、二维码页面整合(qriously组件)
| 需要使用qriously组件,它会根据地址实时下载图片显示 |
|---|



1、修改订单页面,点击去支付,跳转到支付页面

2、编写api接口

3、编写程序



4、测试


3、修改课程页面,让其判断,购买状态,如果已购,不显示立即购买,显示立即观看
1、api接口

2、代码


3、测试

744





