文章目录
1. 前期准备工作
1.1 创建订单相关的表
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');
表之间的对应关系

2.2 创建service_order模块
- 在service下创建service_order模块
- 导入依赖
<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>
- 使用代码生成器生成代码
public class CodeGeneral {
@Test
public void run() {
// 1、创建代码生成器
AutoGenerator mpg = new AutoGenerator();
// 2、全局配置
GlobalConfig gc = new GlobalConfig();
String projectPath = System.getProperty("user.dir");
gc.setOutputDir("D:\\guli_parent\\service\\service_order" + "/src/main/java");
gc.setAuthor("smile");
gc.setOpen(false); //生成后是否打开资源管理器
gc.setFileOverride(false); //重新生成时文件是否覆盖
//UserServie
gc.setServiceName("%sService"); //去掉Service接口的首字母I
gc.setIdType(IdType.ID_WORKER_STR); //主键策略
gc.setDateType(DateType.ONLY_DATE);//定义生成的实体类中日期类型
gc.setSwagger2(true);//开启Swagger2模式
mpg.setGlobalConfig(gc);
// 3、数据源配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://localhost:3306/guli?serverTimezone=GMT%2B8");
dsc.setDriverName("com.mysql.cj.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("root");
dsc.setDbType(DbType.MYSQL);
mpg.setDataSource(dsc);
// 4、包配置
PackageConfig pc = new PackageConfig();
pc.setModuleName("eduorder"); //模块名
//包 com.atguigu.eduservice
pc.setParent("com.atguigu");
//包 com.atguigu.eduservice.controller
pc.setController("controller");
pc.setEntity("domain");
pc.setService("service");
pc.setMapper("mapper");
mpg.setPackageInfo(pc);
// 5、策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setInclude("t_order","t_pay_log");
strategy.setNaming(NamingStrategy.underline_to_camel);//数据库表映射到实体的命名策略
strategy.setTablePrefix(pc.getModuleName() + "_"); //生成实体时去掉表前缀
strategy.setColumnNaming(NamingStrategy.underline_to_camel);//数据库表字段映射到实体的命名策略
strategy.setEntityLombokModel(true); // lombok 模型 @Accessors(chain = true) setter链式操作
strategy.setRestControllerStyle(true); //restful api风格控制器
strategy.setControllerMappingHyphenStyle(true); //url中驼峰转连字符
mpg.setStrategy(strategy);
// 6、执行
mpg.execute();
}
}
2. 微信支付后端相关的接口
- 生成订单接口
- 根据订单id查询订单信息
- 生成微信支付二维码
- 查询订单支付状态接口
2.1 生成订单的接口

- 在common_utils下创建远程调用返回课程信息和用户信息的实体类
返回课程信息的实体类CourseWebVoOrder
@Data
public class CourseWebVoOrder {
private String id;
@ApiModelProperty(value = "课程标题")
private String title;
@ApiModelProperty(value = "课程销售价格,设置为0则可免费观看")
private BigDecimal price;
@ApiModelProperty(value = "总课时")
private Integer lessonNum;
@ApiModelProperty(value = "课程封面图片路径")
private String cover;
@ApiModelProperty(value = "销售数量")
private Long buyCount;
@ApiModelProperty(value = "浏览数量")
private Long viewCount;
@ApiModelProperty(value = "课程简介")
private String description;
@ApiModelProperty(value = "讲师ID")
private String teacherId;
@ApiModelProperty(value = "讲师姓名")
private String teacherName;
@ApiModelProperty(value = "讲师资历,一句话说明讲师")
private String intro;
@ApiModelProperty(value = "讲师头像")
private String avatar;
@ApiModelProperty(value = "课程类别ID")
private String subjectLevelOneId;
@ApiModelProperty(value = "类别称名")
private String subjectLevelOne;
@ApiModelProperty(value = "课程类别ID")
private String subjectLevelTwoId;
@ApiModelProperty(value = "类别名称")
private String subjectLevelTwo;
}
返回用户信息的实体类UCenterMemberOrder
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@ApiModel(value="UcenterMember对象", description="会员表")
public class UcenterMemberOrder implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "会员id")
@TableId(value = "id", type = IdType.ID_WORKER_STR)
private String id;
@ApiModelProperty(value = "微信openid")
private String openid;
@ApiModelProperty(value = "手机号")
private String mobile;
@ApiModelProperty(value = "密码")
private String password;
@ApiModelProperty(value = "昵称")
private String nickname;
@ApiModelProperty(value = "性别 1 女,2 男")
private Integer sex;
@ApiModelProperty(value = "年龄")
private Integer age;
@ApiModelProperty(value = "用户头像")
private String avatar;
@ApiModelProperty(value = "用户签名")
private String sign;
@ApiModelProperty(value = "是否禁用 1(true)已禁用, 0(false)未禁用")
private Boolean isDisabled;
@ApiModelProperty(value = "逻辑删除 1(true)已删除, 0(false)未删除")
private Boolean isDeleted;
@TableField(fill = FieldFill.INSERT)
@ApiModelProperty(value = "创建时间")
private Date gmtCreate;
@TableField(fill = FieldFill.INSERT_UPDATE)
@ApiModelProperty(value = "更新时间")
private Date gmtModified;
}
- 在service_ucenter模块下的UCentermemberController中创建根据用户id返回用户信息的接口
//根据用户id获取用户信息
@PostMapping("/getUserInfoOrder/{id}")
public UcenterMemberOrder getUserInfoOrder(@PathVariable String id)
{
UcenterMember ucenterMember = memberService.getById(id);
UcenterMemberOrder ucenterMemberOrder = new UcenterMemberOrder();
//把member里面的对象值赋值给UcenterMemberOrder对象
BeanUtils.copyProperties(ucenterMember,ucenterMemberOrder);
return ucenterMemberOrder;
}
- 在service_edu模块下的TeacherFrontController创建根据课程id查询课程信息的接口
//根据课程id查询课程信息
@PostMapping("/getCourseInfoOrder/{id}")
public CourseWebVoOrder getCourseInfoOrder(@PathVariable String id)
{
CourseWebVo courseInfo = courseService.getBaseCourseInfo(id);
CourseWebVoOrder courseWebVoOrder = new CourseWebVoOrder();
BeanUtils.copyProperties(courseInfo,courseWebVoOrder);
return courseWebVoOrder;
}
- 在service_order创建远程调用的接口
EduClient
@Component
@FeignClient("service-edu")
public interface EduClient {
//根据课程id查询课程信息
@PostMapping("/eduservice/coursefront/getCourseInfoOrder/{id}")
public CourseWebVoOrder getCourseInfoOrder(@PathVariable("id") String id);
}
UCenterClient
@Component
@FeignClient("service-ucenter")
public interface UCenterClient {
//根据用户id获取用户信息
@PostMapping("/eudcenter/member/getUserInfoOrder/{id}")
public UcenterMemberOrder getUserInfoOrder(@PathVariable("id") String id);
}
- 创建生成订单的工具类
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;
}
}
- 在TOrderController创建返回订单信息的接口
@RestController
@RequestMapping("/eduorder/order")
public class TOrderController {
@Autowired
private TOrderService tOrderService;
//生成订单的方法
@PostMapping("/createOrder/{courseId}")
public R saveOrder(@PathVariable String courseId, HttpServletRequest request)
{
//创建订单,返回订单号
String orderNo=tOrderService.createOrders(courseId, JwtUtils.getMemberIdByJwtToken(request));
return R.ok().data("orderNo",orderNo);
}
}
- service层
@Autowired
private EduClient eduClient;
@Qualifier("UCenterClient")
@Autowired
private UCenterClient uCenterClient;
//生成订单的方法
@Override
public String createOrders(String courseId, String memberId) {
//通过远程调用根据用户id获取用户信息
UcenterMemberOrder userInfoOrder = uCenterClient.getUserInfoOrder(memberId);
//5通过远程调用根据课程id获取课程信息
CourseWebVoOrder courseInfoOrder = eduClient.getCourseInfoOrder(courseId);
// 创建order并设置数据
TOrder order = new TOrder();
order.setOrderNo(OrderNoUtil.getOrderNo());
order.setCourseId(courseId);
order.setCourseTitle(courseInfoOrder.getTitle());
order.setCourseCover(courseInfoOrder.getCover());
order.setTeacherName("test");
order.setTotalFee(courseInfoOrder.getPrice());
order.setMemberId(memberId);
order.setMobile(userInfoOrder.getMobile());
order.setNickname(userInfoOrder.getNickname());
order.setStatus(0);
order.setPayType(1);
baseMapper.insert(order);
return order.getOrderNo();
}
2.2 根据订单id查询订单信息
在service_order模块下的TOrderController中
//根据订单id查询订单信息
@GetMapping("/getOrderInfo/{orderId}")
public R getOrderInfo(@PathVariable String orderId)
{
QueryWrapper<TOrder> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("order_no",orderId);
TOrder order = tOrderService.getOne(queryWrapper);
return R.ok().data("item",order);
}
2.3 微信支付二维码
- 准备工作
微信支付id,商户号,商户key - 在service_order模块中TPayLogController
@RestController
@RequestMapping("/eduorder/paylog")
@CrossOrigin
public class TPayLogController {
@Autowired
private TPayLogService payLogService;
//生成微信支付二维码接口
//参数为订单号
@GetMapping("/createNative/{orderNo}")
public R createNative(@PathVariable String orderNo)
{
//返回信息,二维码地址和其他需要的信息
Map map= payLogService.createNative(orderNo);
System.out.println("***********返回二维码"+map);
return R.ok().data(map);
}
//根据订单号查询支付状态
@GetMapping("/queryStatus/{orderNo}")
public R queryStatus (@PathVariable String orderNo)
{
Map<String,String> map= payLogService.queryPayStatus(orderNo);
System.out.println("*****************查询订单状态的map集合"+map);
if(map==null)
{
return R.error().message("支付出错了");
}
if(map.get("trade_state").equals("SUCCESS"))
{
//添加记录到支付表,更新订单表状态
payLogService.updateOrdersStatus(map);
return R.ok().message("支付成功");
}
return R.ok().message("支付中");
}
}
- Http请求和客户端
在utils包下HttpClient
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;
}
}
- 对应的service
@Service
public class TPayLogServiceImpl extends ServiceImpl<TPayLogMapper, TPayLog> implements TPayLogService {
@Autowired
private TOrderService orderService;
@Override
public Map createNative(String orderNo) {
try {
//1、根据订单id获取订单信息
QueryWrapper<TOrder> wrapper = new QueryWrapper<>();
wrapper.eq("order_no",orderNo);
TOrder order = orderService.getOne(wrapper);
Map m = new HashMap();
//2、设置支付参数
//微信id
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()+"");
//显示的地址
m.put("spbill_create_ip", "127.0.0.1");
//回调的地址
m.put("notify_url", "http://guli.shop/api/order/weixinPay/weixinNotify\n");
//类型
m.put("trade_type", "NATIVE");
//3、HTTPClient来根据URL访问第三方接口并且传递参数
HttpClient client = new HttpClient("https://api.mch.weixin.qq.com/pay/unifiedorder");
//client设置参数 商户key
client.setXmlParam(WXPayUtil.generateSignedXml(m, "T6m9iK73b0kn9g5v426MKfHQH7X8rKwb"));
client.setHttps(true);
client.post();
//4、返回第三方的数据
//得到返回的内容
String xml = client.getContent();
//xml转换为map集合
Map<String, String> resultMap = WXPayUtil.xmlToMap(xml);
//5、封装返回结果集
Map map = new HashMap<>();
map.put("out_trade_no", orderNo);
map.put("course_id", order.getCourseId());
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) {
throw new GuliException(20001,"生成二维码失败");
}
}
//根据订单号,查询订单状态
@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 client = new HttpClient("https://api.mch.weixin.qq.com/pay/orderquery");
client.setXmlParam(WXPayUtil.generateSignedXml(m, "T6m9iK73b0kn9g5v426MKfHQH7X8rKwb"));
client.setHttps(true);
client.post();
//3、返回第三方的数据
String xml = client.getContent();
Map<String, String> resultMap = WXPayUtil.xmlToMap(xml);
//6、转成Map返回
return resultMap;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
//添加支付记录和更新订单状态
@Override
public void updateOrdersStatus(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 = orderService.getOne(wrapper);
//更新订单状态 1为支付 0为未支付
if(order.getStatus().intValue() == 1) return;
order.setStatus(1);
orderService.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);//插入到支付日志表
}
}
3. 整合生成订单页面
3.1. 复制订单和支付页面所需要的css
3.2. 点击立即购买,生成订单订单,绑定事件,编写方法调用接口
- 在api中定义order.js文件
import request from '@/utils/request'
export default{
//生成订单
createOrders(courseId){
return request({
url:'/eduorder/order/createOrder/'+courseId,
method: 'POST'
})
},
//根据订单id查询订单信息
getOrdersInfo(id){
return request({
url:'/eduorder/order/getOrderInfo/'+id,
method: 'GET'
})
}
}
- 在页面进行调用
在课程详情页面立即购买按钮,绑定事件,调用方法
methods:{
//生成订单
createOrders(){
ordersApi.createOrders(this.courseId)
.then(response =>{
//获取返回的订单号
//生成订单后跳转订单显示页面
this.$router.push({path:'/orders/'+response.data.data.orderNo})
})
}
}
- 创建订单显示页面,在pages目录下创建一个orders目录,下面创建一个_oid.vue用于显示订单状态
<template>
<div class="Page Confirm">
<div class="Title">
<h1 class="fl f18">订单确认</h1>
<img src="~/assets/img/cart_setp2.png" class="fr">
<div class="clear"></div>
</div>
<form name="flowForm" id="flowForm" method="post" action="">
<table class="GoodList">
<tbody>
<tr>
<th class="name">商品</th>
<th class="price">原价</th>
<th class="priceNew">价格</th>
</tr>
</tbody>
<tbody>
<!-- <tr>
<td colspan="3" class="Title red f18 fb"><p>限时折扣</p></td>
</tr> -->
<tr>
<td colspan="3" class="teacher">讲师:{{order.teacherName}}</td>
</tr>
<tr class="good">
<td class="name First">
<a target="_blank" :href="'https://localhost:3000/course/'+order.courseId">
<img :src="order.courseCover"></a>
<div class="goodInfo">
<input type="hidden" class="ids ids_14502" value="14502">
<a target="_blank" :href="'https://localhost:3000/course/'+ order.courseId">{{order.courseTitle}}</a>
</div>
</td>
<td class="price">
<p>¥<strong>{{order.totalFee}}</strong></p>
<!-- <span class="discName red">限时8折</span> -->
</td>
<td class="red priceNew Last">¥<strong>{{order.totalFee}}</strong></td>
</tr>
<tr>
<td class="Billing tr" colspan="3">
<div class="tr">
<p>共 <strong class="red">1</strong> 件商品,合计<span
class="red f20">¥<strong>{{order.totalFee}}</strong></span></p>
</div>
</td>
</tr>
</tbody>
</table>
<div class="Finish">
<div class="fr" id="AgreeDiv">
<label for="Agree"><p class="on"><input type="checkbox" checked="checked">我已阅读并同意<a href="javascript:" target="_blank">《谷粒学院购买协议》</a></p></label>
</div>
<div class="clear"></div>
<div class="Main fl">
<div class="fl">
<a :href="'/course/'+order.courseId">返回课程详情页</a>
</div>
<div class="fr">
<p>共 <strong class="red">1</strong> 件商品,合计<span class="red f20">¥<strong
id="AllPrice">{{order.totalFee}}</strong></span></p>
</div>
</div>
<input name="score" value="0" type="hidden" id="usedScore">
<button class="fr redb" type="button" id="submitPay" @click="toPay()">去支付</button>
<div class="clear"></div>
</div>
</form>
</div>
</template>
<script>
import ordersApi from '@/api/order'
export default {
asyncData({ params, error }) {
return ordersApi.getOrdersInfo(params.oid)
.then(response => {
return {
order: response.data.data.item
}
})
}
}
</script>
- 在order.js中添加支付相关的路由信息
//生成二维码的方法
createNative(orderNo){
return request({
url:'/eduorder/paylog/createNative/'+orderNo,
method:'get'
})
},
//查看订单状态
queryPayStatus(orderNo){
return request({
url:'/eduorder/paylog/queryStatus/'+orderNo,
method:'get'
})
}
- 在pages下面创建一个pay文件夹,在pay文件夹创建_pid.vue用来调用支付信息
<template>
<div class="cart py-container">
<!--主内容-->
<div class="checkout py-container pay">
<div class="checkout-tit">
<h4 class="fl tit-txt"><span class="success-icon"></span><span class="success-info">订单提交成功,请您及时付款!订单号:{{payObj.out_trade_no}}</span>
</h4>
<span class="fr"><em class="sui-lead">应付金额:</em><em class="orange money">¥{{payObj.total_fee}}</em></span>
<div class="clearfix"></div>
</div>
<div class="checkout-steps">
<div class="fl weixin">微信支付</div>
<div class="fl sao">
<p class="red">请使用微信扫一扫。</p>
<div class="fl code">
<!-- <img id="qrious" src="~/assets/img/erweima.png" alt=""> -->
<!-- <qriously value="weixin://wxpay/bizpayurl?pr=R7tnDpZ" :size="338"/> -->
<qriously :value="payObj.code_url" :size="338"/>
<div class="saosao">
<p>请使用微信扫一扫</p>
<p>扫描二维码支付</p>
</div>
</div>
</div>
<div class="clearfix"></div>
<!-- <p><a href="pay.html" target="_blank">> 其他支付方式</a></p> -->
</div>
</div>
</div>
</template>
<script>
import ordersApi from '@/api/order'
export default {
asyncData({ params, error }) {
console.log(params.pid)
return ordersApi.createNative(params.pid)
.then(response => {
console.log(response.data.data)
return {
payObj: response.data.data
}
})
} ,
data() {
return {
timer1:''
}
},
//每隔三秒调用一次查询订单状态的方法
mounted() {//页面渲染之后执行
this.timer1 = setInterval(() => {
this.queryOrderStatus(this.payObj.out_trade_no)
},3000);
},
methods:{
queryOrderStatus(orderNo) {
ordersApi.queryPayStatus(orderNo)
.then(response => {
if (response.data.success) {
//支付成功,清除定时器
clearInterval(this.timer1)
//提示
this.$message({
type: 'success',
message: '支付成功!'
})
//跳转回到课程详情页面
this.$router.push({path: '/course/' + this.payObj.course_id})
}
})
}
}
}
</script>
4.功能完善
4.1 课程详情页面,有按钮 立即观看(立即购买)
- 如果课程是免费课程,按钮显示立即观看
- 如果课程已支付过,按钮显示立即观看
- 如果课程没有购买或者不是免费课程,按钮显示立即购买
4.2 如何判断课程是否已经支付
根据课程id和用户id去查询订单表,查询订单状态,如何值为1 表示已经支付,否则未支付
在service_order模块中在TOrderController添加查询账单状态的接口
//根据课程id和用户id查询订单表中的订单状态
@GetMapping("isBuyCourse/{courseId}/{memberId}")
public boolean isBuyCourse(@PathVariable String courseId,@PathVariable String memberId)
{
QueryWrapper<TOrder> wrapper = new QueryWrapper<>();
wrapper.eq("course_id",courseId);
wrapper.eq("member_id",memberId);
wrapper.eq("status",1);
int count = tOrderService.count(wrapper);
if(count>0)
return true;
else
return false;
}
4.2 修改课程详情的接口
在service_edu模块中CourseFromController修改查询课程详情的接口
写服务调用的接口
在service_edu模块下的client包下创建远程调用的接口
@FeignClient(name = "service-order")
@Component
public interface OrderClient {
@GetMapping("/eduorder/order/isBuyCourse/{courseId}/{memberId}")
public boolean isBuyCourse(@PathVariable("courseId") String courseId, @PathVariable("memberId") String memberId);
}
在CourseFromController修改查询课程详情的接口
//课程详情
@GetMapping("/getFrontCourseInfo/{courseId}")
public R getBaseCourseInfo(@PathVariable String courseId, HttpServletRequest request){
//根据课程id编写SQL语句,查询课程信息
CourseWebVo courseWebVo= courseService.getBaseCourseInfo(courseId);
//根据课程id查询章节和小节
List<ChapterVo> chapterVoList = chapterService.getChapterVideoByCourseId(courseId);
//根据课程id和用户id判断课程是否以及支付过了
boolean buyCourse = orderClient.isBuyCourse(courseId, JwtUtils.getMemberIdByJwtToken(request));
return R.ok().data("courseWebVo",courseWebVo).data("chapterVoList",chapterVoList).data("isBuy",buyCourse);
}
在pages/course/_id_vue修改vue请求内容
export default {
asyncData({params,error}){
return {courseId:params.id}
},
data(){
return {
courseWebVo: {},
chapterVoList: [],
isbuy: false,
}
},
created(){//在页面渲染之前执行
this.initCourseInfo()
},
methods:{
//查询课程详情信息
initCourseInfo()
{
courseApi.getCourseInfo(this.courseId)
.then(response =>{
this.courseWebVo=response.data.data.courseWebVo,
this.chapterVoList=response.data.data.chapterVoList,
this.isbuy=response.data.data.isBuy
})
},
//生成订单
createOrders(){
ordersApi.createOrders(this.courseId)
.then(response =>{
//获取返回的订单号
//生成订单后跳转订单显示页
this.$router.push({path:'/orders/'+response.data.data.orderNo})
})
}
}
};
以及购买函数的调用


998

被折叠的 条评论
为什么被折叠?



