Springboot封装微信扫码支付(附完整源码)

流程分析--逆向思维

我们最终需要能够实现的目的 -->引入依赖,yaml中做好配置,直接依赖注入xxxTemplate能够直接使用

--->需要创建一个xxxTemplate对象---> 提供一个xxxTemplate类,封装扫码支付的api,一些环境级别的参数做成配置

--> 提供xxxProperties配置类,然后加载yaml中的配置

最终实现步骤整理

0.创建工程,引入相关依赖

  1. 提供WxPayProperties配置类,用于加载application.yaml中的环境配置

  2. 提供WxPayTemplate类,封装扫码支付的api,环境配置依赖注入得到

  3. 提供配置类,启动WxPayProperties类对象,创建WxPayTemplate对象

  4. 提供META-INF/spring.factory配置类,配置自动化配置

  5. 创建新测试工程,测试starter使用

代码实现

0.创建工程,引入相关依赖

<dependencies>
        <dependency>
            <groupId>com.github.wechatpay-apiv3</groupId>
            <artifactId>wechatpay-apache-httpclient</artifactId>
            <version>0.4.9</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.83</version>
        </dependency>
    </dependencies>

  1. 提供WxPayProperties配置类,用于加载application.yaml中的环境配置


​
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
​
@Data
@ConfigurationProperties(prefix = "wxpay")
public class WxPayProperties {
​
    private String mchId = "1561414331"; //商户号
    private String appId = "wxffb3637a228223b8"; //应用号
    private String privateKey = "-----BEGIN PRIVATE KEY-----\n" +
            "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDBHGgIh80193Gh\n" +
            "dpD1LtMZfTRpcWI0fImyuBCyrd3gYb3rrsARebGcHdJsQA3mVjVqVp5ybhEZDPa4\n" +
            "ecoK4Ye1hTppNpI/lmLt4/uUV/zhF5ahli7hi+116Ty6svHSbuMQBuUZeTFOwGrx\n" +
            "jvofU/4pGIwh8ZvkcSnyOp9uX2177UVxDBkhgbZbJp9XF2b83vUa5eHo93CziPzn\n" +
            "3hFdAlBCdTXB7DH+m0nN3Jou0szGukvq7cIgGpHku4ycKSTkIhhl9WRhN6OoSEJx\n" +
            "q88MXzjkzTruc85PHN52aUTUifwg3T8Y4XqFQ61dTnEmgxeD2O6/pLdB9gLsp6yC\n" +
            "GqN5Lqk7AgMBAAECggEBAL4X+WzUSbSjFS9NKNrCMjm4H1zgqTxjj6TnPkC1mGEl\n" +
            "tjAHwLgzJBw62wWGdGhWWpSIGccpBBm1wjTMZpAZfF66fEpP1t1Ta6UjtGZNyvfF\n" +
            "IZmE3jdWZ/WXGBnsxtFQKKKBNwrBW0Fbdqq9BQjLxLitmlxbmwrgPttcy855j6vZ\n" +
            "qq4MBT1v8CtUT/gz4UWW2xWovVnmWOrRSScv7Nh0pMbRpPLkNHXrBwSSNz/keORz\n" +
            "XB9JSm85wlkafa7n5/IJbdTml3A/uAgW3q3JZZQotHxQsYvD4Zb5Cnc9CPAXE5L2\n" +
            "Yk877kVXZMGt5QPIVcPMj/72AMtaJT67Y0fN0RYHEGkCgYEA38BIGDY6pePgPbxB\n" +
            "7N/l6Df0/OKPP0u8mqR4Q0aQD3VxeGiZUN1uWXEFKsKwlOxLfIFIFk1/6zQeC0xe\n" +
            "tNTKk0gTL8hpMUTNkE7vI9gFWws2LY6DE86Lm0bdFEIwh6d7Fr7zZtyQKPzMsesC\n" +
            "3XV9sdSUExEi5o/VwAyf+xZlOXcCgYEA3PGZYlILjg3esPNkhDz2wxFw432i8l/B\n" +
            "CPD8ZtqIV9eguu4fVtFYcUVfawBb0T11RamJkc4eiSOqayC+2ehgb+GyRLJNK4Fq\n" +
            "bFcsIT+CK0HlscZw51jrMR0MxTc4RzuOIMoYDeZqeGB6/YnNyG4pw2sD8bIwHm84\n" +
            "06gtJsX/v10CgYAo8g3/aEUZQHcztPS3fU2cTkkl0ev24Ew2XGypmwsX2R0XtMSB\n" +
            "uNPNyFHyvkgEKK2zrhDcC/ihuRraZHJcUyhzBViFgP5HBtk7VEaM36YzP/z9Hzw7\n" +
            "bqu7kZ85atdoq6xpwC3Yn/o9le17jY8rqamD1mv2hUdGvAGYsHbCQxnpBwKBgHTk\n" +
            "eaMUBzr7yZLS4p435tHje1dQVBJpaKaDYPZFrhbTZR0g+IGlNmaPLmFdCjbUjiPy\n" +
            "A2+Znnwt227cHz0IfWUUAo3ny3419QkmwZlBkWuzbIO2mms7lwsf9G6uvV6qepKM\n" +
            "eVd5TWEsokVbT/03k27pQmfwPxcK/wS0GFdIL/udAoGAOYdDqY5/aadWCyhzTGI6\n" +
            "qXPLvC+fsJBPhK2RXyc+jYV0KmrEv4ewxlK5NksuFsNkyB7wlI1oMCa/xB3T/2vT\n" +
            "BALgGFPi8BJqceUjtnTYtI4R2JIVEl08RtEJwyU5JZ2rvWcilsotVZYwfuLZ9Kfd\n" +
            "hkTrgNxlp/KKkr+UuKce4Vs=\n" +
            "-----END PRIVATE KEY-----\n"; //私钥字符串
    private String mchSerialNo = "25FBDE3EFD31B03A4377EB9A4A47C517969E6620"; //商户证书序列号
    private String apiV3Key = "CZBK51236435wxpay435434323FFDuv3"; //V3密钥
​
}

  1. 提供WxPayTemplate类,封装扫码支付的api,环境配置依赖注入得到

2个参数实体类:


​
import lombok.Builder;
import lombok.Data;
​
@Builder
@Data
public class NativePayParams {
​
    private String appid; // 应用id
    private String mchid;  // 商户id
    private String description; //商品描述
    private String out_trade_no; //订单号
    private String notify_url; // 支付成功回调通知地址
    private Amount amount; //订单金额信息
}


​
import lombok.Builder;
import lombok.Data;
​
@Builder
@Data
public class Amount {
    private Integer total;
    private String currency;
}

工具类: ​

import com.alibaba.fastjson.JSON;
import com.heima.wxpay.dto.Amount;
import com.heima.wxpay.dto.NativePayParams;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
​
import java.io.IOException;
import java.util.Map;
​
public class WxPayTemplate {
​
    private WxPayProperties wxPayProperties;
​
    private CloseableHttpClient httpClient;
​
    public WxPayTemplate(WxPayProperties wxPayProperties,CloseableHttpClient httpClient) {
        this.wxPayProperties = wxPayProperties;
        this.httpClient = httpClient;
    }
​
    public String nativePay(Integer total, String description, String outTradeNo) throws Exception{
        HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/native");
        // 请求body参数
​
        Amount amount = Amount.builder().currency("CNY").total(total).build();
​
        NativePayParams nativePayParams = NativePayParams.builder().appid(wxPayProperties.getAppId())
                .description(description)
                .mchid(wxPayProperties.getMchId())
                .notify_url("https://36d5634033.vicp.fun/native/notify")
                .out_trade_no(outTradeNo)
                .amount(amount)
                .build();
​
​
        String reqdata = JSON.toJSONString(nativePayParams);
        StringEntity entity = new StringEntity(reqdata,"utf-8");
        entity.setContentType("application/json");
        httpPost.setEntity(entity);
        httpPost.setHeader("Accept", "application/json");
​
        //完成签名并执行请求
        CloseableHttpResponse response = httpClient.execute(httpPost);
​
        String url = "";
        try {
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode == 200) { //处理成功
                System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));
                url = JSON.parseObject( EntityUtils.toString(response.getEntity()), Map.class).get("code_url").toString();
            } else if (statusCode == 204) { //处理成功,无返回Body
                System.out.println("success");
            } else {
                System.out.println("failed,resp code = " + statusCode+ ",return body = " + EntityUtils.toString(response.getEntity()));
                throw new IOException("request failed");
            }
        } finally {
            response.close();
        }
        return url;
    }
}

  1. 提供配置类,启动WxPayProperties类对象,创建WxPayTemplate对象 ​

import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
import com.wechat.pay.contrib.apache.httpclient.auth.AutoUpdateCertificatesVerifier;
import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import org.apache.http.impl.client.CloseableHttpClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
​
import java.io.ByteArrayInputStream;
import java.security.PrivateKey;
​
@Configuration
@EnableConfigurationProperties(WxPayProperties.class)
public class WxPayAutoConfig {
​
​
    @Bean
    public CloseableHttpClient httpClient(WxPayProperties wxPayProperties) throws Exception{
        // 加载商户私钥(privateKey:私钥字符串)
        PrivateKey merchantPrivateKey = PemUtil
                .loadPrivateKey(new ByteArrayInputStream(wxPayProperties.getPrivateKey().getBytes("utf-8")));
​
        // 加载平台证书(mchId:商户号,mchSerialNo:商户证书序列号,apiV3Key:V3密钥)
        AutoUpdateCertificatesVerifier verifier = new AutoUpdateCertificatesVerifier(
                new WechatPay2Credentials(wxPayProperties.getMchId(), new PrivateKeySigner(wxPayProperties.getMchSerialNo(), merchantPrivateKey)),wxPayProperties.getApiV3Key().getBytes("utf-8"));
​
        // 初始化httpClient
        return WechatPayHttpClientBuilder.create()
                .withMerchant(wxPayProperties.getMchId(), wxPayProperties.getMchSerialNo(), merchantPrivateKey)
                .withValidator(new WechatPay2Validator(verifier)).build();
    }
​
    @Bean
    public WxPayTemplate wxPayTemplate(WxPayProperties wxPayProperties,CloseableHttpClient httpClient){
​
        return new WxPayTemplate(wxPayProperties,httpClient);
    }
​
}
  1. 提供META-INF/spring.factory配置类,配置自动化配置

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.heima.wxpay.config.WxPayAutoConfig
  1. 创建新测试工程,测试starter使用

导入starter依赖:

<dependency>
    <groupId>com.heima</groupId>
    <artifactId>wx_pay_starter</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>

直接springBoot测试

import com.heima.wxpay.config.WxPayTemplate;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class StarterTest {

    @Autowired
    private WxPayTemplate wxPayTemplate;

    @Test
    public void testNativePay() throws Exception{

        String url = wxPayTemplate.nativePay(1, "javaEE企业级开发", "ADFADSFS4353534");
        System.out.println(url);
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值