目录
接口实现
第一步:当点击立即购买生成订单
第二步:根据订单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 {@Autowiredprivate 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 {@Autowiredprivate EduClient eduClient;@Autowiredprivate UcenterClient ucenterClient;/*** 1.生成订单的方法,通过远程调用两个feign方法(课程信息和人物信息)结合到Order中为订单* @param courseId* @param memberId* @return*/@Overridepublic 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); //课程idorder.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);//支付类型 微信1baseMapper.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 {@Autowiredprivate 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 {@Autowiredprivate OrderService orderService;/*** 1.返回二维码地址* @param orderNo* @return*/@Overridepublic 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转为mapMap<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*/@Overridepublic 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*/@Overridepublic 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);//支付类型 1wxpayLog.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,那么动态路由的参数就是pidreturn 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>