SpringCloud+Vue在线教育项目——课程支付模块(整合微信支付)

一、分析

在这里插入图片描述
需要写4个接口:
生成订单接口、根据订单ID查询订单信息接口、生成微信支付二维码接口、查询订单支付状态并且更新订单接口。

课程详情页面调用生成订单接口,来到订单详情页面,调用根据订单ID查询订单信息接口渲染页面。点击去支付来到支付页面,调用生成二维码接口,扫描支付后需要判断订单是否支付,根据微信官方API文档可以写出最后一个接口。

二、后端接口

1.controller

OrderController


@RestController
@RequestMapping("/eduorder/order")
@CrossOrigin
public class OrderController {


    @Autowired
    private OrderService orderService;

    //1 生成订单
    @PostMapping("/generateOrder/{courseId}")
    public R generateOrder(@PathVariable String courseId, HttpServletRequest request){
        String orderId = orderService.generateOrder(courseId, JwtUtils.getMemberIdByJwtToken(request));

        return R.ok().data("orderId", orderId);
    }

    //2 根据订单ID查询订单信息
    @GetMapping("/getOrderInfoById/{orderId}")
    @ApiOperation("根据订单ID查询订单信息")
    public R getOrderInfoById(@PathVariable String orderId){
        QueryWrapper<Order> wrapper = new QueryWrapper<>();
        wrapper.eq("order_no", orderId);

        Order order = orderService.getOne(wrapper);

        System.out.println(order);
        return R.ok().data("orderInfo", order);
    }

}

PayLogController

@RestController
@RequestMapping("/eduorder/paylog")
@CrossOrigin
@Api(description = "课程支付模块")
public class PayLogController {


    @Autowired
    private PayLogService payLogService;


    //生成微信二维码
    @GetMapping("/generateWXCode/{orderId}")
    @ApiOperation("生成微信二维码")
    public R generateWXCode(@PathVariable String orderId){
        //返回信息:包含二维码地址,还有其他信息
        Map<String, Object> map = payLogService.generateWXCode(orderId);

        System.out.println("二维码信息:" + map);

        return R.ok().data(map);
    }


    //查询订单支付状态并且更新订单
    @GetMapping("/findPayStatus/{orderId}")
    @ApiOperation("查询订单状态")
    public R findPayStatus(@PathVariable String orderId){
        Map<String,String> map = payLogService.findPayStatus(orderId);

        System.out.println("订单信息:" + map);

        if (map == null){
            return R.error().message("支付出错了!").data("status",0);
        }

        //如果返回map里面不为空,通过map获取订单状态
        if (map.get("trade_state").equals("SUCCESS")){
            //向支付表中添加记录,更新订单状态
            payLogService.updateOrderStatus(map);
            return R.ok().message("支付成功").data("status",1);
        }

        return R.ok().code(25000).message("正在支付中").data("status",2);
    }

}

2.service

OrderServiceImpl

@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {

    @Autowired
    private EduClient eduClient;

    @Autowired
    private UCenterClient uCenterClient;

    //生成订单
    @Override
    public String generateOrder(String courseId, String memberId) {
        //1 通过远程调用 调用根据课程ID查询课程信息
        CourseWebVoOrder courseWebVoOrder = eduClient.getCourseInfoById(courseId);
        //2 通过远程调用 调用根据用户ID查询用户信息
        UcenterMemberOrder ucenterMemberOrder = uCenterClient.getMemberInfoById(memberId);

        //3 创建order对象,向order对象set
        Order order = new Order();
        order.setOrderNo(UUID.randomUUID().toString().replaceAll("-",""));//订单号
        order.setCourseId(courseId);//课程ID
        order.setCourseTitle(courseWebVoOrder.getTitle());//课程标题
        order.setCourseCover(courseWebVoOrder.getCover());//课程封面
        order.setTeacherName(courseWebVoOrder.getTeacherName());//教师名称
        order.setTotalFee(courseWebVoOrder.getPrice());//课程价格
        order.setMemberId(memberId);//会员ID
        order.setMobile(ucenterMemberOrder.getMobile());//会员手机号
        order.setNickname(ucenterMemberOrder.getNickname());//会员姓名
        order.setStatus(0);//订单状态 未支付状态
        order.setPayType(1);//支付方式 1 微信支付 2 支付宝

        //4 加入数据库
        baseMapper.insert(order);

        return order.getOrderNo();
    }
}

PayLogServiceImpl

@Service
public class PayLogServiceImpl extends ServiceImpl<PayLogMapper, PayLog> implements PayLogService {

    @Autowired
    private OrderService orderService;

    //生成二维码
    @Override
    public Map<String, Object> generateWXCode(String orderId) {
        try {
            //1 根据订单号查询订单信息
            QueryWrapper<Order> wrapper = new QueryWrapper<>();
            wrapper.eq("order_no", orderId);
            Order order = orderService.getOne(wrapper);

            //2 使用map设置生成二维码需要参数
            Map<String,String> paramsMap = new HashMap<>();
            paramsMap.put("appid","appid");
            paramsMap.put("mch_id", "mch_id");
            paramsMap.put("nonce_str", WXPayUtil.generateNonceStr());
            paramsMap.put("body", order.getCourseTitle()); //课程标题
            paramsMap.put("out_trade_no", orderId); //订单号
            paramsMap.put("total_fee", order.getTotalFee().multiply(new BigDecimal("100")).longValue()+"");
            paramsMap.put("spbill_create_ip", "127.0.0.1");
            paramsMap.put("notify_url", "http://guli.shop/api/order/weixinPay/weixinNotify\n");
            paramsMap.put("trade_type", "NATIVE");

            //3 发送httpclient请求,传递参数xml格式,微信支付提供的固定的地址
            HttpClient client = new HttpClient("https://api.mch.weixin.qq.com/pay/unifiedorder");

            //设置xml格式的参数
            client.setXmlParam(WXPayUtil.generateSignedXml(paramsMap, "key"));
            client.setHttps(true);

            //4 执行请求发送
            client.post();

            //5 得到发送请求返回的内容
            String xmlContent = client.getContent();//注意,这个格式是xml格式的

            Map<String,String> resultMap = WXPayUtil.xmlToMap(xmlContent);

            //6 最终返回数据的封装
            Map<String,Object> dataMap = new HashMap<>();
            dataMap.put("out_trade_no", orderId);
            dataMap.put("course_id", order.getCourseId());
            dataMap.put("total_fee", order.getTotalFee());
            dataMap.put("result_code", resultMap.get("result_code"));  //返回二维码操作状态码
            dataMap.put("code_url", resultMap.get("code_url"));        //二维码地址

            return dataMap;

        }catch (Exception e){
            e.printStackTrace();
            throw new GuliException(20001, "生成二维码失败!");
        }

    }

    //查询订单支付状态
    @Override
    public Map<String, String> findPayStatus(String orderId) {
        try {
            //1、封装参数
            Map<String,String> m = new HashMap<>();
            m.put("appid", "appid");
            m.put("mch_id", "mch_id");
            m.put("out_trade_no", orderId);
            m.put("nonce_str", WXPayUtil.generateNonceStr());

            //2 发送httpclient
            HttpClient client = new HttpClient("https://api.mch.weixin.qq.com/pay/orderquery");
            client.setXmlParam(WXPayUtil.generateSignedXml(m,"key"));
            client.setHttps(true);
            client.post();

            //3 得到请求返回内容
            String xml = client.getContent();
            //6、转成Map再返回
            return WXPayUtil.xmlToMap(xml);
        }catch(Exception e) {
            return null;
        }
    }


    //根据id更新订单状态,同时新增一条支付记录
    @Override
    public void updateOrderStatus(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() != 1){
            order.setStatus(1);
            boolean update = orderService.updateById(order);
            if (!update){
                throw new GuliException(20001, "添加失败!");
            }
        }

        //4 向支付表中添加支付记录
        PayLog payLog = new PayLog();
        payLog.setOrderNo(orderNo);//订单号
        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));//fastjson

        int insert = baseMapper.insert(payLog);

        if (insert == 0){
            throw new GuliException(20001, "添加支付记录失败!");
        }

    }
}

三、前端页面

order.js

import request from '@/utils/request'

export default{
    //1 生成订单
    generateOrder(courseId){
        return request ({
            url: `/eduorder/order/generateOrder/${courseId}`,
            method: 'post'
        })
    },
    //2 根据订单ID查询订单信息
    getOrderInfoById(orderId){
        return request ({
            url: `/eduorder/order/getOrderInfoById/${orderId}`,
            method: 'get'
        })
    },
    //3 生成微信二维码
    generateWXCode(orderId){
        return request({
            url: `/eduorder/paylog/generateWXCode/${orderId}`,
            method: 'get'
        })
    },
    //4 根据订单ID查询订单支付状态并且更新订单
    findPayStatus(orderId){
        return request({
            url: `/eduorder/paylog/findPayStatus/${orderId}`,
            method: 'get'
        })
    }
}

course/_id.vue js部分代码

<script>
import courseApi from '@/api/course'
import orderApi from '@/api/order'
import memberApi from '@/api/member'

import cookie from 'js-cookie';


export default {
  
  //异步调用
  asyncData({ params, error }){
    return courseApi.getCourseInfo(params.id).then(response => {
      return {
        courseWebVo: response.data.data.courseWebVo,
        chapterVideoList: response.data.data.chapterVideoList,
        courseId: params.id
      }
    })
  },
  methods: {
    //生成订单
    purchase(){
      
        orderApi.generateOrder(this.courseId).then(response => {

        //获取订单号
        const orderId = response.data.data.orderId
        alert(orderId)
        //生成订单后,跳转到订单详情页面
        this.$router.push({ path: '/order/' + orderId })
        })
      }
    
  }
}
</script>

order/_id.vue js部分代码

<script>
import orderApi from '@/api/order'

export default {
    asyncData({ params, error }) {
        return orderApi.getOrderInfoById(params.id)
            .then(response => {
                return {
                    order: response.data.data.orderInfo
                }
            })
    },
    methods:{
      //去支付
      toPay(){
        alert(this.order)
        this.$router.push({  path: `/pay/` + this.order.orderNo })
      }
    }
   
}
</script>

pay/_pid.vue js部分代码

<script>
import orderApi from '@/api/order'

export default {
    asyncData({params,error}){
        return orderApi.generateWXCode(params.pid).then(response => {
            return {
                payObj: response.data.data
            }
        })
    },
    data(){
        return {
            timer: ''
        }

    },
    //在页面渲染之后执行
    mounted(){
        //定时器,每隔三秒调用一次查询订单状态的方法
        this.timer = setInterval(() => {
                        this.queryOrderStatus(this.payObj.out_trade_no)
                    },3000)
    },
    methods:{
        //查询订单状态
        queryOrderStatus(orderNo){
            orderApi.findPayStatus(orderNo).then(response => {
                    console.log(response.data)
                    //清除定时器
                    clearInterval(this.timer)

                    //提示信息
                    this.$message({
                        type: 'success',
                        message: '支付成功!'
                    })
                    //跳转回到课程详情页面
                    this.$router.push({path: '/course/' + this.payObj.course_id})
                
            })
        }
    }
}
</script>

四、效果

1 在课程详情页面点击立即购买来到订单详情页面
在这里插入图片描述
2 在订单详情页面,点击去支付来到支付页面
在这里插入图片描述
3 在支付页面扫描二维码支付成功回到课程页面
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

热爱旅行的小李同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值