SpringBoot 微信退款功能的示例代码

一:微信支付证书配置

二:证书读取以及读取后的使用

package com.zhx.guides.assistant.config.wechatpay;

import org.apache.commons.io.IOUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.springframework.core.io.ClassPathResource;

import javax.net.ssl.SSLContext;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;

/**
 * @Class WeChatConfigUtil
 * @Version 1.0
 * @Date 创建时间:2020-06-15 16:19
 * @Copyright Copyright by
 * @Direction 类说明
 */
public class WeChatConfigUtil {

  private static byte[] certData;

  /****
   * @throws Exception
   */
  static {
    try {
      //从微信商户平台下载的安全证书存放的目录
      //String certPath = "D:\\config\\apiclient_cert.p12";
      //File file = new File(certPath);
      //InputStream certStream = new FileInputStream(file);
      //使用springboot配置文件内读取的方式
      ClassPathResource classPathResource = new ClassPathResource("\\user_key\\apiclient_cert.p12");
      InputStream certStream = classPathResource.getInputStream();
      WeChatConfigUtil.certData = IOUtils.toByteArray(certStream);
      certStream.read(WeChatConfigUtil.certData);
      certStream.close();
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

  /**
   * 开始退款操作
   *
   * @param mchId 商户ID
   * @param url  请求URL
   * @param data 退款参数
   * @return
   * @throws Exception
   */
  public static String doRefund(String mchId, String url, String data) throws Exception {
    /**
     * 注意PKCS12证书 是从微信商户平台-》账户设置-》 API安全 中下载的
     */
    KeyStore keyStore = KeyStore.getInstance("PKCS12");
    //这里自行实现我是使用数据库配置将证书上传到了服务器可以使用 FileInputStream读取本地文件
    //ByteArrayInputStream inputStream = FileUtil.getInputStream("https://############################.p12");
    ByteArrayInputStream inputStream = new ByteArrayInputStream(WeChatConfigUtil.certData);
    try {
      //这里写密码..默认是你的MCHID
      keyStore.load(inputStream, mchId.toCharArray());
    } finally {
      inputStream.close();
    }
    SSLContext sslcontext = SSLContexts.custom()
        //这里也是写密码的
        .loadKeyMaterial(keyStore, mchId.toCharArray())
        .build();
    SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
        sslcontext,
        SSLConnectionSocketFactory.getDefaultHostnameVerifier());
    CloseableHttpClient httpclient = HttpClients.custom()
        .setSSLSocketFactory(sslsf)
        .build();
    try {
      HttpPost httpost = new HttpPost(url);
      httpost.setEntity(new StringEntity(data, "UTF-8"));
      CloseableHttpResponse response = httpclient.execute(httpost);
      try {
        HttpEntity entity = response.getEntity();
        //接受到返回信息
        String jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8");
        EntityUtils.consume(entity);
        return jsonStr;
      } finally {
        response.close();
      }
    } finally {
      httpclient.close();
    }
  }

}

三:发起订单退款操作

/**
 * 封装查询请求数据
 * @param tradeRefund 	退款订单请求信息
 * @param path				数据访问PATH
 * @return
 */
private static SortedMap<String, Object> refundData( TradeRefund tradeRefund , String path ) throws Exception {
	//构建参数
	Map<String, String> dataMap = new HashMap<>();
	dataMap.put("appid","wx#################");
	dataMap.put("mch_id","137#############");
	//自行实现该随机串
	dataMap.put("nonce_str",Core.MD5("12344"));
	dataMap.put("out_trade_no","P190808170038402889c5318502");
	dataMap.put("out_refund_no","P190808170038402889c5318502");
	dataMap.put("total_fee","1");
	dataMap.put("refund_fee","1");
	dataMap.put("refund_desc","退款");
	//生成签名
	String sign = PayToolUtil.createSign("UTF-8", dataMap , WeichatPayConfigure.API_KEY );
	//WXPayUtil.generateSignature(dataMap, "rv4###################");
	dataMap.put("sign", sign);
	//map数据转xml
	String requestXML = getRequestXml( dataMap );
	logger.info( "订单退款请求参数:\n" + requestXML );
	//发起退款
	String responseXml = WeChatConfigUtil.doRefund( WeichatPayConfigure.MCH_ID , "https://api.mch.weixin.qq.com/secapi/pay/refund", requestXML );
}

/**
 * @author
 * @date 2016-4-22
 * @Description:将请求参数转换为xml格式的string
 * @param parameters
 *      请求参数
 * @return
 */
public static String getRequestXml(SortedMap<Object, Object> parameters) {
	StringBuffer sb = new StringBuffer();
	sb.append("<xml>");
	Set es = parameters.entrySet();
	Iterator it = es.iterator();
	while (it.hasNext()) {
		Map.Entry entry = (Map.Entry) it.next();
		String k = (String) entry.getKey();
		String v = (String) entry.getValue();
		if ("attach".equalsIgnoreCase(k) || "body".equalsIgnoreCase(k) || "sign".equalsIgnoreCase(k)) {
			sb.append("<" + k + ">" + "<![CDATA[" + v + "]]></" + k + ">");
		} else {
			sb.append("<" + k + ">" + v + "</" + k + ">");
		}
	}
	sb.append("</xml>");
	return sb.toString();
}
/**
 * @author
 * @date 2016-4-22
 * @Description:sign签名
 * @param characterEncoding
 *      编码格式
 * @param packageParams
 *      请求参数
 * @return
 */
public static String createSign(String characterEncoding, SortedMap<Object, Object> packageParams, String API_KEY) {
	StringBuffer sb = new StringBuffer();
	Set es = packageParams.entrySet();
	Iterator it = es.iterator();
	while (it.hasNext()) {
		Map.Entry entry = (Map.Entry) it.next();
		String k = (String) entry.getKey();
		String v = (String) entry.getValue();
		if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {
			sb.append(k + "=" + v + "&");
		}
	}
	sb.append("key=" + API_KEY);
	String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase();
	return sign;
} 
package com.zhx.guides.assistant.interfaces.pay.wechatpay.util;

import java.security.MessageDigest;

public class MD5Util {

  private static String byteArrayToHexString(byte b[]) {
    StringBuffer resultSb = new StringBuffer();
    for (int i = 0; i < b.length; i++)
      resultSb.append(byteToHexString(b[i])); 

    return resultSb.toString();
  } 

  private static String byteToHexString(byte b) {
    int n = b;
    if (n < 0)
      n += 256;
    int d1 = n / 16;
    int d2 = n % 16;
    return hexDigits[d1] + hexDigits[d2];
  } 

  public static String MD5Encode(String origin, String charsetname) {
    String resultString = null;
    try {
      resultString = new String(origin);
      MessageDigest md = MessageDigest.getInstance("MD5");
      if (charsetname == null || "".equals(charsetname))
        resultString = byteArrayToHexString(md.digest(resultString
            .getBytes()));
      else
        resultString = byteArrayToHexString(md.digest(resultString
            .getBytes(charsetname)));
    } catch (Exception exception) {
    }
    return resultString;
  } 

  /***
   * 简化版本
   * @param s
   * @return
   */
  public final static String MD5(String s) {
		char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
		try {
			byte[] btInput = s.getBytes("utf-8");
			// 获得MD5摘要算法的 MessageDigest 对象
			MessageDigest mdInst = MessageDigest.getInstance("MD5");
			// 使用指定的字节更新摘要
			mdInst.update(btInput);
			// 获得密文
			byte[] md = mdInst.digest();
			// 把密文转换成十六进制的字符串形式
			int j = md.length;
			char str[] = new char[j * 2];
			int k = 0;
			for (int i = 0; i < j; i++) {
				byte byte0 = md[i];
				str[k++] = hexDigits[byte0 >>> 4 & 0xf];
				str[k++] = hexDigits[byte0 & 0xf];
			}
			return new String(str);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

  private static final String hexDigits[] = { "0", "1", "2", "3", "4", "5",
      "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" }; 

}
/**
 * @author
 * @date 2016-4-22
 * @Description:将请求参数转换为xml格式的string
 * @param parameters
 *      请求参数
 * @return
 */
public static String getRequestXml(SortedMap<Object, Object> parameters) {
	StringBuffer sb = new StringBuffer();
	sb.append("<xml>");
	Set es = parameters.entrySet();
	Iterator it = es.iterator();
	while (it.hasNext()) {
		Map.Entry entry = (Map.Entry) it.next();
		String k = (String) entry.getKey();
		String v = (String) entry.getValue();
		if ("attach".equalsIgnoreCase(k) || "body".equalsIgnoreCase(k) || "sign".equalsIgnoreCase(k)) {
			sb.append("<" + k + ">" + "<![CDATA[" + v + "]]></" + k + ">");
		} else {
			sb.append("<" + k + ">" + v + "</" + k + ">");
		}
	}
	sb.append("</xml>");
	return sb.toString();
} 

四:请求XML示例

<xml>
  <appid>wx2421b1c4370ec43b</appid>
  <mch_id>10000100</mch_id>
  <nonce_str>6cefdb308e1e2e8aabd48cf79e546a02</nonce_str>
  <out_refund_no>1415701182</out_refund_no>
  <out_trade_no>1415757673</out_trade_no>
  <refund_fee>1</refund_fee>
  <total_fee>1</total_fee>
  <transaction_id></transaction_id>
  <sign>FE56DD4AA85C0EECA82C35595A69E153</sign>
</xml>

五:官方信息

官方地址:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_4

需注意这两个参数我使用的是out_trade_no

总结

到此这篇关于SpringBoot 微信退款功能的示例代码的文章就介绍到这了,更多相关SpringBoot 微信退款内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • springboot整合微信支付sdk过程解析

    前言 之前做的几个微信小程序项目,大部分客户都有要在微信小程序前端提现的需求.提现功能的实现,自然使用企业付款接口,不过这个功能开通比较麻烦,要满足3个条件; 之前实现过几个微信支付的接口,不过都是自己码的代码,从网上找找拼凑,觉得看起来不舒服~_~ 于是乎找到了微信官方提供的支付sdk.这里用的是java版本,springboot整合java 下载sdk,引入项目 这里可以直接下载官方提供的sdk,然后将几个java类拷贝到你的项目,也可以直接引入maven依赖,这里是直接将Java类拷贝到我

  • SpringBoot集成支付宝沙箱支付(支付、退款)

    前言 支付宝推出一个沙箱环境,能够很好的模拟支付宝支付,并且还提供了demo,但demo是一个普通web项目,怎么整合到Spring Boot项目呢,其实很简单 简单配置请参照支付宝沙箱支付开发文档 一.支付部分 AlipayConfig配置:我使用的是页面跳转同步通知,返回路径return_url为公网访问地址,也可以使用localhost,且不能携带参数,APPID.商户私钥.支付宝公钥和支付宝网关换为自己的. public class AlipayConfig{ // 应用ID,您的APP

  • SpringBoot 微信退款功能的示例代码

    一:微信支付证书配置 二:证书读取以及读取后的使用 package com.zhx.guides.assistant.config.wechatpay; import org.apache.commons.io.IOUtils; import org.apache.http.HttpEntity; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.H

  • Flutter实现仿微信分享功能的示例代码

    目录 1.首先去pub官网 2 在微信开放平台注册开发者账号以及创建你的应用程序 3 在分享页面 3.1 初始化 3.2 检测微信是否安装 3.3 分享微信消息 总结 本文设计到的知识点有 主要问题 Flutter 用来快速开发 Android iOS平台应用,在Flutter 中,通过 fluwx或者fluwx_no_pay 插件来实现微信分享功能 主要还是看自己的需求,本示例我将按照没有支付的实现.至于为什么,主要是ios打包提审比较麻烦. 那么接下来就看一下如何实现吧, 1.首先去pub官

  • SpringBoot整合Vue实现微信扫码支付以及微信退款功能详解

    直接上代码,在order模块添加依赖 <dependency> <groupId>com.github.wxpay</groupId> <artifactId>wxpay-sdk</artifactId> <version>0.0.3</version> </dependency> 在配置类添加申请的商家号信息 #关联的公众号appid weixin.pay.appid=wxXXXXXXX #商户号 weixi

  • Android仿微信发送语音消息的功能及示例代码

    微信的发送语音是有一个向上取消的,我们使用onTouchListener来监听手势,然后做出相应的操作就行了. 直接上代码: //语音操作对象 private MediaPlayer mPlayer = null; private MediaRecorder mRecorder = null; //语音文件保存路径 private String FileName = null; FileName = Environment.getExternalStorageDirectory().getAbs

  • PHP开发实现微信退款功能示例

    本文实例讲述了PHP开发实现微信退款功能.分享给大家供大家参考,具体如下: 最近在调微信退款接口,发现有许多坑,更大家分享一下 ① 要是在测试的时候,网页提示 curl 58 说明 证书的路径出现问题(这里要填物理路径,也就是绝对路径) ② 网页提示curl 52 说明你的证书引入少了,在官方的demo上只有两个证书 apiclient_cert.pem和 apiclient_key.pem  你还需要引入一个证书 rootca.pem,这个证书需要你登录到 你的商户平台上下载 ③ 要是网页提示

  • 微信小程序实现拨打电话功能的示例代码

    1.在对应需要拨打电话的标签那里绑定事件(使用的标签不固定,可以是text.view等) 例子: <text class="phone" bindtap="callPhone">400-9121-211</text> 2.在对应的事件方法里面写入 wx.makePhoneCall方法 例子: callPhone() { wx.makePhoneCall({ phoneNumber: '400-9121-211' //仅为示例,并非真实的电话号

  • 微信小程序连续签到7天积分获得功能的示例代码

    每周每天签到获得积分的案例 功能设计:计算每天签到得1分,显示得到的签到积分,连续签到3天[周一二三]即得+多3分,连续签到7天[周一二三四五六日]+多7分,没有连续即不显示多余的3分或7分的提示- wxml结构: <!--pages/signIn2/signIn2.wxml--> <view class='sign-new'> <view class='in'> <view class='new-head'> <view class='sig-tl'

  • springboot整合gateway实现网关功能的示例代码

    目录 1.使用场景: 2.代码实现 1创建gateway-service服务 2创建gateway-client服务 3.实现效果 1.使用场景: 网关可提供请求路由与组合.协议转换.安全认证.服务鉴权.流量控制与日志监控等服务.可选的网关有不少,比如 Nginx..Linkerd .eureka. Spring Cloud Gateway.consul等. Spring Cloud Gateway 针对进来的请求做各种判断和处理,比如说判断请求的合法性.权限验证,请求地址改写,请求参数.头信息

  • 微信小程序实现幸运大转盘功能的示例代码

    目录 一.项目展示 二.抽奖页 三.领奖页 一.项目展示 幸运大转盘是一个简单的抽奖小程序 参与用户点击抽奖便可抽取轮盘的奖品 二.抽奖页 抽奖页是一个大轮盘和活动规则 页面形式简单 主要核心在于轮盘 核心代码[轮盘旋转]如下: getLottery: function () { var that = this var awardIndex = Math.random() * 6 >>> 0; // 获取奖品配置 var awardsConfig = app.awardsConfig,

  • springboot整合@Retryable实现重试功能的示例代码

    目录 前言 @Retryable 简介 使用步骤 1.引入依赖 2.启用@Retryable 3.添加@Retryable注解 4.测试 注意事项 最后 结语 前言 在实际工作中,重试机制是一个很常见的场景,比如:发送消息失败,下载网络文件失败等…,因为这些错误可能是网络波动造成的,等待一些延迟就能成功处理.我们通常会使用try/catch.while循环等进行相关处理,但是这样看起来比较臃肿复杂,且不好看.于是就有了spring提供的重试模块—— @Retryable @Retryable 简

随机推荐