当前位置:网站首页>支付模块实现

支付模块实现

2022-07-31 21:33:00 Fairy要carry

目录

 2.付费课程流程

 支付模块接口实现

创建订单 

1.编写控制层(创建订单)

2.生成订单的业务实现

3.订单号生成类

4.远程调用的用户和课程信息

根据订单id查询订单信息

支付生成微信支付的二维码接口

1.控制层,返回二维码集合

 2.业务实现层

支付之后的后续操作

1.控制层

2.业务层


场景:

课程分为免费课程和付费课程,如果是免费课程可以直接观看,如果是付费观看的课程,用户需下单支付后才可以观看

 2.付费课程流程

2.1如果是付费课程,在用户选择课程,进入到课程详情页面时候,会显示 “立即购买”

2.2 点击“立即购买”,会生成课程的订单,跳转到订单页面

 2.3点击“去支付”,会跳转到支付页面,生成微信扫描的二维码

 使用微信扫描支付后,会跳转回到课程详情页面,同时显示“立即观看”

 支付模块接口实现

1.导入依赖和配置文件并且明确sql表大概思路

<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>

1.2两个表一个订单表,当支付成功,订单状态发送改变,并且向支付日志表插入新的数据

1.3配置文件

# 服务端口
server.port=8007
# 服务名
spring.application.name=service-order

# mysql数据库连接
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/guli?serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=root

#返回json的全局时间格式
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT+8

#配置mapper xml文件的路径
mybatis-plus.mapper-locations=classpath:com/atguigu/orderservice/mapper/xml/*.xml

#mybatis日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

# nacos服务地址
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848

#开启熔断机制
feign.hystrix.enabled=true
# 设置hystrix超时时间,默认1000ms
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=3000

创建订单 

1.编写控制层(创建订单)

思路:很简单,像订单这种肯定是关于用户和课程的,所以下单的话需要根据课程id和用户id创建订单返回订单id(利用了feign的远程调用)

  /**
     * 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);
    }

2.生成订单的业务实现

思路:1.首先是通过用户id远程调用用户模块得到用户信息,然后课程模块类似——>2.创建Order对象,向里面添加数据,然后进行插入,返回订单号(这个定义了一个时间类OrderNoUtil根据时间生成)

  /**
     * 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();
    }

3.订单号生成类

package com.atguigu.eduorder.utils;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 订单号工具类
 *
 * @author qy
 * @since 1.0
 */
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;
    }

}

4.远程调用的用户和课程信息

用户:通过request对里面token进行解析得到用户id然后根据id获取用户信息

    /**
     * 3.根据token获取用户信息
     */
    @GetMapping("getMemberInfo")
    public R getMemberInfo(HttpServletRequest request){
        //getMemberIdByJwtToken根据请求头中的token得到用户信息(token得到userid->取出信息)
        String memberId = JwtUtils.getMemberIdByJwtToken(request);
        //根据用户id查询用户信息
        UcenterMember member = memberService.getById(memberId);
        return R.ok().data("userInfo",member);
    }
    /**
     * 2.根据课程id查询课程基本信息
     */
    @GetMapping("getCourseInfo/{courseId}")
    public R getCourseInfo(@PathVariable String courseId){
       CourseInfoVo courseInfoVo=courseService.getCourseInfo(courseId);
       return R.ok().data("courseInfo",courseInfoVo);
    }

根据订单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);
    }

判断是否购买课程

思路:根据课程id和人物id还有课程状态进行判断,然后根据这些条件进行查询如果>0代表已经支付

 @GetMapping("isBuyCourse/{courseId}/{memberId}")
    public boolean isBuyCourse(@PathVariable String courseId,@PathVariable String memberId){
        QueryWrapper<Order> wrapper = new QueryWrapper<>();
        wrapper.eq("course_id",courseId);
        wrapper.eq("member_id",memberId);
        wrapper.eq("status",1);

        int count = orderService.count(wrapper);
        if(count>0){
            //代表已经支付
            return true;
        }else{
            return false;
        }

    }

支付生成微信支付的二维码接口

1.控制层,返回二维码集合

 /**
     * 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.业务实现层

 2.1首先根据订单id查询订单信息

 2.2然后我们在map设置二维码参数

 2.3根据微信提供的固定地址生成HttpClient

 2.4因为我们httpClient发送的请求需要时xml格式,所以需要将map转一下

 2.5发送请求得到请求返回的结果,然后将结果转为map格式

 2.6前面只是将map数据给到http生成对应二维码,我们还有一些提示信息,所以定义一个最终结果map,将之前的map二维码地址,状态码啥的还有订单的价格及相关数据封装到结果集中,然后返回

  /**
     * 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.控制层

思路:1.支付之后需要查询支付状态(二维码中的参数),如果状态SUCCESS,就将我们的支付记录添加到支付表中——>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("支付中");
    }

2.业务层

1.还是一样的思路根据orderNo查询订单支付状态queryPayStatus()

,封装订单号微信id密钥,然后设置httpClient发送请求,并且利用商户key进行加密——>2.然后请求之后返回的内容再转为map返回——>3.根据返回map中get的状态决定是否添加支付记录和更新订单状态updateOrdersStatus()方法

 /**
     * 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;
    }

支付成功后添加支付记录和更新订单状态

 1.从map中获取订单号,然后根据订单号得到订单数据,修改订单状态(记得先判断状态提高效率)——>2.然后向支付记录表中设置支付记录

  /**
     * 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);//插入到支付日志表
    }

原网站

版权声明
本文为[Fairy要carry]所创,转载请带上原文链接,感谢
https://blog.csdn.net/weixin_57128596/article/details/126080321

随机推荐