第三方应用微信退款功能
项目中用到微信退款功能,简述一下
打开微信支付开发文档!api列表申请退款,注意:退款需要双向证书
下载API证书,也可以按照以下路径下载:微信商户平台(pay.weixin.qq.com)-->账户中心-->账户设置-->API安全-->证书下载
有四个文件分被是:apiclient_cert.p12;apiclient_cert.pem;apiclient_key.pem;rootca.pem java开发的只用到p12证书!将该证书复制到linux系统下某个目录下(或者windowns系统某个目录下)然后就可以开发了
直接附上代码
/*** * @Description (微信退款)* @param order* @return*/public static Map<String,Object> refundOrder(Order order){Map<String,Object> retMap = new HashMap<String,Object>();try{//将金额单位转换成分int amount = 1;if(StringUtils.isNotEmpty(String.valueOf(order.getPayMoney()))){amount = (int) Math.round(Double.parseDouble(String.valueOf(order.getPayMoney()))*100);}//获得随机字符串String nonce_str = StringUtil.createNonceStr();//组装签名字符串String signStr = "appid=" + WxPayConfig.APP_ID +"&mch_id=" + WxPayConfig.APP_MCH_ID+"&nonce_str=" + nonce_str+"&out_refund_no=" + order.getOrderCode()+"&out_trade_no=" + order.getOrderId()+"&refund_fee=" + amount+"&total_fee=" + amount+"&key="+ WxPayConfig.APP_MCH_APPSECRET;System.out.println(signStr);//签名最后全部转为大写String sign = Md5Util.MD5Encode(signStr).toUpperCase();//拼接下单xmlStringBuffer xml = new StringBuffer();xml.append("<xml>");xml.append("<appid>").append(WxPayConfig.APP_ID).append("</appid>");xml.append("<mch_id>").append(WxPayConfig.APP_MCH_ID).append("</mch_id>");xml.append("<nonce_str>").append(nonce_str).append("</nonce_str>");xml.append("<out_refund_no>").append(order.getOrderCode()).append("</out_refund_no>");xml.append("<out_trade_no>").append(order.getOrderId()).append("</out_trade_no>");xml.append("<refund_fee>").append(amount).append("</refund_fee>");xml.append("<total_fee>").append(amount).append("</total_fee>");xml.append("<sign>").append(sign).append("</sign>");xml.append("</xml>");//请求微信下单接口String retXmlStr =new HttpsRequest().sendPost(WxPayConfig.REFUND_ORDER_ADDRESS, xml.toString());//解析返回数据if(StringUtils.isNotEmpty(retXmlStr)){retMap = XmlUtil.xmlStrParser(retXmlStr);}}catch(Exception ex){ex.printStackTrace();}return retMap;}
其中涉及到的工具类方法
/*** * @Title: createNonceStr * @Description: 创建* @return* @throws*/public static String createNonceStr(){String letter[] = {"A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","S","Y","Z"};String nonce_str="";for(int i=0;i<26;i++){int num = new Random().nextInt(26);nonce_str+= letter[num];}return nonce_str;}
/*** MD5编码* @param origin 原始字符串* @return 经过MD5加密之后的结果*/public static String MD5Encode(String origin) {String resultString = null;try {resultString = origin;MessageDigest md = MessageDigest.getInstance("MD5");resultString = byteArrayToHexString(md.digest(resultString.getBytes("UTF-8")));} catch (Exception e) {e.printStackTrace();}return resultString;}
/*** 将xml结构的字符串转换成map* * @param xmlStr* @return*/public static Map<String,Object> xmlStrParser(String xmlStr) {Map<String,Object> map = new HashMap<String,Object>();// 创建一个新的字符串StringReader read = new StringReader(xmlStr);// 创建新的输入源SAX 解析器将使用 InputSource 对象来确定如何读取 XML 输入InputSource source = new InputSource(read);// 创建一个新的SAXBuilderSAXBuilder sb = new SAXBuilder();try {// 通过输入源构造一个DocumentDocument doc = sb.build(source);// 取的根元素Element root = doc.getRootElement();System.out.println(root.getName());// 输出根元素的名称(测试)// 得到根元素所有子元素的集合List jiedian = root.getChildren();// 获得XML中的命名空间(XML中未定义可不写)Namespace ns = root.getNamespace();Element et = null;for (int i = 0; i < jiedian.size(); i++) {et = (Element) jiedian.get(i);// 循环依次得到子元素// System.out.println("key/value==>" + et.getName() +"/"+// et.getText());map.put(et.getName(), et.getText());}// et = (Element) jiedian.get(0);// List zjiedian = et.getChildren();// for(int j=0;j<zjiedian.size();j++){// Element xet = (Element) zjiedian.get(j);// System.out.println(xet.getName());// }} catch (Exception ex) {ex.printStackTrace();}return map;}
加载证书以及发送请求类
package com.bluemobi.framework.utils.wxPay;import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.SocketTimeoutException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;import javax.net.ssl.SSLContext;import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.ConnectionPoolTimeoutException;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;public class HttpsRequest {private static Logger logger = Logger.getLogger(HttpsRequest.class);//表示请求器是否已经做了初始化工作private boolean hasInit = false;//连接超时时间,默认10秒private int socketTimeout = 10000;//传输超时时间,默认30秒private int connectTimeout = 30000;//请求器的配置private RequestConfig requestConfig;//HTTP请求器private CloseableHttpClient httpClient;/*** 构造方法*/public HttpsRequest() throws UnrecoverableKeyException, KeyManagementException, NoSuchAlgorithmException, KeyStoreException, IOException, NoSuchProviderException {init();}/**** 初始化https(加载证书)*/private void init() throws IOException, KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyManagementException , NoSuchProviderException{KeyStore keyStore = KeyStore.getInstance("PKCS12");FileInputStream instream = new FileInputStream(new File(WxPayConfig.CERT_LOCALPATH));//加载本地的证书进行https加密传输try {keyStore.load(instream, WxPayConfig.APP_MCH_ID.toCharArray());//设置证书密码} catch (CertificateException e) {e.printStackTrace();} catch (NoSuchAlgorithmException e) {e.printStackTrace();} finally {instream.close();}SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, WxPayConfig.APP_MCH_ID.toCharArray()).build();SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[]{"TLSv1"},null,SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout).setConnectTimeout(connectTimeout).build();hasInit = true;}/*** 通过Https往API post xml数据(post)** @param url API地址* @param xmlObj 要提交的XML数据对象* @return API回包的实际数据*/public String sendPost(String url, String xmlObj) throws IOException, KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyManagementException, NoSuchProviderException {if (!hasInit) {init();}String result = null;HttpPost httpPost = new HttpPost(url);logger.info("API,POST过去的数据是:" + xmlObj);//得指明使用UTF-8编码,否则到API服务器XML的中文不能被成功识别StringEntity postEntity = new StringEntity(xmlObj, "UTF-8");httpPost.addHeader("Content-Type", "text/xml");httpPost.setEntity(postEntity);//设置请求器的配置httpPost.setConfig(requestConfig);logger.info("执行请求:" + httpPost.getRequestLine());try {HttpResponse response = httpClient.execute(httpPost);HttpEntity entity = response.getEntity();result = EntityUtils.toString(entity, "UTF-8");} catch (ConnectionPoolTimeoutException e) {logger.error("http get throw ConnectionPoolTimeoutException(wait time out)");} catch (ConnectTimeoutException e) {logger.error("http get throw ConnectTimeoutException");} catch (SocketTimeoutException e) {logger.error("http get throw SocketTimeoutException");} catch (Exception e) {logger.error("http get throw Exception");} finally {httpPost.abort();}return result;}/*** 设置连接超时时间** @param socketTimeouts 连接时长,默认10秒*/public void setSocketTimeout(int socketTimeouts) {socketTimeout = socketTimeouts;resetRequestConfig();}/*** 设置传输超时时间** @param connectTimeouts 传输时长,默认30秒*/public void setConnectTimeout(int connectTimeouts) {connectTimeout = connectTimeouts;resetRequestConfig();}private void resetRequestConfig() {requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout).setConnectTimeout(connectTimeout).build();}/*** 允许商户自己做更高级更复杂的请求器配置** @param requestConfigs 设置HttpsRequest的请求器配置*/public void setRequestConfig(RequestConfig requestConfigs) {requestConfig = requestConfigs;}}
其中涉及到的包在 使用商户证书-点击(请参考微信支付提供的demo外链)下载就会有相应的jar包;主要是:httpclient-4.3.4.jar;httpcore-4.3.2.jar
第三方应用微信退款功能相关推荐
- 售后退款的java代码_SpringBoot 微信退款功能的示例代码
一:微信支付证书配置 二:证书读取以及读取后的使用 package com.zhx.guides.assistant.config.wechatpay; import org.apache.commo ...
- php做一个微信退款,PHP实现微信退款功能
大家好,我是小编,最近在调微信退款接口,发现有许多坑,更大家分享一下 ① 要是在测试的时候,网页提示 curl 58 说明 证书的路径出现问题(这里要填物理路径,也就是绝对路径) ②网页提示curl ...
- 拼团功能实现 php_PHP实现微信退款功能
最近在调微信退款接口,发现有许多坑,更大家分享一下 ① 要是在测试的时候,网页提示 curl 58 说明 证书的路径出现问题(这里要填物理路径,也就是绝对路径) ②网页提示curl 52 说明你的证书 ...
- 微信小程序支付退款功能
微信小程序支付退款功能 2022年02月做了一个微信小程序前端+ASP.NET后台的微信退款功能.功能的基本原理是使用JSAPI方式,对接之前的微信支付功能差不多.也是要签名,校验等.只不过它的退款传 ...
- IJPay微信退款协议不正确 No appropriate protocol
目录 问题发现 问题研究 解决方案 问题发现 项目中有微信支付功能,也可以微信退款,因为自己写支付代码比较臃肿,所以用了第三方包IJPay来实现支付和退款功能,它封装了一些第三方支付的方法,比如支付宝 ...
- 尚医通(二十四)微信退款(取消预约功能)
目录 一.取消预约 1.需求描述 2.开发取消预约接口 一.取消预约 1.需求描述 取消订单分两种情况: (1)未支付取消订单,直接通知医院更新取消预约状态 (2)已支付取消订单,先退款给用户,然后通 ...
- 【愚公系列】2022年10月 微信小程序-电商项目-微信支付小程序确认支付结果和退款功能实现(node)
文章目录 前言 一.微信支付小程序确认支付结果和退款功能实现 1.确认支付结果 2.退款功能实现 前言 微信小程序在支付成功后会给注册的接口发消息来通知订单支付成功的状态,下面是微信和接口通信的数据格 ...
- php 微信支付 退款接口,php实现微信支付之退款功能
网上的很多PHP微信支付接入教程都颇为复杂,且需要配置和引入较多的文件,本人通过整理后给出一个单文件版的,希望可以给各位想接入微信支付的带来些许帮助和借鉴意义. 直接运行该文件即可给指定的微信用户退款 ...
- Java实现微信的申请退款功能
一,问题 今天要将微信的最后一个功能给做完了,这个功能就是申请退款.刚开始我先看了一下文档,发现它跟那个企业付款到零钱特别相似,然后就自己模仿企业付款到零钱把它给实现了. 二,解决方法 申请退款官方文 ...
最新文章
- 设计模式系列·抽象工厂模式
- Linux给用户添加sudo权限
- laravel Collection mapToDictionary 例子
- php_中替换换行符
- CF79D Password(P3943 星空)
- java web开发技术大_2021年六大javaweb开发主流技术
- 字节流复制文件 java
- 【ElasticSearch】Es 源码之 CcrRestoreSourceService 源码解读
- 24_多易教育之《yiee数据运营系统》OLAP平台-运营分析篇
- 游戏算法整理(贴图完整版)
- SPSS——随机抽样
- 相控阵天线面阵方向图(FFT变换)
- ESP8266获取B站粉丝数
- 无法获取 vmci 驱动程序版本句柄无效解决办法
- u盘插电脑计算机卡了,电脑插U盘就卡住是怎么回事 几个步骤轻松解决电脑卡顿故障...
- C++ explicit的使用
- 设一个学生的信息包括学号、姓名、出生日期和性别等。把n个学生的信息放入一个集合中,可以根据学号对学生信息进行检索,并且可以根据出生日期对学生进行排序输出。
- 彻底关闭Windows 10 Defender病毒防护
- leetcode Ch3-DFS Backtracking II
- 对数组中重复的值进行重命名