700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > 微信小程序支付(后台java)简单详细教学

微信小程序支付(后台java)简单详细教学

时间:2021-12-29 12:32:22

相关推荐

微信小程序支付(后台java)简单详细教学

微信小程序支付(后台java)简单详细教学,新手入门

文章目录

微信小程序支付(后台java)简单详细教学,新手入门前言一、准备工作二、正式开始1.前端demo制作2.java代码编写3.工具类(粘贴使用)总结

前言

本文适用于有一定基础的开发者,简单易通。后台用的是java,我用的是springMVC,其他框架基本同理,前端就一个简单的demo。微信提供了v2和v3两种方式,本文基于v2版支付开发。


一、准备工作

准备支付需要的参数材料如下:

/*** 支付配置类* @author jsy* @version /12/24**/public class WechatConfig {//小程序appid(开发者在微信公众平台查询)public static final String appid ="";//小程序appkey(开发者在微信公众平台查询)public static final String APP_SECRET=""//微信支付的商户id(开发者在微信商户平台查询)public static final String mch_id = "";//微信支付的商户密钥(开发者在微信商户平台查询)public static final String key = "";//支付成功后的服务器回调url(后台随便的一个接口能接收到就行)public static final String notify_url = "";//签名方式,固定值public static final String SIGNTYPE = "MD5";//交易类型,小程序支付的固定值为JSAPIpublic static final String TRADETYPE = "JSAPI";//微信统一下单接口地址public static final String pay_url = "https://api.mch./pay/unifiedorder";}

二、正式开始

1.前端demo制作

index.wxml如下:

<view class="container"><view class="container"><input type="text" bindinput="getOrderCode" style="border:1px solid #ccc;" /><button type="primary" bindtap="pay">微信支付</button></view></view>

index.js如下:

const app = getApp()Page({data: {txtOrderCode: ''},pay: function () {var ordercode = this.data.txtOrderCode;wx.login({success: function (res) {if (res.code) {wx.request({url: 'http://192.168.3.33:8080/dangjian/app/wechatPay/wxPay',data: {code: res.code,//要去换取openid的登录凭证money: ordercode,//支付金额(主要是code和money其他都是业务参数可去掉)name:"", idCard:"",post:"",phone:"",receiverInfo:"",duesDate:"",partyOrg:"",agyCode:"",agyName:"",orderId:""},method: 'GET',success: function (res) {console.log(res.data)//通过接口返回的data,调用此方法唤起支付页面wx.requestPayment({//这里的参数和值基本都是固定,不用更改timeStamp: res.data.timeStamp,nonceStr: res.data.nonceStr,package: res.data.package,signType: 'MD5',paySign: res.data.paySign,success: function (res) {console.log("支付成功")console.log(res);},fail: function (res) {wx.showToast({title: '支付失败',icon:'none',duration:2000})},complete: function (res) {console.log('支付完成');var url = that.data.url;console.log('get url', url)if (res.errMsg == 'requestPayment:ok') {wx.showModal({title: '提示',content: '支付成功'});}}})}})} else {console.log('获取用户登录态失败!' + res.errMsg)}}});},getOrderCode: function (event) {console.log(event)this.setData({txtOrderCode: event.detail.value});},onLoad: function () {if (app.globalData.userInfo) {this.setData({userInfo: app.globalData.userInfo,hasUserInfo: true})} else if (this.data.canIUse){// 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回// 所以此处加入 callback 以防止这种情况app.userInfoReadyCallback = res => {this.setData({userInfo: res.userInfo,hasUserInfo: true})}} else {// 在没有 open-type=getUserInfo 版本的兼容处理wx.getUserInfo({success: res => {app.globalData.userInfo = res.userInfothis.setData({userInfo: res.userInfo,hasUserInfo: true})}})}},})

2.java代码编写

WxPayDto类:

package com.jeeplus.modules.app.pay.dto;import java.io.Serializable;/*** @author jsy* @description: 缴费entity* @date /12/24 15:47*/public class WxPayDto implements Serializable {private static final long serialVersionUID = 1L;private String partyOrg; private String duesDate; private String money; //缴费金额private String name; private String idCard;private String post;private String phone;private String orderId;private String receiverInfo;private String code;//获取openid临时凭证private String agyCode;private String agyName;public String getAgyCode() {return agyCode;}public void setAgyCode(String agyCode) {this.agyCode = agyCode;}public String getAgyName() {return agyName;}public void setAgyName(String agyName) {this.agyName = agyName;}public String getPartyOrg() {return partyOrg;}public void setPartyOrg(String partyOrg) {this.partyOrg = partyOrg;}public String getDuesDate() {return duesDate;}public void setDuesDate(String duesDate) {this.duesDate = duesDate;}public String getMoney() {return money;}public void setMoney(String money) {this.money = money;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getIdCard() {return idCard;}public void setIdCard(String idCard) {this.idCard = idCard;}public String getPost() {return post;}public void setPost(String post) {this.post = post;}public String getPhone() {return phone;}public void setPhone(String phone) {this.phone = phone;}public String getOrderId() {return orderId;}public void setOrderId(String orderId) {this.orderId = orderId;}public String getReceiverInfo() {return receiverInfo;}public void setReceiverInfo(String receiverInfo) {this.receiverInfo = receiverInfo;}public String getCode() {return code;}public void setCode(String code) {this.code = code;}}

业务代码如下:

@ApiOperation(value = "统一订单", notes = "统一订单")@ResponseBody@RequestMapping("wxPay")public String wxPay(WxPayDto dto, HttpServletRequest request) {Object result = new Object();try {//获取客户端的ip地址String spbill_create_ip = getIpAddr(request);//获取openidString openid = WeAppUtil.getOpenId(dto.getCode());//订单号 uuidString outTradeNo = IdGen.uuid();//支付业务result = wxPay(spbill_create_ip, openid, outTradeNo, dto);} catch (Exception e) {e.printStackTrace();}return PayUtil.toJson(result);}//获取IPprivate String getIpAddr(HttpServletRequest request) {String ip = request.getHeader("X-Forwarded-For");if (StringUtils.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)) {//多次反向代理后会有多个ip值,第一个ip才是真实ipint index = ip.indexOf(",");if (index != -1) {return ip.substring(0, index);} else {return ip;}}ip = request.getHeader("X-Real-IP");if (StringUtils.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)) {return ip;}return request.getRemoteAddr();}/*** 缴纳费用** @author jsy* @version /12/24**/public Map wxPay(String spbill_create_ip, String openId, String orderNumber, WxPayDto dto) {Map<String, String> payMap = new HashMap<String, String>();//返回给小程序端需要的参数try {logger.info("【小程序支付】 统一下单开始, 订单编号=" + orderNumber);//商品名称String body = dto.getAgyName() + "-" + dto.getName() + "-测试费用";//获取客户端的ip地址BigDecimal ¥ = new BigDecimal(dto.getMoney());//组装参数,用户生成统一下单接口的签名logger.info("----------下单接口签名-------");Map<String, String> packageParams = new HashMap<>();//微信分配的小程序IDpackageParams.put("appid", WechatConfig.appid);//微信支付分配的商户号packageParams.put("mch_id", WechatConfig.mch_id);//随机字符串packageParams.put("nonce_str", System.currentTimeMillis() / 1000 + "");//签名类型packageParams.put("sign_type", "MD5");//充值订单 商品描述packageParams.put("body", body);//商户订单号packageParams.put("out_trade_no", orderNumber);//订单总金额,单位为分packageParams.put("total_fee", ¥.multiply(BigDecimal.valueOf(100)).intValue() + "");//终端IPpackageParams.put("spbill_create_ip", spbill_create_ip);//通知回调地址packageParams.put("notify_url", WechatConfig.notify_url);//交易类型packageParams.put("trade_type", WechatConfig.TRADETYPE);//用户标识packageParams.put("openid", openId);//第一次签名String sign = WXPayUtil.generateSignature(packageParams, WechatConfig.key);packageParams.put("sign", sign);//调用支付定义下单API,返回预付单信息 prepay_idString result = HttpKit.post(WechatConfig.pay_url, PaymentKit.toXml(packageParams));logger.info("调试模式_统一下单接口 返回XML数据:" + result);// 将解析结果存储在HashMap中Map<String, String> map = PaymentKit.xmlToMap(result);String return_code = map.get("return_code");//返回状态码String result_code = map.get("result_code");//返回状态码if (return_code.equals("SUCCESS") || return_code.equals(result_code)) {//返回的预付单信息String prepay_id = map.get("prepay_id");payMap.put("appId", WechatConfig.appid);payMap.put("timeStamp", System.currentTimeMillis() / 1000 + "");payMap.put("nonceStr", System.currentTimeMillis() + "");payMap.put("package", "prepay_id=" + prepay_id);payMap.put("signType", "MD5");//再次签名,这个签名用于小程序端调用wx.requesetPayment方法String paySign = WXPayUtil.generateSignature(payMap, WechatConfig.key);logger.info("=======================第二次签名:", paySign + "============ ======");payMap.put("paySign", paySign);payMap.put("status", "success");//更新订单信息} else {logger.info("----------统一下单失败-------");payMap.put("status", "error");return payMap;}} catch (Exception e) {e.printStackTrace();}return payMap;}/*** 小程序获取openid* @return*/public static String getOpenId(String code) throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {RestTemplate restTemplate = new RestTemplate(factory());String url = "https://api./sns/jscode2session?appid="+APP_KEY+"&secret="+APP_SECRET+"&js_code="+code+"&grant_type=authorization_code";ResponseEntity<String> responseEntity =restTemplate.getForEntity(url, String.class);String body = responseEntity.getBody();JSONObject object = JSON.parseObject(body);String openId = object.getString("openid");// 获取openIdSystem.out.println("该用户的openid——>"+openId);return openId;}

回调类

/*** 功能描述: <小程序回调>* @return:* @auther: jsy* @date: /12/25**/@RequestMapping("/wxProPayNotify")public void wxProPayNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {logger.info("进入微信小程序支付回调");String xmlMsg = HttpKit.readData(request);logger.info("微信小程序通知信息"+xmlMsg);Map<String, String> resultMap = PaymentKit.xmlToMap(xmlMsg);if(resultMap.get(RETURN_CODE).equals(SUCCESS)){String orderNo = resultMap.get("out_trade_no");logger.info("微信小程序支付成功,订单号{}",orderNo);//通过订单号 修改数据库中的记录,业务操作 }String result = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";try {response.getWriter().write(result);} catch (IOException e) {e.printStackTrace();}}


3.工具类(粘贴使用)

http,https-request类

package com.jeeplus.modules.app.pay.util;import .ssl.*;import javax.servlet.http.HttpServletRequest;import java.io.*;import .HttpURLConnection;import .URL;import .URLEncoder;import java.security.KeyManagementException;import java.security.NoSuchAlgorithmException;import java.security.NoSuchProviderException;import java.security.SecureRandom;import java.security.cert.CertificateException;import java.security.cert.X509Certificate;import java.util.Iterator;import java.util.Map;/*** http,https-request类* @author jsy* @version /12/24**/public class HttpKit {private static String CHARSET = "UTF-8";private static final SSLSocketFactory sslSocketFactory = initSSLSocketFactory();private static final TrustAnyHostnameVerifier trustAnyHostnameVerifier = new HttpKit().new TrustAnyHostnameVerifier();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 */@Deprecatedpublic 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;}}}

微信支付api

package com.jeeplus.modules.app.pay.util;import java.io.UnsupportedEncodingException;import java.util.HashMap;import java.util.Map;/*** 微信支付api* @author jsy* @version /12/25**/public class PaymentApi {private PaymentApi() {}// 文档地址:https://pay./wiki/doc/api/jsapi.php?chapter=9_1private static String unifiedOrderUrl = "https://api.mch./pay/unifiedorder";/*** 交易类型枚举* WAP的文档:https://pay./wiki/doc/api/wap.php?chapter=15_1* @author L.cm* <pre>* email: 596392912@* site: * date: 10月27日 下午9:46:27* </pre>*/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./wiki/doc/api/wap.php?chapter=15_4* <pre>* @param appId 公众账号ID 是 String(32) wx8888888888888888 微信分配的公众账号ID* 随机字符串 noncestr 是 String(32) 5K8264ILTKCH16CQ2502SI8ZNMTM67VS 随机字符串,不长于32位。推荐随机数生成算法* 订单详情扩展字符串 package 是 String(32) WAP 扩展字段,固定填写WAP* @param prepayId 预支付交易会话标识 是 String(64) wx1027395522657a690389285100 微信统一下单接口返回的预支付回话标识,用于后续接口调用中使用,该值有效期为2小时* 签名 sign 是 String(32) C380BEC2BFD727A4B6845133519F3AD6 签名,详见签名生成算法* 时间戳 timestamp 是 String(32) 1414561699 当前的时间,其他详见时间戳规则* @param paternerKey 签名密匙* </pre>* @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./wiki/doc/api/jsapi.php?chapter=9_2private static String orderQueryUrl = "https://api.mch./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./wiki/doc/api/jsapi.php?chapter=9_3private static String closeOrderUrl = "https://api.mch./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./wiki/doc/api/jsapi.php?chapter=9_4public static String refundUrl = "https://api.mch./secapi/pay/refund";// /**//* 申请退款,内部添加了随机字符串nonce_str和签名sign//* @param params 参数map,内部添加了随机字符串nonce_str和签名sign//* @param paternerKey 商户密钥//* @param certPath 证书文件目录//* @return map//*/// public static Map<String, String> refund(Map<String, String> params, String paternerKey, String certPath) {// params.put("nonce_str", System.currentTimeMillis() + "");// String sign = PaymentKit.createSign(params, paternerKey);// params.put("sign", sign);// String partner = params.get("mch_id");// String xmlStr = HttpKit.delegate.postSSL(refundUrl, PaymentKit.toXml(params), certPath, partner);// return PaymentKit.xmlToMap(xmlStr);// }// 查询退款文档地址:https://pay./wiki/doc/api/jsapi.php?chapter=9_5private static String refundQueryUrl = "https://api.mch./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./pay/downloadbill";/*** <pre>* ALL,返回当日所有订单信息,默认值* SUCCESS,返回当日成功支付的订单* REFUND,返回当日退款订单* REVOKED,已撤销的订单* </pre>*/public static enum BillType {ALL, SUCCESS, REFUND, REVOKED}/*** 下载对账单* <pre>* 公众账号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) 0603 下载对账单的日期,格式:0603* 账单类型 bill_type 否 String(8)* </pre>* @param appid 公众账号ID* @param mch_id 商户号* @param paternerKey 签名密匙* @param billDate 对账单日期* @return String*/public static Map<String,String> downloadBill(String appid, String mch_id, String paternerKey, String billDate) {return downloadBill(appid, mch_id, paternerKey, billDate, null);}/*** 下载对账单* <pre>* 公众账号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) 0603 下载对账单的日期,格式:0603* 账单类型 bill_type 否 String(8)* </pre>* @param appid 公众账号ID* @param mch_id 商户号* @param paternerKey 签名密匙* @param billDate 对账单日期* @param billType 账单类型* @return String*/public static Map<String,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);String str = HttpKit.post(downloadBillUrl, PaymentKit.toXml(params));return PaymentKit.xmlToMap(str);}}

微信支付的统一下单工具类

package com.jeeplus.modules.app.pay.util;import mons.io.Charsets;import java.io.UnsupportedEncodingException;import .URLEncoder;import java.util.Map;import java.util.Map.Entry;import java.util.TreeMap;/*** 微信支付的统一下单工具类* @author jsy* @version /12/24**/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) {// 生成签名前先去除signparams.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("<xml>");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("</xml>");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.jeeplus.modules.app.pay.util;import com.google.gson.Gson;import com.google.gson.GsonBuilder;import mons.codec.digest.DigestUtils;import org.jdom2.Document;import org.jdom2.Element;import org.jdom2.input.SAXBuilder;import java.io.*;import .HttpURLConnection;import .URL;import java.util.*;/*** 支付签名常用类* @author jsy* @version /12/24**/public class PayUtil {/*** 签名字符串** @param text需要签名的字符串* @param key 密钥* @param input_charset 编码格式* @return 签名结果*/public static String sign(String text, String key, String input_charset) {text = text + "&key=" + key;return DigestUtils.md5Hex(getContentBytes(text, input_charset));}/*** 签名字符串** @param text需要签名的字符串* @param sign签名结果* @param key 密钥* @param input_charset 编码格式* @return 签名结果*/public static boolean verify(String text, String sign, String key, String input_charset) {text = text +"&key=" + key;String mysign = DigestUtils.md5Hex(getContentBytes(text, input_charset)).toUpperCase();if (mysign.equals(sign)) {return true;} else {return false;}}/*** @param content* @param charset* @return* @throws java.security.SignatureException* @throws UnsupportedEncodingException*/public static byte[] getContentBytes(String content, String charset) {if (charset == null || "".equals(charset)) {return content.getBytes();}try {return content.getBytes(charset);} catch (UnsupportedEncodingException e) {throw new RuntimeException("MD5签名过程中出现错误,指定的编码集不对,您目前指定的编码集是:" + charset);}}private static boolean isValidChar(char ch) {if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z'))return true;if ((ch >= 0x4e00 && ch <= 0x7fff) || (ch >= 0x8000 && ch <= 0x952f))return true;// 简体中文汉字编码return false;}/*** 除去数组中的空值和签名参数** @param sArray 签名参数组* @return 去掉空值与签名参数后的新签名参数组*/public static Map<String, String> paraFilter(Map<String, String> sArray) {Map<String, String> result = new HashMap<String, String>();if (sArray == null || sArray.size() <= 0) {return result;}for (String key : sArray.keySet()) {String value = sArray.get(key);if (value == null || value.equals("") || key.equalsIgnoreCase("sign")|| key.equalsIgnoreCase("sign_type")) {continue;}result.put(key, value);}return result;}/*** 把数组所有元素排序,并按照“参数=参数值”的模式用“&”字符拼接成字符串** @param params 需要排序并参与字符拼接的参数组* @return 拼接后字符串*/public static String createLinkString(Map<String, String> params) {List<String> keys = new ArrayList<>(params.keySet());Collections.sort(keys);String prestr = "";for (int i = 0; i < keys.size(); i++) {String key = keys.get(i);String value = params.get(key);if (i == keys.size() - 1) {// 拼接时,不包括最后一个&字符prestr = prestr + key + "=" + value;} else {prestr = prestr + key + "=" + value + "&";}}return prestr;}/*** @param requestUrl 请求地址* @param requestMethod 请求方法* @param outputStr参数*/public static String httpRequest(String requestUrl, String requestMethod, String outputStr) {// 创建SSLContextStringBuffer buffer = null;try {URL url = new URL(requestUrl);HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setRequestMethod(requestMethod);conn.setDoOutput(true);conn.setDoInput(true);conn.connect();//往服务器端写内容if (null != outputStr) {OutputStream os = conn.getOutputStream();os.write(outputStr.getBytes("utf-8"));os.close();}// 读取服务器端返回的内容InputStream is = conn.getInputStream();InputStreamReader isr = new InputStreamReader(is, "utf-8");BufferedReader br = new BufferedReader(isr);buffer = new StringBuffer();String line = null;while ((line = br.readLine()) != null) {buffer.append(line);}br.close();} catch (Exception e) {e.printStackTrace();}return buffer.toString();}public static String urlEncodeUTF8(String source) {String result = source;try {result = .URLEncoder.encode(source, "UTF-8");} catch (UnsupportedEncodingException e) {// TODO Auto-generated catch blocke.printStackTrace();}return result;}/*** 解析xml,返回第一级元素键值对。如果第一级元素有子节点,则此节点的值是子节点的xml数据。** @param strxml* @return* @throws org.jdom2.JDOMException* @throws IOException*/public static Map doXMLParse(String strxml) throws Exception {if (null == strxml || "".equals(strxml)) {return null;}Map m = new HashMap();InputStream in = String2Inputstream(strxml);SAXBuilder builder = new SAXBuilder();Document doc = builder.build(in);Element root = doc.getRootElement();List list = root.getChildren();Iterator it = list.iterator();while (it.hasNext()) {Element e = (Element) it.next();String k = e.getName();String v = "";List children = e.getChildren();if (children.isEmpty()) {v = e.getTextNormalize();} else {v = getChildrenText(children);}m.put(k, v);}//关闭流in.close();return m;}/*** 获取子结点的xml** @param children* @return String*/public static String getChildrenText(List children) {StringBuffer sb = new StringBuffer();if (!children.isEmpty()) {Iterator it = children.iterator();while (it.hasNext()) {Element e = (Element) it.next();String name = e.getName();String value = e.getTextNormalize();List list = e.getChildren();sb.append("<" + name + ">");if (!list.isEmpty()) {sb.append(getChildrenText(list));}sb.append(value);sb.append("</" + name + ">");}}return sb.toString();}public static InputStream String2Inputstream(String str) {return new ByteArrayInputStream(str.getBytes());}/*** java对象转字符串* @param <T> 泛型占位符* @param obj T* @return String*/public static <T> String toJson(T obj) {Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").enableComplexMapKeySerialization().create();return gson.toJson(obj);}}

支付常量

package com.jeeplus.modules.app.pay.util;/*** 支付常量** @author jsy* @version /12/24**/public class WXPayConstants {public enum SignType {MD5, HMACSHA256}public static final String DOMAIN_API = "api.mch.";public static final String DOMAIN_API2 = "api2.mch.";public static final String DOMAIN_APIHK = "apihk.mch.";public static final String DOMAIN_APIUS = "apius.mch.";public static final String FAIL = "FAIL";/*** 成功的标识*/public static final String SUCCESS = "SUCCESS";/*** 返回状态码的变量名*/public static final String RETURN_CODE = "return_code";public static final String HMACSHA256 = "HMAC-SHA256";public static final String MD5 = "MD5";public static final String FIELD_SIGN = "sign";public static final String FIELD_SIGN_TYPE = "sign_type";public static final String MICROPAY_URL_SUFFIX = "/pay/micropay";public static final String UNIFIEDORDER_URL_SUFFIX = "/pay/unifiedorder";public static final String ORDERQUERY_URL_SUFFIX = "/pay/orderquery";public static final String REVERSE_URL_SUFFIX = "/secapi/pay/reverse";public static final String CLOSEORDER_URL_SUFFIX = "/pay/closeorder";public static final String REFUNDQUERY_URL_SUFFIX = "/pay/refundquery";public static final String DOWNLOADBILL_URL_SUFFIX = "/pay/downloadbill";// sandboxpublic static final String SANDBOX_MICROPAY_URL_SUFFIX = "/sandboxnew/pay/micropay";public static final String SANDBOX_UNIFIEDORDER_URL_SUFFIX = "/sandboxnew/pay/unifiedorder";public static final String SANDBOX_ORDERQUERY_URL_SUFFIX = "/sandboxnew/pay/orderquery";public static final String SANDBOX_REVERSE_URL_SUFFIX = "/sandboxnew/secapi/pay/reverse";public static final String SANDBOX_CLOSEORDER_URL_SUFFIX = "/sandboxnew/pay/closeorder";public static final String SANDBOX_REFUND_URL_SUFFIX = "/sandboxnew/secapi/pay/refund";public static final String SANDBOX_REFUNDQUERY_URL_SUFFIX = "/sandboxnew/pay/refundquery";public static final String SANDBOX_DOWNLOADBILL_URL_SUFFIX = "/sandboxnew/pay/downloadbill";public static final String SANDBOX_REPORT_URL_SUFFIX = "/sandboxnew/payitil/report";public static final String SANDBOX_SHORTURL_URL_SUFFIX = "/sandboxnew/tools/shorturl";public static final String SANDBOX_AUTHCODETOOPENID_URL_SUFFIX = "/sandboxnew/tools/authcodetoopenid";}

xpath解析xml

package com.jeeplus.modules.app.pay.util;import mons.io.IOUtils;import org.w3c.dom.Document;import org.w3c.dom.Element;import org.w3c.dom.Node;import org.w3c.dom.NodeList;import org.xml.sax.InputSource;import org.xml.sax.SAXException;import javax.xml.namespace.QName;import javax.xml.parsers.DocumentBuilder;import javax.xml.parsers.DocumentBuilderFactory;import javax.xml.parsers.ParserConfigurationException;import javax.xml.xpath.XPath;import javax.xml.xpath.XPathConstants;import javax.xml.xpath.XPathExpressionException;import javax.xml.xpath.XPathFactory;import java.io.IOException;import java.io.InputStream;import java.io.StringReader;import java.util.HashMap;import java.util.Map;/*** xpath解析xml* <pre>*文档地址:*/xpath/index.asp* </pre>* @author jsy* @version /12/24**/public class XmlHelper {private final XPath path;private final Document doc;private XmlHelper(InputSource inputSource) throws ParserConfigurationException, SAXException, IOException {DocumentBuilderFactory dbf = getDocumentBuilderFactory();DocumentBuilder db = dbf.newDocumentBuilder();doc = db.parse(inputSource);path = getXPathFactory().newXPath();}private static XmlHelper create(InputSource inputSource) {try {return new XmlHelper(inputSource);} catch (ParserConfigurationException e) {throw new RuntimeException(e);} catch (SAXException e) {throw new RuntimeException(e);} catch (IOException e) {throw new RuntimeException(e);}}public static XmlHelper of(InputStream is) {InputSource inputSource = new InputSource(is);return create(inputSource);}public static XmlHelper of(String xmlStr) {StringReader sr = new StringReader(xmlStr.trim());InputSource inputSource = new InputSource(sr);XmlHelper xmlHelper = create(inputSource);IOUtils.closeQuietly(sr);return xmlHelper;}private Object evalXPath(String expression, Object item, QName returnType) {item = null == item ? doc : item;try {return path.evaluate(expression, item, returnType);} catch (XPathExpressionException e) {throw new RuntimeException(e);}}/*** 获取String* @param expression 路径* @return String*/public String getString(String expression) {return (String) evalXPath(expression, null, XPathConstants.STRING);}/*** 获取Boolean* @param expression 路径* @return String*/public Boolean getBoolean(String expression) {return (Boolean) evalXPath(expression, null, XPathConstants.BOOLEAN);}/*** 获取Number* @param expression 路径* @return {Number}*/public Number getNumber(String expression) {return (Number) evalXPath(expression, null, XPathConstants.NUMBER);}/*** 获取某个节点* @param expression 路径* @return {Node}*/public Node getNode(String expression) {return (Node) evalXPath(expression, null, XPathConstants.NODE);}/*** 获取子节点* @param expression 路径* @return NodeList*/public NodeList getNodeList(String expression) {return (NodeList) evalXPath(expression, null, XPathConstants.NODESET);}/*** 获取String* @param node 节点* @param expression 相对于node的路径* @return String*/public String getString(Object node, String expression) {return (String) evalXPath(expression, node, XPathConstants.STRING);}/*** 获取* @param node 节点* @param expression 相对于node的路径* @return String*/public Boolean getBoolean(Object node, String expression) {return (Boolean) evalXPath(expression, node, XPathConstants.BOOLEAN);}/*** 获取* @param node 节点* @param expression 相对于node的路径* @return {Number}*/public Number getNumber(Object node, String expression) {return (Number) evalXPath(expression, node, XPathConstants.NUMBER);}/*** 获取某个节点* @param node 节点* @param expression 路径* @return {Node}*/public Node getNode(Object node, String expression) {return (Node) evalXPath(expression, node, XPathConstants.NODE);}/*** 获取子节点* @param node 节点* @param expression 相对于node的路径* @return NodeList*/public NodeList getNodeList(Object node, String expression) {return (NodeList) evalXPath(expression, node, XPathConstants.NODESET);}/*** 针对没有嵌套节点的简单处理* @return map集合*/public Map<String, String> toMap() {Element root = doc.getDocumentElement();Map<String, String> params = new HashMap<String, String>();// 将节点封装成map形式NodeList list = root.getChildNodes();for (int i = 0; i < list.getLength(); i++) {Node node = list.item(i);if (node instanceof Element) {params.put(node.getNodeName(), node.getTextContent());}}return params;}private static DocumentBuilderFactory getDocumentBuilderFactory(){return XmlHelperHolder.documentBuilderFactory;}private static XPathFactory getXPathFactory() {return XmlHelperHolder.xPathFactory;}/*** 内部类单例*/private static class XmlHelperHolder {private static DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();private static XPathFactory xPathFactory = XPathFactory.newInstance();}}

常用工具类

package com.jeeplus.modules.app.pay.util;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.w3c.dom.Node;import org.w3c.dom.NodeList;import javax.crypto.Mac;import javax.crypto.spec.SecretKeySpec;import javax.xml.parsers.DocumentBuilder;import javax.xml.parsers.DocumentBuilderFactory;import javax.xml.transform.OutputKeys;import javax.xml.transform.Transformer;import javax.xml.transform.TransformerFactory;import javax.xml.transform.dom.DOMSource;import javax.xml.transform.stream.StreamResult;import java.io.ByteArrayInputStream;import java.io.InputStream;import java.io.StringWriter;import java.security.MessageDigest;import java.util.*;/*** 常用工具类* @author jsy* @version /12/24**/public class WXPayUtil {/*** XML格式字符串转换为Map** @param strXML XML字符串* @return XML数据转换后的Map* @throws Exception*/public static Map<String, String> xmlToMap(String strXML) throws Exception {try {Map<String, String> data = new HashMap<String, String>();DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();InputStream stream = new ByteArrayInputStream(strXML.getBytes("UTF-8"));org.w3c.dom.Document doc = documentBuilder.parse(stream);doc.getDocumentElement().normalize();NodeList nodeList = doc.getDocumentElement().getChildNodes();for (int idx = 0; idx < nodeList.getLength(); ++idx) {Node node = nodeList.item(idx);if (node.getNodeType() == Node.ELEMENT_NODE) {org.w3c.dom.Element element = (org.w3c.dom.Element) node;data.put(element.getNodeName(), element.getTextContent());}}try {stream.close();} catch (Exception ex) {// do nothing}return data;} catch (Exception ex) {WXPayUtil.getLogger().warn("Invalid XML, can not convert to map. Error message: {}. XML content: {}", ex.getMessage(), strXML);throw ex;}}/*** 将Map转换为XML格式的字符串** @param data Map类型数据* @return XML格式的字符串* @throws Exception*/public static String mapToXml(Map<String, String> data) throws Exception {DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();DocumentBuilder documentBuilder= documentBuilderFactory.newDocumentBuilder();org.w3c.dom.Document document = documentBuilder.newDocument();org.w3c.dom.Element root = document.createElement("xml");document.appendChild(root);for (String key: data.keySet()) {String value = data.get(key);if (value == null) {value = "";}value = value.trim();org.w3c.dom.Element filed = document.createElement(key);filed.appendChild(document.createTextNode(value));root.appendChild(filed);}TransformerFactory tf = TransformerFactory.newInstance();Transformer transformer = tf.newTransformer();DOMSource source = new DOMSource(document);transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");transformer.setOutputProperty(OutputKeys.INDENT, "yes");StringWriter writer = new StringWriter();StreamResult result = new StreamResult(writer);transformer.transform(source, result);String output = writer.getBuffer().toString(); //.replaceAll("\n|\r", "");try {writer.close();}catch (Exception ex) {}return output;}/*** 生成带有 sign 的 XML 格式字符串** @param data Map类型数据* @param key API密钥* @return 含有sign字段的XML*/public static String generateSignedXml(final Map<String, String> data, String key) throws Exception {return generateSignedXml(data, key, WXPayConstants.SignType.MD5);}/*** 生成带有 sign 的 XML 格式字符串** @param data Map类型数据* @param key API密钥* @param signType 签名类型* @return 含有sign字段的XML*/public static String generateSignedXml(final Map<String, String> data, String key, WXPayConstants.SignType signType) throws Exception {String sign = generateSignature(data, key, signType);data.put(WXPayConstants.FIELD_SIGN, sign);return mapToXml(data);}/*** 判断签名是否正确** @param xmlStr XML格式数据* @param key API密钥* @return 签名是否正确* @throws Exception*/public static boolean isSignatureValid(String xmlStr, String key) throws Exception {Map<String, String> data = xmlToMap(xmlStr);if (!data.containsKey(WXPayConstants.FIELD_SIGN) ) {return false;}String sign = data.get(WXPayConstants.FIELD_SIGN);return generateSignature(data, key).equals(sign);}/*** 判断签名是否正确,必须包含sign字段,否则返回false。使用MD5签名。** @param data Map类型数据* @param key API密钥* @return 签名是否正确* @throws Exception*/public static boolean isSignatureValid(Map<String, String> data, String key) throws Exception {return isSignatureValid(data, key, WXPayConstants.SignType.MD5);}/*** 判断签名是否正确,必须包含sign字段,否则返回false。** @param data Map类型数据* @param key API密钥* @param signType 签名方式* @return 签名是否正确* @throws Exception*/public static boolean isSignatureValid(Map<String, String> data, String key, WXPayConstants.SignType signType) throws Exception {if (!data.containsKey(WXPayConstants.FIELD_SIGN) ) {return false;}String sign = data.get(WXPayConstants.FIELD_SIGN);return generateSignature(data, key, signType).equals(sign);}/*** 生成签名** @param data 待签名数据* @param key API密钥* @return 签名*/public static String generateSignature(final Map<String, String> data, String key) throws Exception {return generateSignature(data, key, WXPayConstants.SignType.MD5);}/*** 生成签名. 注意,若含有sign_type字段,必须和signType参数保持一致。** @param data 待签名数据* @param key API密钥* @param signType 签名方式* @return 签名*/public static String generateSignature(final Map<String, String> data, String key, WXPayConstants.SignType signType) throws Exception {Set<String> keySet = data.keySet();String[] keyArray = keySet.toArray(new String[keySet.size()]);Arrays.sort(keyArray);StringBuilder sb = new StringBuilder();for (String k : keyArray) {if (k.equals(WXPayConstants.FIELD_SIGN)) {continue;}if(data.get(k).trim().length() > 0) // 参数值为空,则不参与签名sb.append(k).append("=").append(data.get(k).trim()).append("&");}sb.append("key=").append(key);if (WXPayConstants.SignType.MD5.equals(signType)) {return MD5(sb.toString()).toUpperCase();}else if (WXPayConstants.SignType.HMACSHA256.equals(signType)) {return HMACSHA256(sb.toString(), key);}else {throw new Exception(String.format("Invalid sign_type: %s", signType));}}/*** 获取随机字符串 Nonce Str** @return String 随机字符串*/public static String generateNonceStr() {return UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32);}/*** 生成 MD5** @param data 待处理数据* @return MD5结果*/public static String MD5(String data) throws Exception {MessageDigest md = MessageDigest.getInstance("MD5");byte[] array = md.digest(data.getBytes("UTF-8"));StringBuilder sb = new StringBuilder();for (byte item : array) {sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));}return sb.toString().toUpperCase();}/*** 生成 HMACSHA256* @param data 待处理数据* @param key 密钥* @return 加密结果* @throws Exception*/public static String HMACSHA256(String data, String key) throws Exception {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"));StringBuilder sb = new StringBuilder();for (byte item : array) {sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));}return sb.toString().toUpperCase();}/*** 日志* @return*/public static Logger getLogger() {Logger logger = LoggerFactory.getLogger("wxpay java sdk");return logger;}/*** 获取当前时间戳,单位秒* @return*/public static long getCurrentTimestamp() {return System.currentTimeMillis()/1000;}/*** 获取当前时间戳,单位毫秒* @return*/public static long getCurrentTimestampMs() {return System.currentTimeMillis();}/*** 生成 uuid, 即用来标识一笔单,也用做 nonce_str* @return*/public static String generateUUID() {return UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32);}}

Tools工具类

package com.jeeplus.modules.app.pay.util;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 jsy* @version /12/24**/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 = pile(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 = pile("^[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的正则表达式{或<script[^>]*?>[\\s\\S]*?<\\/script> }String regEx_style = "<[\\s]*?style[^>]*?>[\\s\\S]*?<[\\s]*?\\/[\\s]*?style[\\s]*?>";//定义style的正则表达式{或<style[^>]*?>[\\s\\S]*?<\\/style> }String regEx_html = "<[^>]+>"; //定义HTML标签的正则表达式p_script = pile(regEx_script,Pattern.CASE_INSENSITIVE);m_script = p_script.matcher(content);content = m_script.replaceAll(""); //过滤script标签p_style = pile(regEx_style,Pattern.CASE_INSENSITIVE);m_style = p_style.matcher(content);content = m_style.replaceAll(""); //过滤style标签p_html = pile(regEx_html,Pattern.CASE_INSENSITIVE);m_html = p_html.matcher(content);content = m_html.replaceAll(""); //过滤html标签}catch(Exception e) {return "";}if(content.length()>p){content = content.substring(0, p)+"...";}else{content = content + "...";}return content;}public static String md5(String str) {try {MessageDigest md = MessageDigest.getInstance("MD5");md.update(str.getBytes());byte b[] = md.digest();int i;StringBuffer buf = new StringBuffer("");for (int offset = 0; offset < b.length; offset++) {i = b[offset];if (i < 0)i += 256;if (i < 16)buf.append("0");buf.append(Integer.toHexString(i));}str = buf.toString();} catch (Exception e) {e.printStackTrace();}return str;}}

总结

到现在基本上已经完成了,大家照着我的方法来一定能成功。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。