目录
接口实现
第一步:当点击立即购买生成订单
第二步:根据订单id查询订单信息
第三步:生成微信支付的二维码
第四步:查询订单支付状态
前端实现
编辑
1.点击支付
2.订单详情页
接口实现
像这种微服务B2C模式的,订单业务需要远程调用我们的课程信息+用户信息
依赖:
<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>
第一步:当点击立即购买生成订单
通过远程调用,order业务调用course+user
1.查询Course课程信息暴露出来的接口+用户信息接口
@Component
@FeignClient("service-edu")
public interface EduClient {
/**
* 1.远程调用ucenter中根据id获取用户信息的方法
*/
@GetMapping("/eduservice/indexfront/getCourseInfoOrder/{id}")
public CourseWebVoOrder getCourseInfoOrder(@PathVariable String id);
}
@Component
@FeignClient("service-ucenter")
public interface UcenterClient {
/**
* 1.根据课程id查询课程信息
*/
@GetMapping("/educenter/member/getUserInfoOrder/{id}")
public UcenterMemberOrder getUserInfoOrder(@PathVariable("id") String id);
}
2.生成订单的接口+实现类
通过请求头得到token然后给到JWT进行解析得到用户id
@RestController
@RequestMapping("/eduorder/order")
@CrossOrigin
public class OrderController {
@Autowired
private OrderService orderService;
/**
* 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);
}
/**
* <p>
* 订单 服务实现类
* </p>
*
* @author testjava
* @since 2022-07-25
*/
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {
@Autowired
private EduClient eduClient;
@Autowired
private UcenterClient ucenterClient;
/**
* 1.生成订单的方法,通过远程调用两个feign方法(课程信息和人物信息)结合到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对象,向order对象里面设置需要的数据
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();
}
}
返回的CourseWebVoOrder等远程调用的类放在公共模块中
第二步:根据订单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);
}
第三步:生成微信支付的二维码
准备工作(wxid,商户号,商户key)
1.根据订单号获取订单信息
/**
* <p>
* 支付日志表 前端控制器
* </p>
*
* @author testjava
* @since 2022-07-25
*/
@RestController
@RequestMapping("/eduorder/paylog")
@CrossOrigin
public class PayLogController {
@Autowired
private PayLogService payLogService;
/**
* 1.生成微信支付的二维码接口
*/
@GetMapping("createNative/{orderNo}")
public R createNative(@PathVariable String orderNo) {
//1.返回信息含有二维码的地址还有其他信息
Map map = payLogService.createNative(orderNo);
System.out.println("*****返回二维码map集合****:"+map);
return R.ok().data(map);
}
2.1根据订单号获取订单信息——>2.2业务实现类中设置支付参数 ——>2.3将参数请求到我们vx支付的接口地址,回调得到返回集(client.getContent(),利用WXPayUtil将xml转为map集合方便返回到前端)
@Service
public class PayLogServiceImpl extends ServiceImpl<PayLogMapper, PayLog> implements PayLogService {
@Autowired
private OrderService orderService;
/**
* 1.返回二维码地址
* @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,"生成二维码失败");
}
}
第四步:查询订单支付状态
1.先查订单的支付状态,返回的支付state为成功——>2.然后在支付日志表中添加一条记录,并且更新订单表状态
/**
* 2.查询订单状态
* @param orderNo
* @return
*/
@GetMapping("queryPayStatus/{orderNo}")
public R queryPayStatus(@PathVariable String orderNo){
Map<String,String>map= payLogService.queryPayStatus(orderNo);
System.out.println("返回二维码状态:"+map);
//1.根据查询出来的订单状态进行判断
if(map==null){
return R.error().message("支付出错了...");
}
//2.如果返回的map不为空,从这里面获取订单状态
if(map.get("trade_state").equals("SUCCESS")){//支付成功
//3.添加记录到支付表中,并且更新订单表的状态
payLogService.updateOrdersStatus(map);
return R.ok();
}
return R.ok().code(25000).message("支付中");
}
}
业务实现类-根据订单号查询订单状态
/**
* 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;
}
业务实现-添加支付记录+更新订单状态
/**
* 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.更新订单表的订单状态
if(order.getStatus().intValue()==1){
return;//说明支付过了
}
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);//插入到支付日志表
}
前端实现
当点击商品的去支付就会生成支付的二维码
1.点击支付
methods:{
//去支付,通过动态路由的方式传递orderNo订单号
toPay(){
this.$router.push({path:'/pay/'+this.order.orderNo})
}
}
2.订单详情页
因为oid页面到pid页面点击toPay方法传入订单号,我们这里根据订单号调后台接口createNative生成二维码
mouted()方法:里面定义一个定时器,每3s判断一次订单的状态,如果订单响应状态为success则清除定时器——>跳转到订单详情页去看视频
import ordersApi from "@/api/order";
export default {
//1.return除了要return方法还要return成功数据
asyncData({ params, error }) {
// 2.名字是pid,那么动态路由的参数就是pid
return ordersApi.createNative(params.pid).then((response) => {
return {
payObj: response.data.data,
};
});
},
data() {
return {
tiemer1: "",
};
},
//2.定义mouted,意思是页面渲染之后执行,防止没有数据
mounted() {
//1.每隔3s调一次查询订单状态方法
this.tiemer1 = setInterval(() => {
this.queryOrderStatus(this.payObj.out_trade_no);
}, 3000);
},
methods: {
//3.查询支付状态
queryOrderStatus(orderNo) {
ordersApi.queryPayStatus(orderNo).then((response) => {
console.log("正在查询订单信息.....");
console.log(response.data);
if(response.data.success){
console.log("支付成功,清除定时器")
//1.支付成功清除定时器
clearInterval(this.tiemer1);
//2.支付成功提示
this.$message({
type: "success",
message: "支付成功!",
});
//3.跳转到课程详情页面观看视频
this.$router.push({ path: "/course/" + this.payObj.course_id });
}
});
},
},
};
</script>