地址:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_4&index=3
springboot项目pom.xml配置文件:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.1.3.RELEASEversion>
<relativePath/>
parent>
<groupId>com.majkergroupId>
<artifactId>wxPayDemoartifactId>
<version>0.0.1-SNAPSHOTversion>
<name>wxPayDemoname>
<description>Demo project for Spring Bootdescription>
<properties>
<java.version>1.8java.version>
<commons-lang3.version>3.5commons-lang3.version>
<commons-io.version>2.4commons-io.version>
<lombok.version>1.16.18lombok.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-redisartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>org.apache.httpcomponentsgroupId>
<artifactId>httpclientartifactId>
<version>4.5.3version>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-apiartifactId>
<version>1.7.21version>
dependency>
<dependency>
<groupId>io.swaggergroupId>
<artifactId>swagger-annotationsartifactId>
<version>1.5.9version>
<scope>compilescope>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>fastjsonartifactId>
<version>1.1.40version>
dependency>
<dependency>
<groupId>org.apache.commonsgroupId>
<artifactId>commons-lang3artifactId>
<version>${commons-lang3.version}version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>${lombok.version}version>
<optional>trueoptional>
dependency>
<dependency>
<groupId>commons-iogroupId>
<artifactId>commons-ioartifactId>
<version>${commons-io.version}version>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
project>
package com.majker.common.config;
/****************************************************
*
* 微信小程序 配置
*
*
* @author majker
* @date 2019-02-25 10:17
* @version 1.0
**************************************************/
public class WxProgramPayConfig {
/**
* AppID(小程序ID)
*/
public static final String APPID = "";
/**
* AppSecret(小程序密钥)
*/
public static final String SECRET="";
public static String MCH_ID = "";
/**
* 回调地址
*/
public static String NOTIFY_URL = "";
public static String KEY = "";
}
参数详情请看下图,(来源:小程序账号申请微信支付过程中获取的)
package com.majker.common.util;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import java.io.Serializable;
import java.security.SecureRandom;
import java.util.UUID;
/****************************************************
*
* 封装各种生成唯一性ID算法的工具类.
*
* @author majker
* @date: 2016-01-15
* @version 1.0
**************************************************/
@Service
@Lazy(false)
public class IdGen implements Serializable{
private static SecureRandom random = new SecureRandom();
/**
* 封装JDK自带的UUID, 通过Random数字生成, 中间无-分割.
*/
public static String uuid() {
return UUID.randomUUID().toString().replaceAll("-", "");
}
/**
* 使用SecureRandom随机生成Long.
*/
public static long randomLong() {
return Math.abs(random.nextLong());
}
}
package com.majker.common.util;
import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.annotation.JsonIgnore;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.*;
/****************************************************
*
* 响应结果
*
* @author majker
* @date: 2018/2/10
* @version 1.0
**************************************************/
public class Render<T> implements Serializable {
private String msg;
private T data;
private int code;
private Boolean error;
private Long timestamp;
private static Map map;
public String getMsg() {
return msg;
}
public int getCode() {
return code;
}
public T getData() {
return data;
}
public Boolean getError() {
return error;
}
public Long getTimestamp() {
return timestamp;
}
public static <T> Render<T> fail(String message) {
Render<T> msg = new Render<>();
msg.msg = message;
msg.code(ResultCode.EXCEPTION.val());
msg.error(true);
return msg.putTimeStamp();
}
public static <T> Render<T> fail(ResultCode resultCode) {
Render<T> msg = new Render<>();
msg.msg = resultCode.msg();
msg.code(resultCode.val());
msg.error(true);
return msg.putTimeStamp();
}
public static <T> Render<T> ok() {
return ok(null);
}
private Render<T> putTimeStamp() {
this.timestamp = System.currentTimeMillis();
return this;
}
public static <T> Render<T> ok(T data) {
return new Render<T>()
.data(data)
.putTimeStamp()
.error(false)
.msg(ResultCode.SUCCESS.msg())
.code(ResultCode.SUCCESS.val());
}
public static <T> Render<T> ok(T data, String msg) {
return new Render<T>()
.data(data)
.putTimeStamp()
.error(false)
.msg(msg)
.code(ResultCode.SUCCESS.val());
}
public static Map okMap(Object data) {
map = new HashMap();
map.put("data", data);
map.put("error", false);
map.put("code", ResultCode.SUCCESS.val());
map.put("msg", ResultCode.SUCCESS.msg());
map.put("timestamp", System.currentTimeMillis());
return map;
}
public static Map failMap(String msg) {
map = new HashMap();
map.put("data", null);
map.put("error", true);
map.put("code", ResultCode.EXCEPTION.val());
map.put("msg", msg);
map.put("timestamp", System.currentTimeMillis());
return map;
}
public static Map failMap(ResultCode resultCode) {
map = new HashMap();
map.put("data", null);
map.put("error", true);
map.put("code", resultCode.val());
map.put("msg", resultCode.msg());
map.put("timestamp", System.currentTimeMillis());
return map;
}
public Render<T> data(T data) {
this.data = data;
return this;
}
public Render<T> code(int code) {
this.code = code;
return this;
}
public Render<T> error(Boolean error) {
this.error = error;
return this;
}
public Render<T> msg(String msg) {
this.msg = msg;
return this;
}
/**
* 过滤字段:指定需要序列化的字段
*/
@JsonIgnore
private transient Map<Class<?>, Set<String>> includes;
/**
* 过滤字段:指定不需要序列化的字段
*/
@JsonIgnore
private transient Map<Class<?>, Set<String>> excludes;
public Render() {
}
public Render<T> include(Class<?> type, String... fields) {
return include(type, Arrays.asList(fields));
}
public Render<T> include(Class<?> type, Collection<String> fields) {
if (includes == null)
includes = new HashMap<>();
if (fields == null || fields.isEmpty()) return this;
fields.forEach(field -> {
if (field.contains(".")) {
String tmp[] = field.split("[.]", 2);
try {
Field field1 = type.getDeclaredField(tmp[0]);
if (field1 != null) {
include(field1.getType(), tmp[1]);
}
} catch (Throwable e) {
}
} else {
getStringListFromMap(includes, type).add(field);
}
});
return this;
}
public Render<T> exclude(Class type, Collection<String> fields) {
if (excludes == null)
excludes = new HashMap<>();
if (fields == null || fields.isEmpty()) return this;
fields.forEach(field -> {
if (field.contains(".")) {
String tmp[] = field.split("[.]", 2);
try {
Field field1 = type.getDeclaredField(tmp[0]);
if (field1 != null) {
exclude(field1.getType(), tmp[1]);
}
} catch (Throwable e) {
}
} else {
getStringListFromMap(excludes, type).add(field);
}
});
return this;
}
public Render<T> exclude(Collection<String> fields) {
if (excludes == null)
excludes = new HashMap<>();
if (fields == null || fields.isEmpty()) return this;
Class type;
if (getData() != null) type = getData().getClass();
else return this;
exclude(type, fields);
return this;
}
public Render<T> include(Collection<String> fields) {
if (includes == null)
includes = new HashMap<>();
if (fields == null || fields.isEmpty()) return this;
Class type;
if (getData() != null) type = getData().getClass();
else return this;
include(type, fields);
return this;
}
public Render<T> exclude(Class type, String... fields) {
return exclude(type, Arrays.asList(fields));
}
public Render<T> exclude(String... fields) {
return exclude(Arrays.asList(fields));
}
public Render<T> include(String... fields) {
return include(Arrays.asList(fields));
}
protected Set<String> getStringListFromMap(Map<Class<?>, Set<String>> map, Class type) {
return map.computeIfAbsent(type, k -> new HashSet<>());
}
@Override
public String toString() {
return JSON.toJSONStringWithDateFormat(this, "yyyy-MM-dd HH:mm:ss");
}
public Map<Class<?>, Set<String>> getExcludes() {
return excludes;
}
public Map<Class<?>, Set<String>> getIncludes() {
return includes;
}
}
package com.majker.common.util;
import java.io.Serializable;
/****************************************************
*
* 响应码
*
* @author majker
* @date: 2019/3/10
* @version 1.0
**************************************************/
public enum ResultCode implements Serializable{
/** 成功 */
SUCCESS(200, "成功"),
/** 发生异常 */
EXCEPTION(500, "发生异常"),
NO_AUTH(401,"请重新登录"),
FORBIDDEN(403,"未认证"),
NULL(403,"禁止"),
NOT_BIND(1234,"请先绑定手机号"),
NOT_FOUND(404,"未找到相应文件");
ResultCode(int value, String msg){
this.val = value;
this.msg = msg;
}
public int val() {
return val;
}
public String msg() {
return msg;
}
private int val;
private String msg;
}
使用的官方的sdk和自己编写的代码,相关类如下,下载下方给的demo
package com.majker.common.sdk;
import javax.net.ssl.*;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.security.*;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Iterator;
import java.util.Map;
public class HttpKit {
private static final String GET = "GET";
private static final String POST = "POST";
private static String CHARSET = "UTF-8";
private static final SSLSocketFactory sslSocketFactory = initSSLSocketFactory();
private static final TrustAnyHostnameVerifier trustAnyHostnameVerifier = new HttpKit().new TrustAnyHostnameVerifier();
// public static final OkHttp3Delegate delegate = new OkHttp3Delegate();
private HttpKit() {
}
private static SSLSocketFactory initSSLSocketFactory() {
try {
TrustManager[] e = new TrustManager[]{new HttpKit().new TrustAnyTrustManager()};
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init((KeyManager[])null, e, new SecureRandom());
return sslContext.getSocketFactory();
} catch (Exception var2) {
throw new RuntimeException(var2);
}
}
public static void setCharSet(String charSet) {
if(charSet!=null && !charSet.equals("")) {
throw new IllegalArgumentException("charSet can not be blank.");
} else {
CHARSET = charSet;
}
}
private static HttpURLConnection getHttpConnection(String url, String method, Map<String, String> headers) throws IOException, NoSuchAlgorithmException, NoSuchProviderException, KeyManagementException {
URL _url = new URL(url);
HttpURLConnection conn = (HttpURLConnection)_url.openConnection();
if(conn instanceof HttpsURLConnection) {
((HttpsURLConnection)conn).setSSLSocketFactory(sslSocketFactory);
((HttpsURLConnection)conn).setHostnameVerifier(trustAnyHostnameVerifier);
}
conn.setRequestMethod(method);
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setConnectTimeout(19000);
conn.setReadTimeout(19000);
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
conn.setRequestProperty("AuthUser-Agent", "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.146 Safari/537.36");
if(headers != null && !headers.isEmpty()) {
Iterator i$ = headers.entrySet().iterator();
while(i$.hasNext()) {
Map.Entry entry = (Map.Entry)i$.next();
conn.setRequestProperty((String)entry.getKey(), (String)entry.getValue());
}
}
return conn;
}
public static String get(String url, Map<String, String> queryParas, Map<String, String> headers) {
HttpURLConnection conn = null;
String e;
try {
conn = getHttpConnection(buildUrlWithQueryString(url, queryParas), "GET", headers);
conn.connect();
e = readResponseString(conn);
} catch (Exception var8) {
throw new RuntimeException(var8);
} finally {
if(conn != null) {
conn.disconnect();
}
}
return e;
}
public static String get(String url, Map<String, String> queryParas) {
return get(url, queryParas, (Map)null);
}
public static String get(String url) {
return get(url, (Map)null, (Map)null);
}
public static String post(String url, Map<String, String> queryParas, String data, Map<String, String> headers) {
HttpURLConnection conn = null;
String var6;
try {
conn = getHttpConnection(buildUrlWithQueryString(url, queryParas), "POST", headers);
conn.connect();
OutputStream e = conn.getOutputStream();
e.write(data.getBytes(CHARSET));
e.flush();
e.close();
var6 = readResponseString(conn);
} catch (Exception var10) {
throw new RuntimeException(var10);
} finally {
if(conn != null) {
conn.disconnect();
}
}
return var6;
}
public static String post(String url, Map<String, String> queryParas, String data) {
return post(url, queryParas, data, (Map)null);
}
public static String post(String url, String data, Map<String, String> headers) {
return post(url, (Map)null, data, headers);
}
public static String post(String url, String data) {
return post(url, (Map)null, data, (Map)null);
}
private static String readResponseString(HttpURLConnection conn) {
StringBuilder sb = new StringBuilder();
InputStream inputStream = null;
try {
inputStream = conn.getInputStream();
BufferedReader e = new BufferedReader(new InputStreamReader(inputStream, CHARSET));
String line = null;
while((line = e.readLine()) != null) {
sb.append(line).append("\n");
}
String var5 = sb.toString();
return var5;
} catch (Exception var14) {
throw new RuntimeException(var14);
} finally {
if(inputStream != null) {
try {
inputStream.close();
} catch (IOException var13) {
}
}
}
}
private static String buildUrlWithQueryString(String url, Map<String, String> queryParas) {
if(queryParas != null && !queryParas.isEmpty()) {
StringBuilder sb = new StringBuilder(url);
boolean isFirst;
if(url.indexOf("?") == -1) {
isFirst = true;
sb.append("?");
} else {
isFirst = false;
}
String key;
String value;
for(Iterator i$ = queryParas.entrySet().iterator(); i$.hasNext(); sb.append(key).append("=").append(value)) {
Map.Entry entry = (Map.Entry)i$.next();
if(isFirst) {
isFirst = false;
} else {
sb.append("&");
}
key = (String)entry.getKey();
value = (String)entry.getValue();
if(value!=null && !value.equals("")) {
try {
value = URLEncoder.encode(value, CHARSET);
} catch (UnsupportedEncodingException var9) {
throw new RuntimeException(var9);
}
}
}
return sb.toString();
} else {
return url;
}
}
public static String readData(HttpServletRequest request) {
BufferedReader br = null;
try {
StringBuilder e = new StringBuilder();
br = request.getReader();
String line = null;
while((line = br.readLine()) != null) {
e.append(line).append("\n");
}
line = e.toString();
return line;
} catch (IOException var12) {
throw new RuntimeException(var12);
} finally {
if(br != null) {
try {
br.close();
} catch (IOException var11) {
}
}
}
}
/** @deprecated */
@Deprecated
public static String readIncommingRequestData(HttpServletRequest request) {
return readData(request);
}
private class TrustAnyTrustManager implements X509TrustManager {
private TrustAnyTrustManager() {
}
public X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
}
private class TrustAnyHostnameVerifier implements HostnameVerifier {
private TrustAnyHostnameVerifier() {
}
public boolean verify(String hostname, SSLSession session) {
return true;
}
}
}
package com.majker.common.sdk;
import org.apache.commons.io.Charsets;
import java.io.*;
import java.nio.charset.Charset;
/**
* IOUtils
* @author majker
*/
public abstract class IOUtils {
private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
/**
* closeQuietly
* @param closeable 自动关闭
*/
public static void closeQuietly(Closeable closeable) {
try {
if (closeable != null) {
closeable.close();
}
} catch (IOException ioe) {
// ignore
}
}
/**
* InputStream to String utf-8
*
* @param input the InputStream
to read from
* @return the requested String
* @throws NullPointerException if the input is null
* @throws IOException if an I/O error occurs
*/
public static String toString(InputStream input) throws IOException {
return toString(input, Charsets.UTF_8);
}
/**
* InputStream to String
*
* @param input the InputStream
to read from
* @param charset the Charset
* @return the requested String
* @throws NullPointerException if the input is null
* @throws IOException if an I/O error occurs
*/
public static String toString(InputStream input, Charset charset) throws IOException {
InputStreamReader in = new InputStreamReader(input, charset);
StringBuffer out = new StringBuffer();
char[] c = new char[DEFAULT_BUFFER_SIZE];
for (int n; (n = in.read(c)) != -1;) {
out.append(new String(c, 0, n));
}
IOUtils.closeQuietly(in);
IOUtils.closeQuietly(input);
return out.toString();
}
/**
* InputStream to File
* @param input the InputStream
to read from
* @param file the File to write
* @throws IOException id异常
*/
public static void toFile(InputStream input, File file) throws IOException {
OutputStream os = new FileOutputStream(file);
int bytesRead = 0;
byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
while ((bytesRead = input.read(buffer, 0, DEFAULT_BUFFER_SIZE)) != -1) {
os.write(buffer, 0, bytesRead);
}
IOUtils.closeQuietly(os);
IOUtils.closeQuietly(input);
}
}
package com.majker.common.sdk;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;
/****************************************************
*
* 微信支付api
*
* @author majker
* @version 1.0
**************************************************/
public class PaymentApi {
private PaymentApi() {}
// 文档地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1
private static String unifiedOrderUrl = "https://api.mch.weixin.qq.com/pay/unifiedorder";
/**
* 交易类型枚举
* WAP的文档:https://pay.weixin.qq.com/wiki/doc/api/wap.php?chapter=15_1
* @author L.cm
*
* email: [email protected]
* site: http://www.dreamlu.net
* date: 2015年10月27日 下午9:46:27
*
*/
public enum TradeType {
JSAPI, NATIVE, APP, WAP, MWEB
}
/**
* 统一下单
* @param params 参数map
* @return String
*/
public static String pushOrder(Map<String, String> params) {
return HttpKit.post(unifiedOrderUrl, PaymentKit.toXml(params));
}
private static Map<String, String> request(String url, Map<String, String> params, String paternerKey) {
params.put("nonce_str", System.currentTimeMillis() + "");
String sign = PaymentKit.createSign(params, paternerKey);
params.put("sign", sign);
String xmlStr = HttpKit.post(url, PaymentKit.toXml(params));
return PaymentKit.xmlToMap(xmlStr);
}
/**
* 文档说明:https://pay.weixin.qq.com/wiki/doc/api/wap.php?chapter=15_4
*
* @param appId 公众账号ID 是 String(32) wx8888888888888888 微信分配的公众账号ID
* 随机字符串 noncestr 是 String(32) 5K8264ILTKCH16CQ2502SI8ZNMTM67VS 随机字符串,不长于32位。推荐随机数生成算法
* 订单详情扩展字符串 package 是 String(32) WAP 扩展字段,固定填写WAP
* @param prepayId 预支付交易会话标识 是 String(64) wx201410272009395522657a690389285100 微信统一下单接口返回的预支付回话标识,用于后续接口调用中使用,该值有效期为2小时
* 签名 sign 是 String(32) C380BEC2BFD727A4B6845133519F3AD6 签名,详见签名生成算法
* 时间戳 timestamp 是 String(32) 1414561699 当前的时间,其他详见时间戳规则
* @param paternerKey 签名密匙
*
* @return {String}
*/
public static String getDeepLink(String appId, String prepayId, String paternerKey) {
Map<String, String> params = new HashMap<String, String>();
params.put("appid", appId);
params.put("noncestr", System.currentTimeMillis() + "");
params.put("package", "WAP");
params.put("prepayid", prepayId);
params.put("timestamp", System.currentTimeMillis() / 1000 + "");
String sign = PaymentKit.createSign(params, paternerKey);
params.put("sign", sign);
String string1 = PaymentKit.packageSign(params, true);
String string2 = "";
try { string2 = PaymentKit.urlEncode(string1); } catch (UnsupportedEncodingException e) {}
return "weixin://wap/pay?" + string2;
}
// 文档地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_2
private static String orderQueryUrl = "https://api.mch.weixin.qq.com/pay/orderquery";
/**
* 根据商户订单号查询信息
* @param appid 公众账号ID
* @param mch_id 商户号
* @param paternerKey 商户密钥
* @param transaction_id 微信订单号
* @return 回调信息
*/
public static Map<String, String> queryByTransactionId(String appid, String mch_id, String paternerKey, String transaction_id) {
Map<String, String> params = new HashMap<String, String>();
params.put("appid", appid);
params.put("mch_id", mch_id);
params.put("transaction_id", transaction_id);
return request(orderQueryUrl, params, paternerKey);
}
/**
* 根据商户订单号查询信息
* @param appid 公众账号ID
* @param mch_id 商户号
* @param paternerKey 商户密钥
* @param out_trade_no 商户订单号
* @return 回调信息
*/
public static Map<String, String> queryByOutTradeNo(String appid, String mch_id, String paternerKey, String out_trade_no) {
Map<String, String> params = new HashMap<String, String>();
params.put("appid", appid);
params.put("mch_id", mch_id);
params.put("out_trade_no", out_trade_no);
return request(orderQueryUrl, params, paternerKey);
}
// 文档地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_3
private static String closeOrderUrl = "https://api.mch.weixin.qq.com/pay/closeorder";
/**
* 关闭订单
* @param appid 公众账号ID
* @param mch_id 商户号
* @param paternerKey 商户密钥
* @param out_trade_no 商户订单号
* @return 回调信息
*/
public static Map<String, String> closeOrder(String appid, String mch_id, String paternerKey, String out_trade_no) {
Map<String, String> params = new HashMap<String, String>();
params.put("appid", appid);
params.put("mch_id", mch_id);
params.put("out_trade_no", out_trade_no);
return request(closeOrderUrl, params, paternerKey);
}
// 申请退款文档地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_4
public static String refundUrl = "https://api.mch.weixin.qq.com/secapi/pay/refund";
// 查询退款文档地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_5
private static String refundQueryUrl = "https://api.mch.weixin.qq.com/pay/refundquery";
private static Map<String, String> baseRefundQuery(Map<String, String> params, String appid, String mch_id, String paternerKey) {
params.put("appid", appid);
params.put("mch_id", mch_id);
return request(refundQueryUrl, params, paternerKey);
}
/**
* 根据微信订单号查询退款
* @param appid 公众账号ID
* @param mch_id 商户号
* @param paternerKey 商户密钥
* @param transaction_id 微信订单号
* @return map
*/
public static Map<String, String> refundQueryByTransactionId(String appid, String mch_id, String paternerKey, String transaction_id) {
Map<String, String> params = new HashMap<String, String>();
params.put("transaction_id", transaction_id);
return baseRefundQuery(params, appid, mch_id, paternerKey);
}
/**
* 根据微信订单号查询退款
* @param appid 公众账号ID
* @param mch_id 商户号
* @param paternerKey 商户密钥
* @param out_trade_no 商户订单号
* @return map
*/
public static Map<String, String> refundQueryByOutTradeNo(String appid, String mch_id, String paternerKey, String out_trade_no) {
Map<String, String> params = new HashMap<String, String>();
params.put("out_trade_no", out_trade_no);
return baseRefundQuery(params, appid, mch_id, paternerKey);
}
/**
* 根据微信订单号查询退款
* @param appid 公众账号ID
* @param mch_id 商户号
* @param paternerKey 商户密钥
* @param out_refund_no 商户退款单号
* @return map
*/
public static Map<String, String> refundQueryByOutRefundNo(String appid, String mch_id, String paternerKey, String out_refund_no) {
Map<String, String> params = new HashMap<String, String>();
params.put("out_refund_no", out_refund_no);
return baseRefundQuery(params, appid, mch_id, paternerKey);
}
/**
* 根据微信订单号查询退款
* @param appid 公众账号ID
* @param mch_id 商户号
* @param paternerKey 商户密钥
* @param refund_id 微信退款单号
* @return map
*/
public static Map<String, String> refundQueryByRefundId(String appid, String mch_id, String paternerKey, String refund_id) {
Map<String, String> params = new HashMap<String, String>();
params.put("refund_id", refund_id);
return baseRefundQuery(params, appid, mch_id, paternerKey);
}
private static String downloadBillUrl = "https://api.mch.weixin.qq.com/pay/downloadbill";
/**
*
* ALL,返回当日所有订单信息,默认值
* SUCCESS,返回当日成功支付的订单
* REFUND,返回当日退款订单
* REVOKED,已撤销的订单
*
*/
public static enum BillType {
ALL, SUCCESS, REFUND, REVOKED
}
/**
* 下载对账单
*
* 公众账号ID appid 是 String(32) wx8888888888888888 微信分配的公众账号ID(企业号corpid即为此appId)
* 商户号 mch_id 是 String(32) 1900000109 微信支付分配的商户号
* 设备号 device_info 否 String(32) 013467007045764 微信支付分配的终端设备号
* 随机字符串 nonce_str 是 String(32) 5K8264ILTKCH16CQ2502SI8ZNMTM67VS 随机字符串,不长于32位。推荐随机数生成算法
* 签名 sign 是 String(32) C380BEC2BFD727A4B6845133519F3AD6 签名,详见签名生成算法
* 对账单日期 bill_date 是 String(8) 20140603 下载对账单的日期,格式:20140603
* 账单类型 bill_type 否 String(8)
*
* @param appid 公众账号ID
* @param mch_id 商户号
* @param paternerKey 签名密匙
* @param billDate 对账单日期
* @return String
*/
public static String downloadBill(String appid, String mch_id, String paternerKey, String billDate) {
return downloadBill(appid, mch_id, paternerKey, billDate, null);
}
/**
* 下载对账单
*
* 公众账号ID appid 是 String(32) wx8888888888888888 微信分配的公众账号ID(企业号corpid即为此appId)
* 商户号 mch_id 是 String(32) 1900000109 微信支付分配的商户号
* 设备号 device_info 否 String(32) 013467007045764 微信支付分配的终端设备号
* 随机字符串 nonce_str 是 String(32) 5K8264ILTKCH16CQ2502SI8ZNMTM67VS 随机字符串,不长于32位。推荐随机数生成算法
* 签名 sign 是 String(32) C380BEC2BFD727A4B6845133519F3AD6 签名,详见签名生成算法
* 对账单日期 bill_date 是 String(8) 20140603 下载对账单的日期,格式:20140603
* 账单类型 bill_type 否 String(8)
*
* @param appid 公众账号ID
* @param mch_id 商户号
* @param paternerKey 签名密匙
* @param billDate 对账单日期
* @param billType 账单类型
* @return String
*/
public static String downloadBill(String appid, String mch_id, String paternerKey, String billDate, BillType billType) {
Map<String, String> params = new HashMap<String, String>();
params.put("appid", appid);
params.put("mch_id", mch_id);
params.put("nonce_str", System.currentTimeMillis() + "");
params.put("bill_date", billDate);
if (null != billType) {
params.put("bill_type", billType.name());
} else {
params.put("bill_type", BillType.ALL.name());
}
String sign = PaymentKit.createSign(params, paternerKey);
params.put("sign", sign);
return HttpKit.post(downloadBillUrl, PaymentKit.toXml(params));
}
}
package com.majker.common.sdk;
import org.apache.commons.io.Charsets;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
/****************************************************
*
* 微信支付的统一下单工具类
*
* @author majker
* @version 1.0
**************************************************/
public class PaymentKit {
/**
* 组装签名的字段
* @param params 参数
* @param urlEncoder 是否urlEncoder
* @return String
*/
public static String packageSign(Map<String, String> params, boolean urlEncoder) {
// 先将参数以其参数名的字典序升序进行排序
TreeMap<String, String> sortedParams = new TreeMap<String, String>(params);
// 遍历排序后的字典,将所有参数按"key=value"格式拼接在一起
StringBuilder sb = new StringBuilder();
boolean first = true;
for (Entry<String, String> param : sortedParams.entrySet()) {
String value = param.getValue();
if (Tools.isEmpty(value)) {
continue;
}
if (first) {
first = false;
} else {
sb.append("&");
}
sb.append(param.getKey()).append("=");
if (urlEncoder) {
try { value = urlEncode(value); } catch (UnsupportedEncodingException e) {}
}
sb.append(value);
}
return sb.toString();
}
/**
* urlEncode
* @param src 微信参数
* @return String
* @throws UnsupportedEncodingException 编码错误
*/
public static String urlEncode(String src) throws UnsupportedEncodingException {
return URLEncoder.encode(src, Charsets.UTF_8.name()).replace("+", "%20");
}
/**
* 生成签名
* @param params 参数
* @param paternerKey 支付密钥
* @return sign
*/
public static String createSign(Map<String, String> params, String paternerKey) {
// 生成签名前先去除sign
params.remove("sign");
String stringA = packageSign(params, false);
String stringSignTemp = stringA + "&key=" + paternerKey;
return Tools.md5(stringSignTemp).toUpperCase();
}
/**
* 支付异步通知时校验sign
* @param params 参数
* @param paternerKey 支付密钥
* @return {boolean}
*/
public static boolean verifyNotify(Map<String, String> params, String paternerKey){
String sign = params.get("sign");
String localSign = PaymentKit.createSign(params, paternerKey);
return sign.equals(localSign);
}
/**
* 微信下单,map to xml
* @param params 参数
* @return String
*/
public static String toXml(Map<String, String> params) {
StringBuilder xml = new StringBuilder();
xml.append("" );
for (Entry<String, String> entry : params.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
// 略过空值
if (Tools.isEmpty(value)) continue;
xml.append("<").append(key).append(">");
xml.append(entry.getValue());
xml.append("").append(key).append(">");
}
xml.append("");
return xml.toString();
}
/**
* 针对支付的xml,没有嵌套节点的简单处理
* @param xmlStr xml字符串
* @return map集合
*/
public static Map<String, String> xmlToMap(String xmlStr) {
XmlHelper xmlHelper = XmlHelper.of(xmlStr);
return xmlHelper.toMap();
}
}
常用工具
package com.majker.common.sdk;
import java.security.MessageDigest;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/****************************************************
*
* 常用工具
*
* @author majker
* @version 1.0
**************************************************/
public class Tools {
/**
* 随机生成六位数验证码
* @return
*/
public static int getRandomNum(){
Random r = new Random();
return r.nextInt(900000)+100000;//(Math.random()*(999999-100000)+100000)
}
/**
* 检测字符串是否不为空(null,"","null")
* @param s
* @return 不为空则返回true,否则返回false
*/
public static boolean notEmpty(String s){
return s!=null && !"".equals(s) && !"null".equals(s);
}
/**
* 检测字符串是否为空(null,"","null")
* @param s
* @return 为空则返回true,不否则返回false
*/
public static boolean isEmpty(String s){
return s==null || "".equals(s) || "null".equals(s);
}
/**
* 字符串转换为字符串数组
* @param str 字符串
* @param splitRegex 分隔符
* @return
*/
public static String[] str2StrArray(String str,String splitRegex){
if(isEmpty(str)){
return null;
}
return str.split(splitRegex);
}
/**
* 用默认的分隔符(,)将字符串转换为字符串数组
* @param str 字符串
* @return
*/
public static String[] str2StrArray(String str){
return str2StrArray(str,",\\s*");
}
/**
* 按照yyyy-MM-dd HH:mm:ss的格式,日期转字符串
* @param date
* @return yyyy-MM-dd HH:mm:ss
*/
public static String date2Str(Date date){
return date2Str(date,"yyyy-MM-dd HH:mm:ss");
}
/**
* 按照yyyy-MM-dd HH:mm:ss的格式,字符串转日期
* @param date
* @return
*/
public static Date str2Date(String date){
if(notEmpty(date)){
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
return sdf.parse(date);
} catch (ParseException e) {
e.printStackTrace();
}
return new Date();
}else{
return null;
}
}
/**
* 按照参数format的格式,日期转字符串
* @param date
* @param format
* @return
*/
public static String date2Str(Date date,String format){
if(date!=null){
SimpleDateFormat sdf = new SimpleDateFormat(format);
return sdf.format(date);
}else{
return "";
}
}
/**
* 把时间根据时、分、秒转换为时间段
* @param StrDate
*/
public static String getTimes(String StrDate){
String resultTimes = "";
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date now;
try {
now = new Date();
Date date=df.parse(StrDate);
long times = now.getTime()-date.getTime();
long day = times/(24*60*60*1000);
long hour = (times/(60*60*1000)-day*24);
long min = ((times/(60*1000))-day*24*60-hour*60);
long sec = (times/1000-day*24*60*60-hour*60*60-min*60);
StringBuffer sb = new StringBuffer();
//sb.append("发表于:");
if(hour>0 ){
sb.append(hour+"小时前");
} else if(min>0){
sb.append(min+"分钟前");
} else{
sb.append(sec+"秒前");
}
resultTimes = sb.toString();
} catch (ParseException e) {
e.printStackTrace();
}
return resultTimes;
}
/**
* 验证邮箱
* @param email
* @return
*/
public static boolean checkEmail(String email){
boolean flag = false;
try{
String check = "^([a-z0-9A-Z]+[-|_|\\.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-zA-Z]{2,}$";
Pattern regex = Pattern.compile(check);
Matcher matcher = regex.matcher(email);
flag = matcher.matches();
}catch(Exception e){
flag = false;
}
return flag;
}
/**
* 验证手机号码
* @return
*/
public static boolean checkMobileNumber(String mobileNumber){
Pattern p = null;
Matcher m = null;
boolean b = false;
p = Pattern.compile("^[1][3,4,5,7,8][0-9]{9}$"); // 验证手机号
m = p.matcher(mobileNumber);
b = m.matches();
return b;
}
/**
* 将驼峰转下划线
* @param param
* @return
*/
public static String camelToUnderline(String param){
if (param==null||"".equals(param.trim())){
return "";
}
int len=param.length();
StringBuilder sb=new StringBuilder(len);
for (int i = 0; i < len; i++) {
char c=param.charAt(i);
if (Character.isUpperCase(c)){
sb.append("_");
sb.append(Character.toLowerCase(c));
}else{
sb.append(c);
}
}
return sb.toString();
}
/**
* 去掉下划线并将下划线后的首字母转为大写
* @param str
* @return
*/
public static String transformStr(String str){
//去掉数据库字段的下划线
if(str.contains("_")) {
String[] names = str.split("_");
String firstPart = names[0];
String otherPart = "";
for (int i = 1; i < names.length; i++) {
String word = names[i].replaceFirst(names[i].substring(0, 1), names[i].substring(0, 1).toUpperCase());
otherPart += word;
}
str = firstPart + otherPart;
}
return str;
}
/**
* 转换为map
* @param list
* @return
*/
public static List<Map<String,Object>> transformMap(List<Map<String,Object>> list){
List<Map<String,Object>> resultMapList = new ArrayList<>();
for (Map<String, Object> map : list) {
Map<String,Object> tempMap = new HashMap<>();
for (String s : map.keySet()) {
tempMap.put(transformStr(s),map.get(s));
}
resultMapList.add(tempMap);
}
return resultMapList;
}
public static String clearHtml(String content,int p) {
if(null==content) return "";
if(0==p) return "";
Pattern p_script;
Matcher m_script;
Pattern p_style;
Matcher m_style;
Pattern p_html;
Matcher m_html;
try {
String regEx_script = "<[\\s]*?script[^>]*?>[\\s\\S]*?<[\\s]*?\\/[\\s]*?script[\\s]*?>";
//定义script的正则表达式{或