SpringBoot整合微信小程序支付功能,V3版本

官方文档要是写成这样会省我很多事,好多坑

1.准备工作

1.1 开通小程序支付功能
登录微信公众平台,开通
在这里插入图片描述
个人无法申请,需要企业身份

1.2. 准备好法人身份证,营业执照,如果不是法人,公司盖章授权,授权你开发,公司的对公账户

1.3 进入微信支付平台申请API秘钥

https://pay.weixin.qq.com/

在这里插入图片描述
在这里插入图片描述
1.4.随机生成秘钥32位
直接搜在线生成器
在这里插入图片描述
1.5域名映射工具
我用的花生壳,回调的时候解密失败,用自己的域名可以解密,已经踩坑,你们换个试试

2.新建一个SpringBoot项目

导入依赖

     <dependency>
            <groupId>com.fasterxml.jackson.dataformat</groupId>
            <artifactId>jackson-dataformat-avro</artifactId>
        </dependency>

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </dependency>

官方开发文档
https://pay.weixin.qq.com/doc/v3/partner/4012085802

在这里插入图片描述

3.微信支付地址



/**
 * 微信支付地址
 *
 * @Author: albc
 * @Date: 2024/12/20/15:54
 * @Description: good good study,day day up
 */
public class WechatUrlConfig {


    /**
     * 小程序jsapi下单地址
     */
    public static final String JSAPI_ORDER = "https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi";


    /**
     * 小程序查询订单接口,根据微信订单号查询支付状态,这个订单号是微信支付成功后返回的订单号
     */
    public static final String JSAPI_QUERY_WX_ID = "https://api.mch.weixin.qq.com/v3/pay/transactions/id/%s?mchid=%s";


    /**
     * 小程序查询订单状态接口,这个订单号是自己生成的订单号
     */
    public static final String JSAPI_QUERY_OEDER_ID = "https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/%s?mchid=%s";


    /**
     * 小程序申请退款接口
     */
    public static final String JSAPI_REFUND_ORDER = "https://api.mch.weixin.qq.com/v3/refund/domestic/refunds";


    /**
     * 小程序退款状态查询接口
     */
    public static final String JSAPI_REFUND_QUERY = "https://api.mch.weixin.qq.com/v3/refund/domestic/refunds/%s";


    /**
     * 小程序关闭订单接口
     */
    public static final String JSAPI_CLOSE_ORDER = "https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/%s/close";



    /**
     * 获取证书
     */
    public static final String CERTIFICATESURL = "https://api.mch.weixin.qq.com/v3/certificates";


}

4.微信支付配置参数类

import lombok.Data;
import org.springframework.stereotype.Component;

/**
 * 微信支付配置参数
 *
 * @Author: albc
 * @Date: 2024/12/20/15:43
 * @Description: good good study,day day up
 */
@Data
@Component
public class WxpayConfig {


    /**
     * 小程序appid
     */
    public static String appId = "wx123456789";


    /**
     * 商户号
     */
    public static String mchId = "123456789";


    /**
     * 证书秘钥
     */
    public static String mchSerialNo = "12521FAS9A57A51234567897B1ABCDE545A6A1B3";


    /**
     * v3秘钥
     */
    public static String v3Key = "TuaoTWtonjHSbEEuDOPYWcPASvQUrUmH";


    /**
     * 商户私钥路径
     */
    public static String privateKeyPath = "classpath:/date/apiclient_key.pem";


    /**
     * 商户公钥路径
     */
    public static String publicKeyPath = "classpath:/date/pub_key.pem";


    /**
     * 支付成功回调
     */
    public static String notifyOrderUrl = "https://4lakfa12312312.vicp.fun.com/pay/api/v1/pay/wxPayCallback";


    /**
     * 退款成功后回调地址
     */
    public static String notifyRefoundUrl = "https://4lakfa12312312.vicp.fun/pay/api/v1/pay/wxRefoundCallback";

}

5.将公钥私钥放在recources目录下

在这里插入图片描述

6.新建解密工具类


import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;


/**
 * 解密工具类,回调时候解密
 * @Author: albc
 * @Date: 2024/12/20/16:00
 * @Description: good good study,day day up
 */
public class AesUtil {

    static final int KEY_LENGTH_BYTE = 32;
    static final int TAG_LENGTH_BIT = 128;
    private final byte[] aesKey;

    public AesUtil(byte[] key) {
        if (key.length != KEY_LENGTH_BYTE) {
            throw new IllegalArgumentException("无效的ApiV3Key,长度必须为32个字节");
        }
        this.aesKey = key;
    }

    public String decryptToString(byte[] associatedData, byte[] nonce, String ciphertext)
            throws GeneralSecurityException, IOException {
        try {
            Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");

            SecretKeySpec key = new SecretKeySpec(aesKey, "AES");
            GCMParameterSpec spec = new GCMParameterSpec(TAG_LENGTH_BIT, nonce);

            cipher.init(Cipher.DECRYPT_MODE, key, spec);
            cipher.updateAAD(associatedData);

            return new String(cipher.doFinal(Base64.getDecoder().decode(ciphertext)), "utf-8");
        } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
            throw new IllegalStateException(e);
        } catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
            throw new IllegalArgumentException(e);
        }
    }
}

7.新建签名工具类


import com.fasterxml.jackson.databind.JsonNode;
import org.springframework.core.io.ClassPathResource;

import java.io.*;
import java.net.URL;
import java.security.*;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * 签名工具类
 *
 * @Author: albc
 * @Date: 2024/12/20/16:00
 * @Description: good good study,day day up
 */
public class WechatPayUtils {


    private static final String SIGNATURE_ALGORITHM = "SHA256withRSA";

    private static final String KEY_ALGORITHM = "RSA";


    /**
     * 获取私钥
     *
     * @param filename 私钥文件路径
     * @return 私钥对象
     */
    public static PrivateKey getPrivateKey(String filename) throws IOException {
        InputStream inputStream = new ClassPathResource(filename
                .replace("classpath:", "")).getInputStream();
        String content = new BufferedReader(new InputStreamReader(inputStream))
                .lines().collect(Collectors.joining(System.lineSeparator()));
        try {
            String privateKey = content.replace("-----BEGIN PRIVATE KEY-----", "")
                    .replace("-----END PRIVATE KEY-----", "")
                    .replaceAll("\\s+", "");

            KeyFactory kf = KeyFactory.getInstance("RSA");
            return kf.generatePrivate(new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey)));
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("当前Java环境不支持RSA", e);
        } catch (InvalidKeySpecException e) {
            throw new RuntimeException("无效的密钥格式");
        }
    }


    /**
     * 获取公钥
     *
     * @param filename
     * @return
     */
    public static String getPublicKey(String filename) throws IOException {
        InputStream inputStream = new ClassPathResource(filename
                .replace("classpath:", "")).getInputStream();
        String content = new BufferedReader(new InputStreamReader(inputStream))
                .lines().collect(Collectors.joining(System.lineSeparator()));
        String publicKey = content.replace("-----BEGIN PUBLIC KEY-----", "")
                .replace("-----END PUBLIC KEY-----", "")
                .replaceAll("\\s+", "");
        return publicKey;
    }


    /**
     * 生成token 也就是生成签名
     *
     * @param method
     * @param url
     * @param body
     * @return
     * @throws Exception
     */
    public static String getToken(String method, URL url, String body) throws Exception {
        String nonceStr = getNonceStr();
        long timestamp = System.currentTimeMillis() / 1000;
        String message = buildMessage(method, url, timestamp, nonceStr, body);
        String signature = sign(message.getBytes("utf-8"));

        return "WECHATPAY2-SHA256-RSA2048 " + "mchid=\"" + WxpayConfig.mchId + "\","
                + "nonce_str=\"" + nonceStr + "\","
                + "timestamp=\"" + timestamp + "\","
                + "serial_no=\"" + WxpayConfig.mchSerialNo + "\","
                + "signature=\"" + signature + "\"";
    }


    /**
     * 获取平台证书
     *
     * @return
     */
    public static Map<String, X509Certificate> refreshCertificate() throws Exception {
        Map<String, X509Certificate> certificateMap = new HashMap();
        // 1: 执行get请求
        JsonNode jsonNode = WxHttpUtils.doGet(WechatUrlConfig.CERTIFICATESURL);
        // 2: 获取平台验证的相关参数信息
        JsonNode data = jsonNode.get("data");
        if (data != null) {
            for (int i = 0; i < data.size(); i++) {
                JsonNode encrypt_certificate = data.get(i).get("encrypt_certificate");
                //对关键信息进行解密
                AesUtil aesUtil = new AesUtil(WxpayConfig.v3Key.getBytes());
                String associated_data = encrypt_certificate.get("associated_data").toString().replaceAll("\"", "");
                String nonce = encrypt_certificate.get("nonce").toString().replaceAll("\"", "");
                String ciphertext = encrypt_certificate.get("ciphertext").toString().replaceAll("\"", "");
                //证书内容
                String certStr = aesUtil.decryptToString(associated_data.getBytes(), nonce.getBytes(), ciphertext);
                //证书内容转成证书对象
                CertificateFactory cf = CertificateFactory.getInstance("X509");
                X509Certificate x509Cert = (X509Certificate) cf.generateCertificate(
                        new ByteArrayInputStream(certStr.getBytes("utf-8"))
                );
                String serial_no = data.get(i).get("serial_no").toString().replaceAll("\"", "");
                certificateMap.put(serial_no, x509Cert);
            }
        }
        return certificateMap;
    }


    /**
     * 生成签名
     *
     * @param message
     * @return
     * @throws Exception
     */
    public static String sign(byte[] message) throws Exception {
        Signature sign = Signature.getInstance("SHA256withRSA");
        sign.initSign(getPrivateKey(WxpayConfig.privateKeyPath));
        sign.update(message);
        return Base64.getEncoder().encodeToString(sign.sign());
    }


    /**
     * 验签方法
     *
     * @param data      验签数据
     * @param publicKey 公钥
     * @param sign      签名
     * @return
     * @throws Exception
     */
    public static boolean verifyByPublicKey(byte[] data, String publicKey, String sign) throws Exception {
        byte[] keyBytes = decryptBASE64(publicKey);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        PublicKey pubKey = keyFactory.generatePublic(keySpec);
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initVerify(pubKey);
        signature.update(data);
        return signature.verify(decryptBASE64(sign)); // 验证签名
    }


    public static byte[] decryptBASE64(String data) {
        return org.apache.commons.codec.binary.Base64.decodeBase64(data);
    }

    /**
     * 生成签名串
     *
     * @param method
     * @param url
     * @param timestamp
     * @param nonceStr
     * @param body
     * @return
     */
    public static String buildMessage(String method, URL url, long timestamp, String nonceStr, String body) {
        String canonicalUrl = url.getPath();
        if (url.getQuery() != null) {
            canonicalUrl += "?" + url.getQuery();
        }
        return method + "\n"
                + canonicalUrl + "\n"
                + timestamp + "\n"
                + nonceStr + "\n"
                + body + "\n";
    }


    /**
     * 生成随机数
     *
     * @return
     */
    public static String getNonceStr() {
        return UUID.randomUUID().toString()
                .replaceAll("-", "")
                .substring(0, 32);
    }


    /**
     * 拼接参数
     *
     * @return
     */

    public static String buildMessageTwo(String appId, long timestamp, String nonceStr, String packag) {
        return appId + "\n"
                + timestamp + "\n"
                + nonceStr + "\n"
                + packag + "\n";
    }

}

8.下单工具类

import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SignatureException;
import java.util.HashMap;
import java.util.UUID;

/**
 * 下单工具类
 *
 * @Author: albc
 * @Date: 2024/12/20/16:15
 * @Description: good good study,day day up
 */
public class WeixinchatPayUtils {

    public static String getNonceStr() {
        return UUID.randomUUID().toString()
                .replaceAll("-", "")
                .substring(0, 32);
    }

    /**
     * 参考网站 https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_5_4.shtml
     * 计算签名值
     *
     * @param appId
     * @param prepay_id
     * @return
     * @throws IOException
     * @throws SignatureException
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     */
    public static HashMap<String, Object> getTokenJSAPI(String appId, String prepay_id) throws Exception {
        // 获取随机字符串
        String nonceStr = getNonceStr();
        // 获取微信小程序支付package
        String packagestr = "prepay_id=" + prepay_id;
        long timestamp = System.currentTimeMillis() / 1000;
        //签名,使用字段appId、timeStamp、nonceStr、package计算得出的签名值
        String message = WechatPayUtils.buildMessageTwo(appId, timestamp, nonceStr, packagestr);
        //获取对应的签名
        String signature = WechatPayUtils.sign(message.getBytes("utf-8"));
        // 组装返回
        HashMap<String, Object> map = new HashMap<>();
        map.put("appId", appId);
        map.put("timeStamp", String.valueOf(timestamp));
        map.put("nonceStr", nonceStr);
        map.put("package", packagestr);
        map.put("signType", "RSA");
        map.put("paySign", signature);
        return map;
    }


    /**
     * 参考网站 https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_5_4.shtml
     * 计算签名值
     *
     * @param appId
     * @param prepay_id
     * @return
     * @throws IOException
     * @throws SignatureException
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     */
    public static HashMap<String, Object> getTokenApp(String appId, String prepay_id) throws Exception {
        // 获取随机字符串
        String nonceStr = getNonceStr();
        // 获取微信小程序支付package
        long timestamp = System.currentTimeMillis() / 1000;
        //签名,使用字段appId、timeStamp、nonceStr、package计算得出的签名值
        String message = WechatPayUtils.buildMessageTwo(appId, timestamp, nonceStr, prepay_id);
        //获取对应的签名
        String signature = WechatPayUtils.sign(message.getBytes("utf-8"));
        // 组装返回
        HashMap<String, Object> map = new HashMap<>();
        map.put("appId", appId);
        map.put("partnerid", WxpayConfig.mchId);
        map.put("prepayid", prepay_id);
        map.put("package", "Sign=WXPay");
        map.put("nonceStr", nonceStr);
        map.put("timeStamp", String.valueOf(timestamp));
        map.put("sign", signature);
        return map;
    }
}

9.微信支付请求工具类


import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

import java.net.URL;
import java.util.HashMap;
import java.util.Map;

/**
 * 微信支付请求工具类
 *
 * @Author: albc
 * @Date: 2024/12/20/15:58
 * @Description: good good study,day day up
 */
@Slf4j
public class WxHttpUtils {


    private static final ObjectMapper JSON = new ObjectMapper();

    /**
     * 封装get请求
     *
     * @param url
     * @return
     */
    public static JsonNode doGet(String url) {

        CloseableHttpClient httpClient = HttpClientBuilder.create().build();
        HttpGet httpget = new HttpGet(url);
        httpget.addHeader("Content-Type", "application/json;charset=UTF-8");
        httpget.addHeader("Accept", "application/json");
        try {
            String token = WechatPayUtils.getToken("GET", new URL(url), "");
            httpget.addHeader("Authorization", token);
            CloseableHttpResponse httpResponse = httpClient.execute(httpget);
            if (httpResponse.getStatusLine().getStatusCode() == 200) {

                String jsonResult = EntityUtils.toString(httpResponse.getEntity());
                return JSON.readTree(jsonResult);
            } else {
                log.error("请求错误:" + EntityUtils.toString(httpResponse.getEntity()));
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                httpClient.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return null;
    }


    /**
     * 封装post请求
     *
     * @return
     */
    public static Map<String, Object> doPostWexin(String url, String body) {
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpPost httpPost = new HttpPost(url);
        httpPost.addHeader("Content-Type", "application/json;chartset=utf-8");
        httpPost.addHeader("Accept", "application/json");
        try {
            String token = WechatPayUtils.getToken("POST", new URL(url), body);
            httpPost.addHeader("Authorization", token);

            if (body == null) {
                throw new IllegalArgumentException("data参数不能为空");
            }
            StringEntity stringEntity = new StringEntity(body, "utf-8");
            httpPost.setEntity(stringEntity);

            CloseableHttpResponse httpResponse = httpClient.execute(httpPost);
            HttpEntity httpEntity = httpResponse.getEntity();

            if (httpResponse.getStatusLine().getStatusCode() == 200) {
                String jsonResult = EntityUtils.toString(httpEntity);
                return JSON.readValue(jsonResult, HashMap.class);
            } else {
                log.error("微信支付错误信息:" + EntityUtils.toString(httpEntity));
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                httpClient.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return null;
    }


    /**
     * 关闭订单
     *
     * @param url
     * @param body
     */
    public static void doPostCloseOrder(String url, String body) {
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpPost httpPost = new HttpPost(url);
        httpPost.addHeader("Content-Type", "application/json;chartset=utf-8");
        httpPost.addHeader("Accept", "application/json");
        try {
            String token = WechatPayUtils.getToken("POST", new URL(url), body);
            httpPost.addHeader("Authorization", token);
            if (body == null) {
                throw new IllegalArgumentException("data参数不能为空");
            }
            StringEntity stringEntity = new StringEntity(body, "utf-8");
            httpPost.setEntity(stringEntity);
            CloseableHttpResponse httpResponse = httpClient.execute(httpPost);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                httpClient.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }


}

10.退款回调

    /**
     * 微信退款回调
     *
     * @param body
     * @param request
     * @return
     */
    @PostMapping("/wxRefoundCallback")
    public Map wxRefoundCallback(@RequestBody Map body, HttpServletRequest request) {
        log.info("wxRefoundCallback回调方法进入>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
        log.info("wxRefoundCallback.body获取到值:" + body);
        Map<String, Object> result = new HashMap();
        //应答的时间戳
        String timestamp = request.getHeader("Wechatpay-Timestamp");
        //应答的随机串
        String nonce = request.getHeader("Wechatpay-Nonce");
        ObjectMapper objectMapper = new ObjectMapper();
        try {
            //开始解析报文体
            String data = objectMapper.writeValueAsString(body);
            String message = timestamp + "\n" + nonce + "\n" + data + "\n";
            //获取应答签名
            String sign = request.getHeader("Wechatpay-Signature");
            log.info("wxRefoundCallback.验签开始............................................................");
            String publicKey = WechatPayUtils.getPublicKey(WxpayConfig.publicKeyPath);
            log.info("wxRefoundCallback.获取到公钥:" + publicKey);
            boolean b = WechatPayUtils.verifyByPublicKey(message.getBytes(), publicKey, sign);
            log.info("wxRefoundCallback.验签结束....................................................................");
            log.info("wxRefoundCallback.验签结果:" + b);
            Map<String, String> resource = (Map) body.get("resource");
            log.info("wxRefoundCallback.resource中map值:" + resource);
            //回调报文解密
            AesUtil aesUtil = new AesUtil(WxpayConfig.v3Key.getBytes());
            //解密后json字符串
            String decryptToString = aesUtil.decryptToString(
                    resource.get("associated_data").getBytes(),
                    resource.get("nonce").getBytes(),
                    resource.get("ciphertext"));
            //微信退款返回的信息
            Map<String, Object> jsonData = objectMapper.readValue(decryptToString, Map.class);
            log.info("成功之前jsonData:" + jsonData);
            //退款成功
            if ("SUCCESS".equals(jsonData.get("refund_status"))) {
                log.info("进入到成功方法>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
                //退款单号
                String outRefundNo = jsonData.get("out_refund_no").toString();
                //微信退款单号
                String refundId = jsonData.get("refund_id").toString();
                log.info("退款单号:{}", outRefundNo);
                log.info("微信退款单号:{}", refundId);
            }
            result.put("code", "SUCCESS");
            result.put("message", "成功");
        } catch (Exception e) {
            result.put("code", "fail");
            result.put("message", "系统错误");
            e.printStackTrace();
        }
        return result;
    }

在这里插入图片描述
在这里插入图片描述

11.支付回调

/**
     * 支付回调
     *
     * @param body    应答的报文主体
     * @param request 应答数据
     * @return
     */
    @PostMapping("/wxPayCallback")
    public Map wxPayCallback(@RequestBody Map body, HttpServletRequest request) {
        log.info("wxPayCallback回调方法进入>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
        log.info("body获取到值:" + body);
        Map<String, Object> result = new HashMap();
        //应答的时间戳
        String timestamp = request.getHeader("Wechatpay-Timestamp");
        //应答的随机串
        String nonce = request.getHeader("Wechatpay-Nonce");
        ObjectMapper objectMapper = new ObjectMapper();
        try {
            //开始解析报文体
            String data = objectMapper.writeValueAsString(body);
            String message = timestamp + "\n" + nonce + "\n" + data + "\n";
            //获取应答签名
            String sign = request.getHeader("Wechatpay-Signature");
            log.info("验签开始............................................................");
            String publicKey = WechatPayUtils.getPublicKey(WxpayConfig.publicKeyPath);
            log.info("获取到公钥:" + publicKey);
            boolean b = WechatPayUtils.verifyByPublicKey(message.getBytes(), publicKey, sign);
            log.info("验签结束....................................................................");
            log.info("验签结果:" + b);
            Map<String, String> resource = (Map) body.get("resource");
            log.info("resource中map值:" + resource);
            //回调报文解密
            AesUtil aesUtil = new AesUtil(WxpayConfig.v3Key.getBytes());
            //解密后json字符串
            String decryptToString = aesUtil.decryptToString(
                    resource.get("associated_data").getBytes(),
                    resource.get("nonce").getBytes(),
                    resource.get("ciphertext"));
            //微信支付返回的信息
            Map<String, Object> jsonData = objectMapper.readValue(decryptToString, Map.class);
            log.info("成功之前jsonData:" + jsonData);
            //支付成功
            if ("SUCCESS".equals(jsonData.get("trade_state"))) {
                log.info("进入到成功方法>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
                //交易订单号,自己生成的订单号
                String outTradeNo = jsonData.get("out_trade_no").toString();
                //微信订单号
                String transactionId = jsonData.get("transaction_id").toString();
                log.info("商户订单号:{}", outTradeNo);
                log.info("微信订单号:{}", transactionId);
            }
            result.put("code", "SUCCESS");
            result.put("message", "成功");
        } catch (Exception e) {
            result.put("code", "fail");
            result.put("message", "系统错误");
            e.printStackTrace();
        }
        return result;
    }

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

12.下单支付

前端拿着这个返回参数,调用小程序支付接口,输入密码支付

 /**
     * 下单,返回给前端支付
     *
     * @param openid
     * @return
     * @throws Exception
     */
    @GetMapping("/wxPay")
    public Map<String, Object> wxPay(String openid) throws Exception {
        Map<String, Object> map = new HashMap();
        // 支付的产品
        map.put("appid", WxpayConfig.appId);
        // 支付的商户号
        map.put("mchid", WxpayConfig.mchId);
        //临时写死配置
        map.put("description", "下单");
        String random = ObjectId.next().toUpperCase();
        map.put("out_trade_no", random);
        map.put("notify_url", WxpayConfig.notifyOrderUrl);
        testService.testInsert(random, new Date());
        Map<String, Object> amount = new HashMap();
        //订单金额 单位分
        amount.put("total", 1);
        amount.put("currency", "CNY");
        map.put("amount", amount);
        // 设置小程序所需的openid
        Map<String, Object> payermap = new HashMap();
        payermap.put("openid", openid);
        map.put("payer", payermap);

        ObjectMapper objectMapper = new ObjectMapper();
        String body = objectMapper.writeValueAsString(map);

        Map<String, Object> stringObjectMap = WxHttpUtils.doPostWexin(WechatUrlConfig.JSAPI_ORDER, body);
        HashMap<String, Object> dataMap = WeixinchatPayUtils.getTokenJSAPI(WxpayConfig.appId, String.valueOf(stringObjectMap.get("prepay_id")));
        return dataMap;
    }

在这里插入图片描述
在这里插入图片描述

13.关闭订单

 /**
     * 关闭订单,没有返回,关闭订单后,可以根据订单号查询状态验证
     *
     * @param orderId
     * @return
     */
    @GetMapping("/wxCloseOrder")
    public Result wxCloseOrder(String orderId) throws JsonProcessingException {
        String url = String.format(WechatUrlConfig.JSAPI_CLOSE_ORDER, orderId);
        Map<String, Object> map = new HashMap<>();
        map.put("mchid", WxpayConfig.mchId);
        ObjectMapper objectMapper = new ObjectMapper();
        String body = objectMapper.writeValueAsString(map);
        WxHttpUtils.doPostCloseOrder(url, body);
        return Result.success();
    }

在这里插入图片描述

14.查询订单状态

    /**
     * 查询订单状态
     *
     * @return
     */
    @GetMapping("/findOrderState")
    public Result findOrderState(String orderId) {
        String url = String.format(WechatUrlConfig.JSAPI_QUERY_OEDER_ID, orderId, WxpayConfig.mchId);
        JsonNode jsonNode = WxHttpUtils.doGet(url);
        return Result.success(jsonNode);
    }

在这里插入图片描述

15.申请退款

 /**
     * 申请退款
     *
     * @return
     */
    @PostMapping("/applyRefund")
    public Result applyRefund(@RequestBody ApplyRefundDto applyRefundDto) throws Exception {
        Map<String, Object> map = new HashMap();
        //当前退款订单号码,随机生成,唯一
        map.put("out_refund_no", applyRefundDto.getOutRefundNo());
        //订单号,用户下单时候订单
        map.put("out_trade_no", applyRefundDto.getOutRefundNo());
        ObjectMapper objectMapper = new ObjectMapper();
        //构建订单信息
        Map<String, Object> amountMap = new HashMap();
        amountMap.put("refund", applyRefundDto.getAmount());
        amountMap.put("total", applyRefundDto.getAmount());
        amountMap.put("currency", "CNY");
        map.put("amount", amountMap);
        map.put("notify_url", WxpayConfig.notifyRefoundUrl);
        String body = objectMapper.writeValueAsString(map);
        Map<String, Object> stringObjectMap = WxHttpUtils.doPostWexin(WechatUrlConfig.JSAPI_REFUND_ORDER, body);
        return Result.success(stringObjectMap);
    }

在这里插入图片描述

16.查询退款状态


    /**
     * 查询退款状态
     *
     * @return
     */
    @GetMapping("/findApplyRefundState")
    public Result findApplyRefundState(String orderId) {
        String url = String.format(WechatUrlConfig.JSAPI_REFUND_QUERY, orderId);
        JsonNode jsonNode = WxHttpUtils.doGet(url);
        return Result.success(jsonNode);
    }

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值