我的编程空间,编程开发者的网络收藏夹
学习永远不晚

SpringBoot实现整合微信支付方法详解

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

SpringBoot实现整合微信支付方法详解

1.准备工作

1.1 数据库表

这里涉及微信支付一共两个表:

订单表

支付记录表

1.2 实体类

数据库对应的实体类:

订单表


@Data
@ToString
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("t_order")
@ApiModel(value = "Order对象", description = "订单")
public class Order implements Serializable {

    private static final long serialVersionUID = 1L;

    @TableId(value = "id", type = IdType.ID_WORKER_STR)
    private String id;

    @ApiModelProperty(value = "订单号")
    private String orderNo;

    @ApiModelProperty(value = "课程id")
    private String courseId;

    @ApiModelProperty(value = "课程名称")
    private String courseTitle;

    @ApiModelProperty(value = "课程封面")
    private String courseCover;

    @ApiModelProperty(value = "讲师名称")
    private String teacherName;

    @ApiModelProperty(value = "会员id")
    private String memberId;

    @ApiModelProperty(value = "会员昵称")
    private String nickname;

    @ApiModelProperty(value = "会员手机")
    private String mobile;

    @ApiModelProperty(value = "订单金额(分)")
    private BigDecimal totalFee;

    @ApiModelProperty(value = "支付类型(1:微信 2:支付宝)")
    private Integer payType;

    @ApiModelProperty(value = "订单状态(0:未支付 1:已支付)")
    private Integer status;

    @ApiModelProperty(value = "逻辑删除 1(true)已删除, 0(false)未删除")
    private Boolean isDeleted;

    @ApiModelProperty(value = "创建时间")
    @TableField(fill = FieldFill.INSERT)
    private Date gmtCreate;

    @ApiModelProperty(value = "更新时间")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date gmtModified;
}

支付日志表


@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("t_pay_log")
@ApiModel(value = "PayLog对象", description = "支付日志表")
public class PayLog implements Serializable {

    private static final long serialVersionUID = 1L;

    @TableId(value = "id", type = IdType.ID_WORKER_STR)
    private String id;

    @ApiModelProperty(value = "订单号")
    private String orderNo;

    @ApiModelProperty(value = "支付完成时间")
    private Date payTime;

    @ApiModelProperty(value = "支付金额(分)")
    private BigDecimal totalFee;

    @ApiModelProperty(value = "交易流水号")
    private String transactionId;

    @ApiModelProperty(value = "交易状态")
    private String tradeState;

    @ApiModelProperty(value = "支付类型(1:微信 2:支付宝)")
    private Integer payType;

    @ApiModelProperty(value = "其他属性")
    private String attr;

    @ApiModelProperty(value = "逻辑删除 1(true)已删除, 0(false)未删除")
    private Boolean isDeleted;

    @ApiModelProperty(value = "创建时间")
    @TableField(fill = FieldFill.INSERT)
    private Date gmtCreate;

    @ApiModelProperty(value = "更新时间")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date gmtModified;
}

1.3 导入依赖

在订单模块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>

1.4 配置文件

在配置文件application.properties配置相关的信息:


# 服务端口
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/eduorder/mapper/xml
    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;
    }
}

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

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

}

2.生成订单

这里一共涉及service_order订单模块、service_ucenter用户模块、service-edu课程模块。

service_order使用Fegin远程调用其他模块的方法。

详细的Fegin的使用可以参考:SpringCloud-Feign远程调用

2.1 远程调用用户模块和课程模块

在service_order订单模块创建:


@Component
@FeignClient("service-ucenter") //调用的服务名称
public interface UcenterClient {

    //根据用户id获取用户信息,用于生成订单使用
    @PostMapping("/educenter/member/getUserInfoOrder/{id}")
    public UcenterMemberOrder getUserInfoOrder(@PathVariable("id") String id);
}

@Component
@FeignClient("service-edu") //调用的服务名称
public interface CourseClient {

    //根据课程id查询课程信息
    @PostMapping("/eduservice/coursefront/getCourseInfoOrder/{id}")
    public CourseWebOrder getCourseInfoOrder(@PathVariable("id") String id);

}

2.2 远程调用方法的实现

在service-edu课程模块实现根据课程id查询课程信息的getCourseInfoOrder方法

controller层:



@PostMapping("getCourseInfoOrder/{id}")
public CourseWebOrder getCourseInfoOrder(@PathVariable("id") String id) {
    CourseWebVo courseInfo = courseService.getBaseCourseInfo(id);
    CourseWebOrder courseWebOrder = new CourseWebOrder();
    BeanUtils.copyProperties(courseInfo, courseWebOrder);
    return courseWebOrder;
}

service层:



@Override
public CourseWebVo getBaseCourseInfo(String courseId) {
    return baseMapper.getBaseCourseInfo(courseId);
}

mapper层:


<!--根据课程id查询课程基本信息-->
<select id="getBaseCourseInfo" resultType="com.atguigu.eduservice.entity.frontvo.CourseWebVo">
    SELECT ec.id,
    ec.`title`,
    ec.`price`,
    ec.lesson_num as lessonNum,
    ec.cover,
    ec.buy_count  as buyCount,
    ec.view_count as viewCount,
    ecd.description,
    et.id            teacherId,
    et.`name`     AS teacherName,
    et.intro,
    et.avatar,
    es1.id        as subjectLevelOneId,
    es1.`title`   AS subjectLevelOne,
    es2.id        as subjectLevelTwoId,
    es2.`title`   AS subjectLevelTwo
    FROM edu_course ec
    LEFT JOIN edu_course_description ecd ON ec.id = ecd.id
    LEFT JOIN edu_teacher et ON ec.`teacher_id` = et.`id`
    LEFT JOIN edu_subject es1 ON ec.`subject_parent_id` = es1.`id`
    LEFT JOIN edu_subject es2 ON ec.`subject_id` = es2.`id`
    WHERE ec.id = #{courseId}
</select>

在service_ucenter用户模块实现根据用户id获取用户信息的getUserInfoOrder方法

controller层:



@PostMapping("getUserInfoOrder/{id}")
public UcenterMemberOrder getUserInfoOrder(@PathVariable("id") String id) {
    UcenterMember member = memberService.getById(id);
    UcenterMemberOrder memberOrder = new UcenterMemberOrder();
    BeanUtils.copyProperties(member, memberOrder);
    return memberOrder;
}

2.3 根据课程id和用户id生成订单

controller层:


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

    @Autowired
    private OrderService orderService;

    
    @PostMapping("createOrder/{courseId}")
    public R saveOrder(@PathVariable("courseId") String courseId, HttpServletRequest request) {
        //通过JWT工具类获取用户id
        //创建订单,返回订单号
        String orderNo = orderService.createOrderById(courseId, JwtUtils.getMemberIdByJwtToken(request));
        return R.ok().data("orderId", orderNo);
    }
}

service层:



@Override
public String createOrderById(String courseId, String userId) {
    //通过远程调佣根据用户id获取用户信息
    UcenterMemberOrder userInfoOrder = ucenterClient.getUserInfoOrder(userId);
    //通过远程调佣根据课程id获取课程信息
    CourseWebOrder courseInfoOrder = courseClient.getCourseInfoOrder(courseId);
    Order order = new Order();
    //订单号
    order.setOrderNo(OrderNoUtil.getOrderNo());
    order.setCourseId(courseId);
    order.setCourseTitle(courseInfoOrder.getTitle());
    order.setCourseCover(courseInfoOrder.getCover());

    order.setTeacherName(courseInfoOrder.getTeacherName());
    order.setTotalFee(courseInfoOrder.getPrice());
    order.setMemberId(userId);
    order.setMobile(userInfoOrder.getMobile());
    order.setNickname(userInfoOrder.getNickname());
    //支付状态  未支付:0  已支付:1
    order.setStatus(0);
    //支付类型  微信:1    支付宝:2
    order.setPayType(1);
    //保存到数据库
    baseMapper.insert(order);
    //返回订单号
    return order.getOrderNo();
}

3.查询订单信息

3.1 controller层

在OrderController里创建getOrderInfo用于生成订单:



@GetMapping("getOrderInfo/{orderId}")
public R getOrderInfo(@PathVariable("orderId") String orderId) {
    Order order=orderService.getOrderByOrderId(orderId);
    return R.ok().data("item", order);
}

3.2 service层



@Override
public Order getOrderByOrderId(String orderId) {
    LambdaQueryWrapper<Order> queryWrapper = new LambdaQueryWrapper<>();
    queryWrapper.eq(Order::getOrderNo, orderId);
    return baseMapper.selectOne(queryWrapper);
}

4.生成微信支付的二维码

4.1 controller层

在PayLogController里创建createNative用于生成支付二维码:


@CrossOrigin
@RestController
@RequestMapping("/eduorder/paylog")
public class PayLogController {

    @Autowired
    private PayLogService payLogService;

    
    @GetMapping("createNative/{orderNo}")
    public R createNative(@PathVariable("orderNo") String orderNo){
        //返回信息,包含二维码地址,还有其他信息
        Map map=payLogService.createNative(orderNo);
        return R.ok().data(map);
    }
}

4.2 service层

  1. 生成微信支付二维码大概分为这几步:
  2. 根据订单号查询订单信息
  3. 使用map设置生成二维码需要的参数
  4. 发送httpclient请求,传递xml格式的参数,传入微信支付提供的固定地址
  5. 得到发送请求返回的结果
  6. 最终返回封装数据


@Override
public Map createNative(String orderNo) {
    try {
        //1.根据订单号查询订单信息
        Order order = orderService.getOrderByOrderId(orderNo);
        //2.使用map设置生成二维码需要的参数
        Map m = new HashMap();
        //关联的公众号appid
        m.put("appid", ConstantWxPayUtils.WX_PAY_APP_ID);
        //商户号
        m.put("mch_id", ConstantWxPayUtils.WX_PAY_PARTNER);
        //随机字符串
        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() + "");
        //支付的ip地址
        m.put("spbill_create_ip", "127.0.0.1");
        m.put("notify_url", ConstantWxPayUtils.WX_PAY_NOTIFY_URL);
        m.put("trade_type", "NATIVE");

        //3.发送httpclient请求,传递参数xml格式,传入微信支付提供的固定地址
        HttpClient client = new HttpClient(ConstantWxPayUtils.WX_PAY_WX_URL);
        //设置xml格式的参数,需要传入二维码参数m和商户key
        client.setXmlParam(WXPayUtil.generateSignedXml(m, ConstantWxPayUtils.WX_PAY_PARTNER_KEY));
        //默认不支持https,设置为true支持
        client.setHttps(true);
        //执行请求发送
        client.post();
        //4.得到发送请求返回的结果
        //返回的内容是xml格式
        String xml = client.getContent();
        //把xml格式转换为map集合
        Map<String, String> resultMap = WXPayUtil.xmlToMap(xml);

        //5.最终返回封装数据
        Map map = new HashMap();
        //订单号
        map.put("out_trade_no", orderNo);
        //课程id
        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"));
        return map;
    } catch (Exception e) {
        throw new GuliException(20001, "生成微信支付二维码失败");
    }
}

5.查询订单支付状态

5.1 controller层

在PayLogController里创建queryPayStatus用于获取支付状态:



@GetMapping("queryPayStatus/{orderNo}")
public R queryPayStatus(@PathVariable("orderNo") String orderNo){
    Map<String, String> map=payLogService.queryPayStatus(orderNo);
    if(map==null){
        return R.error().message("支付出错!");
    }
    //如果map不为空,通过map获取订单状态
    if(map.get("trade_state").equals("SUCCESS")){
        //添加记录到支付表,更新订单表订单状态
        payLogService.updateOrdersStatus(map);
        return R.ok().message("支付成功!");
    }
    return R.ok().code(25000).message("正在支付中...");
}

5.2 service层

根据订单号查询订单支付状态大概分为一下几步:

  1. 封装参数
  2. 发送httpclient
  3. 得到请求返回的内容


@Override
public Map<String, String> queryPayStatus(String orderNo) {
    try {
        //1.封装参数
        Map m=new HashMap();
        //关联的公众号appid
        m.put("appid",ConstantWxPayUtils.WX_PAY_APP_ID);
        //商户号
        m.put("mch_id",ConstantWxPayUtils.WX_PAY_PARTNER);
        //订单号
        m.put("out_trade_no",orderNo);
        //随机字符串
        m.put("nonce_str",WXPayUtil.generateNonceStr());
        //2.发送httpclient
        HttpClient client = new HttpClient(ConstantWxPayUtils.WX_PAY_QUERY_URL);
        client.setXmlParam(WXPayUtil.generateSignedXml(m,ConstantWxPayUtils.WX_PAY_PARTNER_KEY));
        client.setHttps(true);
        client.post();
        //3.得到请求返回的内容
        String xml = client.getContent();
        Map<String, String> resultMap=WXPayUtil.xmlToMap(xml);
        return resultMap;
    } catch (Exception e) {
        e.printStackTrace();
        throw  new GuliException(20001,"查询订单支付状态失败");
    }
}

如果支付成功,需要添加记录到支付表,更新订单表订单状态:



@Override
public void updateOrdersStatus(Map<String, String> map) {
    //从map获取订单号
    String orderNo = map.get("out_trade_no");
    Order order = orderService.getOrderByOrderId(orderNo);
    //更新订单表t_order的订单状态status
    if(order.getStatus().intValue()==1){
        return;
    }
    order.setStatus(1);
    orderService.updateById(order);

    //向支付表 t_pag_log 添加记录
    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"));
    //其他属性,转为json字符串
    payLog.setAttr(JSONObject.toJSONString(map));
    baseMapper.insert(payLog);
} 

以上就是SpringBoot实现整合微信支付方法详解的详细内容,更多关于SpringBoot整合微信支付的资料请关注编程网其它相关文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

SpringBoot实现整合微信支付方法详解

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

SpringBoot如何实现整合微信支付

这篇文章将为大家详细讲解有关SpringBoot如何实现整合微信支付,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。1.准备工作1.1 数据库表这里涉及微信支付一共两个表:订单表支付记录表1.2 实体类数据
2023-06-22

Android 支付宝支付、微信支付、银联支付 整合第三方支付接入方法(后台订单支付API设计)

客户端获取后台支付API请求参数的设计参数样例:{ data: { method: 1, platform: 1, version:"1.0", relate_orders:"B201602031023,B2016020310231", o
2022-06-06

微信小程序接入微信支付实现过程详解

这篇文章主要介绍了微信小程序接入微信支付实现过程,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习吧
2022-12-26

Java 实现微信支付详细教程

摘要:最近的一个项目中涉及到了支付业务,其中用到了微信支付和支付宝支付,在做的过程中也遇到些问题,所以现在总结梳理一下,分享给有需要的人,也为自己以后回顾留个思路。 一、微信支付接入准备工作: 首先,微信支付,只支持企业用户,个人用户是不能
2023-08-19

SpringBoot整合Quartz方法详解

这篇文章详解介绍了SpringBoot整合Quartz的方法,Quartz是一个比较成熟了的定时任务框架,本文实例代码给大家详细讲解,需要的朋友可以参考下
2023-05-17

SpringBoot整合Canal方法详解

这篇文章主要介绍了SpringBoot整合Canal,canal可以用来监控数据库数据的变化,从而获得新增数据,或者修改的数据,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习吧
2022-12-21

Java Springboot整合支付宝接口的方法是什么

本篇内容主要讲解“Java Springboot整合支付宝接口的方法是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java Springboot整合支付宝接口的方法是什么”吧!一、创建支付
2023-07-05

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录