Hi,大家好,我是编程小6,很荣幸遇见你,我把这些年在开发过程中遇到的问题或想法写出来,今天说一说微信支付(青蛙刷脸支付、小程序),希望能够帮助你!!!。
package com.slf.utils.dto.wechat;
import lombok.Data;
import java.math.BigDecimal;
/**
* @Author: LiuYong
* @Date:2019/12/17 16:18
* @Description: TODO 描述
*/
@Data
public class WechatDto {
/**设备编号*/
private String dcode;
/**订单编号*/
private String orderNumber;
/**总金额(单位:分)*/
private BigDecimal totalFee;
/**设备ip地址*/
private String ip;
/**用户标识*/
private String openid;
/**人脸凭证*/
private String faceCode;
/**授权码*/
private String authCode;
/***/
private Long faceCodeType;
/**特约商户appid*/
private String subAppid;
/**特约商户号*/
private String subMchId;
/**服务商公众账号ID*/
private String appId;
/**服务商商户号*/
private String mchId;
/**服务商商户支付密钥*/
private String key;
/**商户名称*/
private String bName;
}
package com.slf.utils.utils;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import java.util.logging.Logger;
/**
* json对象或字符串转xml
* @Author: LiuYong
* @Date:2019/12/11 11:21
* @Description: TODO json对象或字符串转xml
*/
public class JsonAndXmlUtils {
private static Logger logger = Logger.getLogger(JsonAndXmlUtils.class.getName());
public static void main(String[] args) throws Exception
{
String jsonInput = "{\"nonce_str\":\"b927722419c52622651a871d1d9ed8b2\",\"device_info\":\"1000\",\"out_trade_no\":\"1403213376\",\"appid\":\"wxE421b1c4370ec43b\",\"total_fee\":\"1\",\"sign\":\"3CA89B5870F944736C657979192E1CF4\",\"trade_type\":\"JSAPI\",\"attach\":\"att1\",\"body\":\"JSAPI支付测试\",\"mch_id\":\"10000100\",\"notify_url\":\"http://wxpay.weixin.qq.com/pub_v2/pay/notify.php\",\"spbill_create_ip\":\"127.0.0.1\"}\n";
String jsonToXml = JsonAndXmlUtils.jsonToXml(jsonInput);
System.out.println("jsonToXml:\n"+jsonToXml);
JSONObject jsonObject = xmlToJson(jsonToXml);
System.out.println("xmlToJson:\n"+jsonObject.toJSONString());
System.out.println("WxJsonToXml:\n"+WxJsonToXml(jsonObject));
}
/**
* xml字符串转json对象
* @Author LiuYong
* @Date 2019/12/11 11:40
* @Description TODO xml字符串转json对象
* @param xmlStr
* @return JSONObject
**/
public static JSONObject xmlToJson(String xmlStr){
XmlMapper xmlMapper = new XmlMapper();
JSONObject jsonObject1=null;
try{
jsonObject1 = xmlMapper.readValue(xmlStr, JSONObject.class);
}catch (Exception e){
logger.info("ERROR com.slf.utils.utils.JsonAndXmlUtils.xmlToJson 异常:"+e.getMessage());
}
return jsonObject1;
}
/**
* json字符串转xml字符串
* @Author LiuYong
* @Date 2019/12/11 11:45
* @Description TODO json字符串转xml字符串
* @param json
* @return String
**/
public static String jsonToXml(String json){
JSONObject jsonObject = JSONObject.parseObject(json);
XmlMapper xmlMapper = new XmlMapper();
String s = null;
try{
s = xmlMapper.writeValueAsString(jsonObject);
}catch (Exception e){
logger.info("ERROR com.slf.utils.utils.JsonAndXmlUtils.jsonToXml 异常:"+e.getMessage());
}
return s;
}
public static String WxJsonToXml(JSONObject jsonObject){
return jsonToXml(jsonObject.toJSONString()).replace("JSONObject","xml");
}
}
package com.slf.utils.utils;
import org.springframework.util.ResourceUtils;
import java.io.*;
/**
* @Author: LiuYong
* @Date:2019/12/16 11:29
* @Description: TODO 描述
*/
public class PathUtil {
public static void main(String[] args) throws Exception{
System.out.println(ResourceUtils.getURL("classpath:").getPath());
System.out.println(PathUtil.class.getClassLoader().getResource(".").getPath());
// String readfile = readfile("D:\\Software\\IdeaProjects\\slf-app-api\\slf-pay\\slf-pay-service\\src\\main\\resources\\static\\sq\\success.html");
// System.out.println(readfile);
}
public static String getPath(String url) throws Exception {
//路径
File path = new File(ResourceUtils.getURL("classpath:").getPath());
if (!path.exists()) {
path = new File("");
}
//如果上传目录为/static/images/upload/,则可以如下获取
File upload = new File(path.getAbsolutePath(), "static/"+url+"/");
if (!upload.exists()) {
upload.mkdirs();
// System.out.println(upload.getAbsolutePath());
//在开发测试模式时,得到地址为:{项目跟目录}/target/static/images/upload/
//在打成jar正式发布时,得到的地址为:{发布jar包目录}/static/images/upload/
}
return upload.getAbsolutePath();
}
public static String readfile(String filePath){
File file = new File(filePath);
InputStream input = null;
try {
input = new FileInputStream(file);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
StringBuffer buffer = new StringBuffer();
byte[] bytes = new byte[1024];
try {
for(int n ; (n = input.read(bytes))!=-1 ; ){
buffer.append(new String(bytes,0,n,"UTF-8"));
}
} catch (IOException e) {
e.printStackTrace();
}
return buffer.toString();
}
}
package com.slf.utils.utils.http;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.net.ssl.*;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.net.ConnectException;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.net.URLConnection;
import java.security.cert.X509Certificate;
/**
* 通用http发送方法
*
*/
public class HttpUtils
{
private static final Logger log = LoggerFactory.getLogger(HttpUtils.class);
public static String getIpAddr(HttpServletRequest request) {
String ip = request.getHeader("x-forwarded-for");
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return ip;
}
/**
* 向指定 URL 发送GET方法的请求
*
* @param url 发送请求的 URL
* @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
* @return 所代表远程资源的响应结果
*/
public static String sendGet(String url, String param)
{
StringBuilder result = new StringBuilder();
BufferedReader in = null;
try
{
String urlNameString = url + "?" + param;
log.info("sendGet - {}", urlNameString);
System.out.println(urlNameString);
URL realUrl = new URL(urlNameString);
URLConnection connection = realUrl.openConnection();
connection.setRequestProperty("accept", "*/*");
connection.setRequestProperty("connection", "Keep-Alive");
connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
connection.connect();
in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line;
while ((line = in.readLine()) != null)
{
result.append(line);
}
log.info("recv - {}", result);
}
catch (ConnectException e)
{
log.error("调用HttpUtils.sendGet ConnectException, url=" + url + ",param=" + param, e);
}
catch (SocketTimeoutException e)
{
log.error("调用HttpUtils.sendGet SocketTimeoutException, url=" + url + ",param=" + param, e);
}
catch (IOException e)
{
log.error("调用HttpUtils.sendGet IOException, url=" + url + ",param=" + param, e);
}
catch (Exception e)
{
log.error("调用HttpsUtil.sendGet Exception, url=" + url + ",param=" + param, e);
}
finally
{
try
{
if (in != null)
{
in.close();
}
}
catch (Exception ex)
{
log.error("调用in.close Exception, url=" + url + ",param=" + param, ex);
}
}
return result.toString();
}
/**
* 向指定 URL 发送POST方法的请求
*
* @param url 发送请求的 URL
* @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
* @return 所代表远程资源的响应结果
*/
public static String sendPost(String url, String param)
{
PrintWriter out = null;
BufferedReader in = null;
StringBuilder result = new StringBuilder();
try
{
String urlNameString = url + "?" + param;
log.info("sendPost - {}", urlNameString);
URL realUrl = new URL(urlNameString);
URLConnection conn = realUrl.openConnection();
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
conn.setRequestProperty("Accept-Charset", "utf-8");
conn.setRequestProperty("contentType", "utf-8");
conn.setDoOutput(true);
conn.setDoInput(true);
out = new PrintWriter(conn.getOutputStream());
out.print(param);
out.flush();
in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
String line;
while ((line = in.readLine()) != null)
{
result.append(line);
}
log.info("recv - {}", result);
}
catch (ConnectException e)
{
log.error("调用HttpUtils.sendPost ConnectException, url=" + url + ",param=" + param, e);
}
catch (SocketTimeoutException e)
{
log.error("调用HttpUtils.sendPost SocketTimeoutException, url=" + url + ",param=" + param, e);
}
catch (IOException e)
{
log.error("调用HttpUtils.sendPost IOException, url=" + url + ",param=" + param, e);
}
catch (Exception e)
{
log.error("调用HttpsUtil.sendPost Exception, url=" + url + ",param=" + param, e);
}
finally
{
try
{
if (out != null)
{
out.close();
}
if (in != null)
{
in.close();
}
}
catch (IOException ex)
{
log.error("调用in.close Exception, url=" + url + ",param=" + param, ex);
}
}
return result.toString();
}
public static String sendSSLPost(String url, String param)
{
StringBuilder result = new StringBuilder();
String urlNameString = url + "?" + param;
try
{
log.info("sendSSLPost - {}", urlNameString);
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, new TrustManager[] { new TrustAnyTrustManager() }, new java.security.SecureRandom());
URL console = new URL(urlNameString);
HttpsURLConnection conn = (HttpsURLConnection) console.openConnection();
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
conn.setRequestProperty("Accept-Charset", "utf-8");
conn.setRequestProperty("contentType", "utf-8");
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setSSLSocketFactory(sc.getSocketFactory());
conn.setHostnameVerifier(new TrustAnyHostnameVerifier());
conn.connect();
InputStream is = conn.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String ret = "";
while ((ret = br.readLine()) != null)
{
if (ret != null && !ret.trim().equals(""))
{
result.append(new String(ret.getBytes("ISO-8859-1"), "utf-8"));
}
}
log.info("recv - {}", result);
conn.disconnect();
br.close();
}
catch (ConnectException e)
{
log.error("调用HttpUtils.sendSSLPost ConnectException, url=" + url + ",param=" + param, e);
}
catch (SocketTimeoutException e)
{
log.error("调用HttpUtils.sendSSLPost SocketTimeoutException, url=" + url + ",param=" + param, e);
}
catch (IOException e)
{
log.error("调用HttpUtils.sendSSLPost IOException, url=" + url + ",param=" + param, e);
}
catch (Exception e)
{
log.error("调用HttpsUtil.sendSSLPost Exception, url=" + url + ",param=" + param, e);
}
return result.toString();
}
private static class TrustAnyTrustManager implements X509TrustManager
{
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType)
{
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType)
{
}
@Override
public X509Certificate[] getAcceptedIssuers()
{
return new X509Certificate[] {};
}
}
private static class TrustAnyHostnameVerifier implements HostnameVerifier
{
@Override
public boolean verify(String hostname, SSLSession session)
{
return true;
}
}
}
package com.slf.utils.utils.wechat;
import org.apache.commons.lang3.RandomStringUtils;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Map;
import java.util.logging.Logger;
/**
* 微信工具类
* @Author: LiuYong
* @Date:2019/12/11 11:06
* @Description: TODO 微信工具类
*/
public class WeChatTool {
private static Logger logger = Logger.getLogger(WeChatTool.class.getName());
/**
* 随机字符串生成
* @Author LiuYong
* @Date 2019/12/12 9:43
* @Description TODO
* @param length 生成的字符串长度
* @param useLetters 生成的字符串可以包括字母字符
* @param useNumbers 生成的字符串可以包含数字字符
* @return
**/
public static String generatedString(int length,boolean useLetters,boolean useNumbers){
return RandomStringUtils.random(length, useLetters, useNumbers);
}
/**
* Sign签名生成方法
* @Author LiuYong
* @Date 2019/12/11 11:13
* @Description TODO Sign签名生成方法
* @param map 自定义参数
* @param key 商户KEY
* @param type 签名类型
* @return
**/
public static String getSign(Map<String,Object> map,String key,String type){
StringBuilder sb = new StringBuilder();
String result =null;
try{
ArrayList<String> list = new ArrayList<String>();
for(Map.Entry<String,Object> entry:map.entrySet()){
if(entry.getValue()!=""){
list.add(entry.getKey() + "=" + entry.getValue() + "&");
}
}
int size = list.size();
String [] arrayToSort = list.toArray(new String[size]);
Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);
for(int i = 0; i < size; i ++) {
sb.append(arrayToSort[i]);
}
sb.append("key=" + key);
result = sb.toString();
if(type.equals(WeChatConstants.MD5)){
result=MD5(result);
}else if(type.equals(WeChatConstants.HMACSHA256)){
result=HMACSHA256(result,key);
}
}catch (Exception e){
logger.info("ERROR com.slf.utils.utils.wechat.WeChatTool.getSign :"+e.getMessage());
return null;
}
return result;
}
/**
* 生成 MD5
* @Author LiuYong
* @Date 2019/12/11 17:08
* @Description TODO 生成 MD5
* @param data 待处理数据
* @return 加密结果
**/
public static String MD5(String data) {
StringBuilder sb = new StringBuilder();
try{
java.security.MessageDigest md = MessageDigest.getInstance("MD5");
byte[] array = md.digest(data.getBytes("UTF-8"));
for (byte item : array) {
sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
}
}catch (Exception e){
logger.info("ERROR com.slf.utils.utils.wechat.WeChatTool.MD5 :"+e.getMessage());
return null;
}
return sb.toString().toUpperCase();
}
/**
* 生成 HMACSHA256
* @Author LiuYong
* @Date 2019/12/11 17:00
* @Description TODO 生成 HMACSHA256
* @param data 待处理数据
* @param key 密钥
* @return 加密结果
**/
public static String HMACSHA256(String data, String key) {
StringBuilder sb = new StringBuilder();
try{
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA256");
sha256_HMAC.init(secret_key);
byte[] array = sha256_HMAC.doFinal(data.getBytes("UTF-8"));
for (byte item : array) {
sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
}
}catch (Exception e){
logger.info("ERROR com.slf.utils.utils.wechat.WeChatTool.HMACSHA256 :"+e.getMessage());
return null;
}
return sb.toString().toUpperCase();
}
}
package com.slf.utils.utils.wechat;
/**
* 微信参数配置
* @Author: LiuYong
* @Date:2019/12/11 10:45
* @Description: TODO 服务商账户信息配置
*/
public class WeChatConstants {
/**
* 服务商公众账号ID
* appid是商户在微信申请公众号成功后分配的帐号ID
*/
protected static final String APPID="";
/**
* 特约商户公众账号ID
* 服务商模式专有参数
*/
protected static final String SUB_APPID="SUB_APPID";
/**
* 服务商商户号
* 微信支付分配的商户号
*/
protected static final String MCH_ID="";
/**
* 服务商商户支付密钥
*/
protected static final String KEY="";
/**签名类型*/
public static final String MD5="MD5";
public static final String HMACSHA256="HMACSHA256";
/*************************************************/
/**
* 小程序密钥
*/
protected static final String APP_SECRET="";
/**
* 小程序appid
*/
protected static final String APP_APPID="";
}
package com.slf.utils.utils.wechat;
/**
* @Author: LiuYong
* @Date:2019/12/12 12:02
* @Description: TODO 微信支付请求参数配置
*/
public class WeChatPayConstants {
/**
* 主要的API
*/
public static final String DOMAIN_API = "https://api.mch.weixin.qq.com/";
/**----------------↓↓↓↓↓↓刷脸支付后端接口↓↓↓↓↓↓----------------*/
/**接口文档: https://pay.weixin.qq.com/wiki/doc/wxfacepay/develop/backend.html#%E5%88%B7%E8%84%B8%E6%94%AF%E4%BB%98%E5%90%8E%E7%AB%AF%E6%8E%A5%E5%8F%A3
* */
/**
* 刷脸支付接口
* 是否需要证书:不需要
*/
public static final String PAY_FACEPAY = "pay/facepay";
/**
* 刷脸支付查询接口
* 是否需要证书:不需要
*/
public static final String PAY_FACEPAYQUERY = "pay/facepayquery";
/**
* 刷脸支付退款查询接口
* 是否需要证书:不需要
*/
public static final String PAY_REFUNDQUERY = "pay/refundquery";
/**
* 刷脸支付撤销订单接口
* 是否需要证书:需要
*/
public static final String SECAPI_PAY_FACEPAYREVERSE = "secapi/pay/facepayreverse";
/**----------------↑↑↑↑↑↑刷脸支付后端接口↑↑↑↑↑↑----------------*/
/**----------------↓↓↓↓↓↓扫码支付接口↓↓↓↓↓↓----------------*/
/**https://pay.weixin.qq.com/wiki/doc/api/micropay_sl.php?chapter=9_2*/
/**
* 扫码支付
* 是否需要证书:不需要
*/
public static final String PAY_MICROPAY = "pay/micropay";
/**
* 扫码支付查询订单
* 是否需要证书:不需要
*/
public static final String PAY_ORDERQUERY = "pay/orderquery";
/**
* 扫码支付撤销订单
* 是否需要证书:请求需要双向证书
*/
public static final String SECAPI_PAY_REVERSE = "secapi/pay/reverse";
/**
* 申请退款:服务商模式下,退款接口需要单独申请权限
* 是否需要证书:请求需要双向证书
*/
public static final String SECAPI_PAY_REFUND = "secapi/pay/refund";
/**
* 下载对账单
* 是否需要证书:不需要
*/
public static final String PAY_DOWNLOADBILL = "pay/downloadbill";
/**
* 授权码查询openid
*/
public static final String TOOLS_AUTHCIDETOOPENID = "tools/authcodetoopenid";
/**----------------↑↑↑↑↑↑扫码支付接口↑↑↑↑↑↑----------------*/
/**----------------↓↓↓↓↓↓人脸付押金接口↓↓↓↓↓↓----------------*/
/**接口文档:https://pay.weixin.qq.com/wiki/doc/api/deposit_sl.php?chapter=27_0&index=1*/
/**
* 支付押金(人脸支付)
* 是否需要证书:不需要
* 签名方式:HMAC-SHA256
*/
public static final String DEPOSIT_FACEPAY = "deposit/facepay";
/**
* 支付押金(付款码支付)
* 是否需要证书:不需要
* 签名方式:HMAC-SHA256
*/
public static final String DEPOSIT_MICROPAY = "deposit/micropay";
/**
* 查询订单
* 是否需要证书:不需要
* 签名方式:HMAC-SHA256
*/
public static final String DEPOSIT_ORDERQUERY = "deposit/orderquery";
/**
* 撤销订单
* 是否需要证书:请求需要双向证书
* 签名方式:HMAC-SHA256
*/
public static final String DEPOSIT_REVERSE = "deposit/reverse";
/**
* 消费押金
* 是否需要证书:请求需要双向证书
* 签名方式:HMAC-SHA256
*/
public static final String DEPOSIT_CONSUME = "deposit/consume";
/**
* 申请退款(押金)
* 是否需要证书:请求需要双向证书
* 签名方式:HMAC-SHA256
*/
public static final String DEPOSIT_REFUND = "deposit/refund";
/**
* 查询退款(押金)
* 是否需要证书:请求需要双向证书
* 签名方式:HMAC-SHA256
*/
public static final String DEPOSIT_REFUNDQUERY = "deposit/refundquery";
package com.slf.utils.utils.wechat;
import com.alibaba.fastjson.JSONObject;
import com.slf.utils.dto.wechat.WechatDto;
import com.slf.utils.utils.JsonAndXmlUtils;
import com.slf.utils.utils.PathUtil;
import com.slf.utils.utils.http.HttpUtils;
import com.slf.utils.utils.text.Convert;
import org.apache.http.HttpEntity;
import org.apache.http.client.config.RequestConfig;
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.conn.ssl.TrustStrategy;
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.SSLContextBuilder;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import java.io.IOException;
import java.math.BigDecimal;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import javax.net.ssl.SSLContext;
import java.io.FileInputStream;
import java.security.KeyStore;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;
/**
* 微信小程序支付工具类
*
* @Author: LiuYong
* @Date:2019/12/12 11:11
* @Description: TODO 微信小程序支付工具类
*/
public class WxPayUtil {
private static Logger log = Logger.getLogger(WxPayUtil.class.getName());
public static void main(String[] args) {
Map<String, Object> map = new HashMap<>();
map.put("appid", "服务商的APPID");
map.put("mch_id", "商户号");
map.put("sub_appid", "子商户公众账号ID");
map.put("sub_mch_id", "子商户号");
map.put("nonce_str", WeChatTool.generatedString(32, true, true));
map.put("out_trade_no", "663742984239583232");
map.put("out_refund_no", "tk01");
map.put("total_fee", "1");
map.put("refund_fee", "1");
map.put("sign", WeChatTool.getSign(map, "商户支付MD5字符串", WeChatConstants.MD5));
JSONObject json = new JSONObject(map);
JSONObject jsonObject1 = WxPayUtil.doRefundRequest("商户号", json);
System.out.println(jsonObject1);
}
/**
* 登录凭证校验
*
* @param jsCode
* @param appAppId 小程序appid
* @param appSecret 小程序密钥
* @return
*/
public static JSONObject openid(String jsCode, String appAppId, String appSecret) {
String s = HttpUtils.sendGet("https://api.weixin.qq.com/sns/jscode2session",
"appid=" + appAppId + "&secret=" + appSecret + "&js_code=" + jsCode + "&grant_type=authorization_code");
System.out.println(s);
return JSONObject.parseObject(s);
}
/**
* 刷脸支付接口
*
* @param jsonObject 参数对象
* @param key 商户支付密钥
* @return
* @Author LiuYong
* @Date 2019/12/16 10:47
* @Description TODO 刷脸支付接口
**/
public static JSONObject facepay(JSONObject jsonObject, String key) {
log.info("Submit payment:" + jsonObject);
String data = JsonAndXmlUtils.WxJsonToXml(jsonObject);
try {
CloseableHttpClient httpClient = notReadCertificate();
String s = HttpPost(WeChatPayConstants.PAY_FACEPAY, data, httpClient);
log.info("Paying with Your Face:" + s);
JSONObject result = JsonAndXmlUtils.xmlToJson(s);
System.out.println(result);
log.info("status:" + result.toJSONString());
if (result.getString("return_code").equalsIgnoreCase("SUCCESS") &&
result.getString("result_code").equalsIgnoreCase("SUCCESS")) {
return result;
} else {
payRevocation(jsonObject, key, false);
return result;
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 刷脸支付接口
*
* @param wechatDto
* @return
*/
public static JSONObject facepay(WechatDto wechatDto) {
JSONObject pay = new JSONObject();
pay.put("appid", wechatDto.getAppId());
pay.put("mch_id", wechatDto.getMchId());
pay.put("sub_appid", wechatDto.getSubAppid());
pay.put("sub_mch_id", wechatDto.getSubMchId());
pay.put("nonce_str", WeChatTool.generatedString(32, true, true));
pay.put("body", wechatDto.getBName());
pay.put("out_trade_no", wechatDto.getOrderNumber());
pay.put("total_fee", getTotalFee(wechatDto.getTotalFee()));
pay.put("spbill_create_ip", wechatDto.getIp());
pay.put("openid", wechatDto.getOpenid());
pay.put("face_code", wechatDto.getFaceCode());
pay.put("sign", WeChatTool.getSign(pay, wechatDto.getKey(), WeChatConstants.MD5));
return facepay(pay, wechatDto.getKey());
}
/**
* 付款码支付
*
* @param wechatDto
* @return
*/
public static JSONObject micropay(WechatDto wechatDto) {
System.out.println(wechatDto);
JSONObject pay = new JSONObject();
pay.put("appid", wechatDto.getAppId());
pay.put("sub_appid", wechatDto.getSubAppid());
pay.put("mch_id", wechatDto.getMchId());
pay.put("sub_mch_id", wechatDto.getSubMchId());
pay.put("nonce_str", WeChatTool.generatedString(32, true, true));
pay.put("body", wechatDto.getBName());
pay.put("out_trade_no", wechatDto.getOrderNumber());
pay.put("total_fee", getTotalFee(wechatDto.getTotalFee()));
pay.put("spbill_create_ip", wechatDto.getIp());
pay.put("auth_code", wechatDto.getAuthCode());
pay.put("sign", WeChatTool.getSign(pay, wechatDto.getKey(), WeChatConstants.MD5));
log.info("Scan the payment parameters:" + pay.toJSONString());
return micropay(pay, wechatDto.getKey());
}
/**
* @param
* @return
* @Author LiuYong
* @Date 2020-01-02 13:45
* @Description TODO 微信金额计算,元转分
**/
public static Long getTotalFee(BigDecimal bigDecimal) {
BigDecimal b1 = new BigDecimal(bigDecimal.toString());
BigDecimal b2 = new BigDecimal("100");
return Convert.toLong(b1.multiply(b2));
}
/**
* 付款码支付
*
* @param jsonObject 参数对象
* @param key 商户支付密钥
* @return
* @Author LiuYong
* @Date 2019/12/23 9:24
* @Description TODO
**/
public static JSONObject micropay(JSONObject jsonObject, String key) {
log.info("Submit payment:" + jsonObject);
String data = JsonAndXmlUtils.WxJsonToXml(jsonObject);
try {
CloseableHttpClient httpClient = notReadCertificate();
String s = HttpPost(WeChatPayConstants.PAY_MICROPAY, data, httpClient);
JSONObject result = JsonAndXmlUtils.xmlToJson(s);
log.info("Payment code payment results:" + result.toJSONString());
if (result.getString("return_code").equalsIgnoreCase("SUCCESS") &&
result.getString("result_code").equalsIgnoreCase("SUCCESS")) {
return result;
} else {
payRevocation(jsonObject, key, true);
return result;
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 撤销订单
*
* @param jsonObject 参数
* @param key 服务商支付KEY
* @param b true为扫码,false为刷脸
* @return
* @Author LiuYong
* @Date 2019/12/23 9:23
* @Description TODO 撤销订单
**/
public static void payRevocation(JSONObject jsonObject, String key, Boolean b) {
log.info("Cancel order parameter JSONObject:" + jsonObject);
log.info("Cancel order parameter key:" + key);
if (jsonObject.getString("out_trade_no") != null) {
JSONObject jsonObject2 = facepayQuery(jsonObject, key, b);
if (!jsonObject2.getString("result_code").equalsIgnoreCase("FAIL")
|| jsonObject2.getString("err_code") != null) {
log.info("View order results:" + jsonObject2);
/**Cancel the order*/
JSONObject json = new JSONObject();
json.put("appid", jsonObject.getString("appid"));
json.put("sub_mch_id", jsonObject.getString("sub_mch_id"));
json.put("mch_id", jsonObject.getString("mch_id"));
json.put("out_trade_no", jsonObject.getString("out_trade_no"));
json.put("nonce_str", WeChatTool.generatedString(32, true, true));
json.put("sign", WeChatTool.getSign(json, key, WeChatConstants.MD5));
JSONObject jsonObject1 = payReverse(jsonObject.getString("mch_id"), json, b);
log.info("Cancel the order results:" + jsonObject1);
}
}
}
/**
* 查询订单接口
*
* @param jsonObject 参数对象
* @return JSONObject
* @Author LiuYong
* @Date 2019/12/16 10:47
* @Description TODO 查询订单
**/
public static JSONObject facepayQuery(JSONObject jsonObject, String key, Boolean b) {
JSONObject json = new JSONObject();
json.put("appid", jsonObject.getString("appid"));
json.put("mch_id", jsonObject.getString("mch_id"));
json.put("sub_mch_id", jsonObject.getString("sub_mch_id"));
json.put("out_trade_no", jsonObject.getString("out_trade_no"));
json.put("nonce_str", WeChatTool.generatedString(32, true, true));
json.put("sign", WeChatTool.getSign(json, key, WeChatConstants.MD5));
String data = JsonAndXmlUtils.WxJsonToXml(json);
try {
CloseableHttpClient httpClient = notReadCertificate();
String s = HttpPost(b ? WeChatPayConstants.PAY_ORDERQUERY : WeChatPayConstants.PAY_FACEPAYQUERY, data, httpClient);
JSONObject jsonObject1 = JsonAndXmlUtils.xmlToJson(s);
log.info("view an order:" + jsonObject1.toJSONString());
return jsonObject1;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 退款订单(需要双向证书)
*
* @param mchId 微信支付分配的商户号
* @param jsonObject 参数对象
* @return JSONObject
* @Author LiuYong
* @Date 2019/12/12 11:19
* @Description TODO 退款订单(需要双向证书)
**/
public static JSONObject doRefundRequest(String mchId, JSONObject jsonObject) {
String data = JsonAndXmlUtils.WxJsonToXml(jsonObject);
try {
CloseableHttpClient httpClient = readCertificate(mchId);
String s = HttpPost(WeChatPayConstants.SECAPI_PAY_REFUND, data, httpClient);
return JsonAndXmlUtils.xmlToJson(s);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 查询退款接口
*
* @param jsonObject 参数对象
* @return JSONObject
* @Author LiuYong
* @Date 2019/12/16 10:47
* @Description TODO 查询退款接口
**/
public static JSONObject refundQuery(JSONObject jsonObject) {
String data = JsonAndXmlUtils.WxJsonToXml(jsonObject);
try {
CloseableHttpClient httpClient = notReadCertificate();
String s = HttpPost(WeChatPayConstants.PAY_REFUNDQUERY, data, httpClient);
return JsonAndXmlUtils.xmlToJson(s);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 刷脸支付撤销订单接口(需要双向证书)
*
* @param mchId 微信支付分配的商户号
* @param jsonObject 参数对象
* @param b true为扫码,false为刷脸
* @return JSONObject
* @Author LiuYong
* @Date 2019/12/12 11:19
* @Description TODO 撤销订单(需要双向证书)
**/
public static JSONObject payReverse(String mchId, JSONObject jsonObject, Boolean b) {
String data = JsonAndXmlUtils.WxJsonToXml(jsonObject);
try {
CloseableHttpClient httpClient = readCertificate(mchId);
String s = HttpPost(b ? WeChatPayConstants.SECAPI_PAY_REVERSE : WeChatPayConstants.SECAPI_PAY_FACEPAYREVERSE, data, httpClient);
JSONObject jsonObject1 = JsonAndXmlUtils.xmlToJson(s);
log.info("Cancellation result:" + jsonObject1.toJSONString());
return jsonObject1;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 下载对账单
*
* @param jsonObject 请求参数
* @return String
* @Author LiuYong
* @Date 2019/12/12 11:18
* @Description TODO 下载对账单
**/
public static JSONObject doDownloadbill(JSONObject jsonObject) {
try {
String data = JsonAndXmlUtils.WxJsonToXml(jsonObject);
CloseableHttpClient httpClient = notReadCertificate();
String s = HttpPost(WeChatPayConstants.PAY_DOWNLOADBILL, data, httpClient);
return JsonAndXmlUtils.xmlToJson(s);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**-----------------------------------PAIVATE----------------------------------------------------*/
/**
* 双向证书请求
*
* @param mchId 微信支付分配的商户号
* @param url 请求地址
* @param jsonObject 参数
* @return 结果
* @Author LiuYong
* @Date 2019/12/12 11:58
* @Description TODO 双向证书请求,请求地址及参数处理
**/
private static String twoWayRequest(String mchId, String url, JSONObject jsonObject) {
try {
String data = JsonAndXmlUtils.WxJsonToXml(jsonObject);
/**小程序下载资金账单需要调用双向证书的认证*/
CloseableHttpClient httpClient = readCertificate(mchId);
return HttpPost(url, data, httpClient);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 请求
*
* @param url
* @param data
* @param httpClient
* @return
* @throws Exception
*/
protected static String HttpPost(String url, String data, CloseableHttpClient httpClient) throws IOException {
try {
/**设置响应头信息*/
HttpPost httpost = new HttpPost(WeChatPayConstants.DOMAIN_API + url);
httpost.addHeader("Connection", "keep-alive");
httpost.addHeader("Accept", "*/*");
httpost.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
httpost.addHeader("Host", "api.mch.weixin.qq.com");
httpost.addHeader("X-Requested-With", "XMLHttpRequest");
httpost.addHeader("Cache-Control", "max-age=0");
httpost.addHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) ");
httpost.setEntity(new StringEntity(data, "UTF-8"));
/**超时时间设置*/
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(5000).setSocketTimeout(5000).build();
httpost.setConfig(requestConfig);
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();
}
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
httpClient.close();
}
}
/**
* 微信小程序读取双向证书
*
* @param mchId 微信支付分配的商户号
* @return CloseableHttpClient
* @Author LiuYong
* @Date 2019/12/12 11:21
* @Description TODO 微信小程序读取双向证书
**/
private static CloseableHttpClient readCertificate(String mchId) throws Exception {
/**
* Note that the PKCS12 certificate is downloaded from WeChat merchant platform - "account Settings -" API security
*/
KeyStore keyStore = KeyStore.getInstance("PKCS12");
/**P12 file directory certificate path, here you need to modify, Linux or Windows under the root path*/
log.info("P12文件目录filepath->" + PathUtil.getPath("P12"));
FileInputStream instream = new FileInputStream(PathUtil.getPath("P12") + "/apiclient_cert.p12");
try {
/**这里写密码..默认是你的MCHID*/
keyStore.load(instream, mchId.toCharArray());
} finally {
instream.close();
}
// Trust own CA and all self-signed certs
/**这里也是写密码的*/
SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, mchId.toCharArray()).build();
// Allow TLSv1 protocol only
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, SSLConnectionSocketFactory.getDefaultHostnameVerifier());
return HttpClients.custom().setSSLSocketFactory(sslsf).build();
}
/**
* 微信小程序不读取双向证书
*
* @param
* @return
* @Author LiuYong
* @Date 2019/12/12 11:20
* @Description TODO 微信小程序不读取双向证书
**/
protected static CloseableHttpClient notReadCertificate() throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
CloseableHttpClient httpClient = null;
SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
/**信任所有*/
@Override
public boolean isTrusted(X509Certificate[] chain, String authType) {
return true;
}
}).build();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext);
httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
return httpClient;
}
}
今天的分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。