微信支付接口对接文档
建立子包demo,demo里面创建controller包、domain包、service包
目录结构:
controller包中创建Pay_controller
package com.ccunix.ihousekeeping.demo.controller;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.ccunix.ihousekeeping.base.controller.BaseMultiController;
import com.ccunix.ihousekeeping.demo.domain.WxOa;
import com.ccunix.ihousekeeping.demo.service.UUID_Tools;
import com.ccunix.ihousekeeping.demo.service.WxSignUtil;
/**
*
* @ClassName: Pay_Controller
* @author xyp
* @date 2019年8月12日 上午9:57:46
*
*/
@Controller
@RequestMapping("Pay_Controller")
public class Pay_Controller extends BaseMultiController {
WxSignUtil wxSignUtil = new WxSignUtil();
// 微信预下单交易
@ResponseBody
@RequestMapping("/yuxiadan")
public Map yuxiadan() throws Exception {
WxOa wxOa = new WxOa();
// 应用ID
wxOa.setAppid("xxxxxxxxxxxxxx");
// 商户号
wxOa.setMch_id("xxxxxxxx");
// 随机字符串 不长于32位
wxOa.setNonce_str(UUID_Tools.getUUID());
// 商品描述
wxOa.setBody("phone");
// 商户订单号
wxOa.setOut_trade_no("12345");
// 订单总金额,单位为分
wxOa.setTotal_fee(10);
// 终端IP
wxOa.setSpbill_create_ip("127.0.0.1");
// 通知地址
wxOa.setNotify_url(wxSignUtil.unifiedorderUrl);
// 交易类型 APP
wxOa.setTrade_type("NATIVE");
// 将数据放入map中
Map map = wxSignUtil.WxMd5Sign(wxOa, "9dffe0f7a65bb1976d4b33d7a8b1f7ac");
//转换为set集合
Set<Map.Entry<Integer, String>> entries = map.entrySet();
//迭代器进行遍历
Iterator<Map.Entry<Integer, String>> iteratorMap = entries.iterator();
while (iteratorMap.hasNext()) {
Map.Entry<Integer, String> next = iteratorMap.next();
System.err.println(next);
}
return map;
}
}
domain包中创建bean类:
WxOa类:
package com.ccunix.ihousekeeping.demo.domain;
import java.io.Serializable;
import java.util.Date;
//微信预下单参数
public class WxOa implements Serializable {
// 应用ID
private String appid;
// 商户号
private String mch_id;
// 设备号
private String device_info;
// 随机字符串 不长于32位
private String nonce_str;
// 商品描述
private String body;
// 附加数据
private String attach;
// 商户订单号
private String out_trade_no;
// 订单总金额,单位为分
private int total_fee;
// 终端IP
private String spbill_create_ip;
// 交易起始时间
private Date time_start;
// 交易结束时间
private Date time_expire;
// 通知地址
private String notify_url;
// 交易类型 APP
private String trade_type;
// openid
private String openid;
//code_url
private String code_url;
public String getCode_url() {
return code_url;
}
public void setCode_url(String code_url) {
this.code_url = code_url;
}
public String getAppid() {
return appid;
}
public void setAppid(String appid) {
this.appid = appid;
}
public String getMch_id() {
return mch_id;
}
public void setMch_id(String mch_id) {
this.mch_id = mch_id;
}
public String getDevice_info() {
return device_info;
}
public void setDevice_info(String device_info) {
this.device_info = device_info;
}
public String getNonce_str() {
return nonce_str;
}
public void setNonce_str(String nonce_str) {
this.nonce_str = nonce_str;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
public String getAttach() {
return attach;
}
public void setAttach(String attach) {
this.attach = attach;
}
public String getOut_trade_no() {
return out_trade_no;
}
public void setOut_trade_no(String out_trade_no) {
this.out_trade_no = out_trade_no;
}
public int getTotal_fee() {
return total_fee;
}
public void setTotal_fee(int total_fee) {
this.total_fee = total_fee;
}
public String getSpbill_create_ip() {
return spbill_create_ip;
}
public void setSpbill_create_ip(String spbill_create_ip) {
this.spbill_create_ip = spbill_create_ip;
}
public Date getTime_start() {
return time_start;
}
public void setTime_start(Date time_start) {
this.time_start = time_start;
}
public Date getTime_expire() {
return time_expire;
}
public void setTime_expire(Date time_expire) {
this.time_expire = time_expire;
}
public String getNotify_url() {
return notify_url;
}
public void setNotify_url(String notify_url) {
this.notify_url = notify_url;
}
public String getTrade_type() {
return trade_type;
}
public void setTrade_type(String trade_type) {
this.trade_type = trade_type;
}
public String getOpenid() {
return openid;
}
public void setOpenid(String openid) {
this.openid = openid;
}
}
WxPayOa类:
package com.ccunix.ihousekeeping.demo.domain;
import java.io.Serializable;
public class WxPayOa implements Serializable {
// 应用ID
private String appid;
// 随机字符串
private String noncestr;
// 扩展字段
private String packageace;
// 商户号
private String partnerid;
// 预支付交易会话ID
private String prepayid;
// 时间戳
private String timestamp;
public String getAppid() {
return appid;
}
public void setAppid(String appid) {
this.appid = appid;
}
public String getNoncestr() {
return noncestr;
}
public void setNoncestr(String noncestr) {
this.noncestr = noncestr;
}
public String getPackageace() {
return packageace;
}
public void setPackageace(String packageace) {
this.packageace = packageace;
}
public String getPartnerid() {
return partnerid;
}
public void setPartnerid(String partnerid) {
this.partnerid = partnerid;
}
public String getPrepayid() {
return prepayid;
}
public void setPrepayid(String prepayid) {
this.prepayid = prepayid;
}
public String getTimestamp() {
return timestamp;
}
public void setTimestamp(String timestamp) {
this.timestamp = timestamp;
}
}
service包中为工具类,其中重要的为WxSignUtil类
WxSignUtil类:
package com.ccunix.ihousekeeping.demo.service;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.crypto.spec.SecretKeySpec;
import javax.net.ssl.SSLContext;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import com.alibaba.fastjson.JSONObject;
import com.ccunix.ihousekeeping.demo.domain.WxOa;
import com.ccunix.ihousekeeping.demo.domain.WxPayOa;
//微信签名
public class WxSignUtil {
// 微信预下单 请求地址
public static final String unifiedorderUrl = "https://api.mch.weixin.qq.com/pay/unifiedorder";
// 微信申请退款请求地址
public static final String callbackamounturl = "https://api.mch.weixin.qq.com/secapi/pay/refund";
// 微信小程序统一下单地址
public static final String smallprogramorderurl = "https://api.mch.weixin.qq.com/pay/unifiedorder";
// 微信App支付预下单接口
public static Map WxMd5Sign(WxOa wxOa, String key) throws Exception {
String stringA = "appid=" + wxOa.getAppid() + "&attach=" + wxOa.getAttach() + "&body=" + wxOa.getBody()
+ "&mch_id=" + wxOa.getMch_id() + "&nonce_str=" + wxOa.getNonce_str() + "¬ify_url="
+ wxOa.getNotify_url() + "&out_trade_no=" + wxOa.getOut_trade_no() + "&spbill_create_ip="
+ wxOa.getSpbill_create_ip() + "&total_fee=" + wxOa.getTotal_fee() + "&trade_type="
+ wxOa.getTrade_type();
String stringSignTemp = stringA + "&key=" + key;
String stringSignTemp1 = new String(stringSignTemp.getBytes("iso8859-1"));
// String stringSignTemp1=new String(stringSignTemp.getBytes("utf-8"));
String sign = LogisticsInfoMD5.encode(stringSignTemp1).toUpperCase();
String par = "<xml>" + "<appid>" + wxOa.getAppid() + "</appid>" + "<attach>" + wxOa.getAttach() + "</attach>"
+ "<body><![CDATA[" + wxOa.getBody() + "]]></body>" + "<mch_id>" + wxOa.getMch_id() + "</mch_id>"
+ "<nonce_str>" + wxOa.getNonce_str() + "</nonce_str>" + "<notify_url>" + wxOa.getNotify_url()
+ "</notify_url>" + "<out_trade_no>" + wxOa.getOut_trade_no() + "</out_trade_no>" + "<spbill_create_ip>"
+ wxOa.getSpbill_create_ip() + "</spbill_create_ip>" + "<total_fee>" + wxOa.getTotal_fee()
+ "</total_fee>" + "<trade_type>" + wxOa.getTrade_type() + "</trade_type>" + "<sign>" + sign + "</sign>"
+ "</xml> ";
String ret = WxSignUtil.post(unifiedorderUrl, par);
System.out.println(ret);
Map<String, String> map = readStringXmlOut(ret);
return map;
}
// 调起支付加签
public static String WxPrePaySign(WxPayOa wxPayOa, String key) throws Exception {
// //应用ID
// String appid="";
// //随机字符串
// String noncestr="";
// //扩展字段
// String packageace="";
// //商户号
// String partnerid="";
// //预支付交易会话ID
// String prepayid="";
// //时间戳
// String timestamp="";
String stringA = "appid=" + wxPayOa.getAppid() + "&noncestr=" + wxPayOa.getNoncestr() + "&package="
+ wxPayOa.getPackageace() + "&partnerid=" + wxPayOa.getPartnerid() + "&prepayid="
+ wxPayOa.getPrepayid() + "×tamp=" + wxPayOa.getTimestamp();
String stringSignTemp = stringA + "&key=" + key;
String stringSignTemp1 = new String(stringSignTemp.getBytes("iso8859-1"));
// String stringSignTemp1=new String(stringSignTemp.getBytes("utf-8"));
String sign = LogisticsInfoMD5.encode(stringSignTemp1).toUpperCase();
return sign;
}
/**
* 发送xml数据请求到server端
*
* @param url
* xml请求数据地址
* @param xmlString
* 发送的xml数据流
* @return null发送失败,否则返回响应内容
*/
public static String post(String url, String xmlFileName) {
// 关闭
System.setProperty("org.apache.commons.logging.Log", "org.apache.commons.logging.impl.SimpleLog");
System.setProperty("org.apache.commons.logging.simplelog.showdatetime", "true");
System.setProperty("org.apache.commons.logging.simplelog.log.org.apache.commons.httpclient", "stdout");
// 创建httpclient工具对象
HttpClient client = new HttpClient();
// 创建post请求方法
PostMethod myPost = new PostMethod(url);
// 设置请求超时时间
client.setConnectionTimeout(300 * 1000);
String responseString = null;
try {
// 设置请求头部类型
myPost.setRequestHeader("Content-Type", "text/xml");
myPost.setRequestHeader("charset", "iso8859-1");
// myPost.setRequestHeader("charset","utf-8");
// 设置请求体,即xml文本内容,注:这里写了两种方式,一种是直接获取xml内容字符串,一种是读取xml文件以流的形式
myPost.setRequestBody(xmlFileName);
// InputStream body=this.getClass().getResourceAsStream("/"+xmlFileName);
// myPost.setRequestBody(body);
// myPost.setRequestEntity(new
// StringRequestEntity(xmlString,"text/xml","utf-8"));
int statusCode = client.executeMethod(myPost);
if (statusCode == HttpStatus.SC_OK) {
BufferedInputStream bis = new BufferedInputStream(myPost.getResponseBodyAsStream());
byte[] bytes = new byte[1024];
ByteArrayOutputStream bos = new ByteArrayOutputStream();
int count = 0;
while ((count = bis.read(bytes)) != -1) {
bos.write(bytes, 0, count);
}
byte[] strByte = bos.toByteArray();
responseString = new String(strByte, 0, strByte.length, "utf-8");
// System.out.println(responseString);
bos.close();
bis.close();
}
} catch (Exception e) {
e.printStackTrace();
}
myPost.releaseConnection();
return responseString;
}
/**
* @description 将xml字符串转换成map
* @param xml
* @return Map
*/
public static Map<String, String> readStringXmlOut(String xml) {
Map<String, String> map = new HashMap<String, String>();
Document doc = null;
try {
doc = DocumentHelper.parseText(xml); // 将字符串转为XML
Element rootElt = doc.getRootElement(); // 获取根节点
@SuppressWarnings("unchecked")
List<Element> list = rootElt.elements();// 获取根节点下所有节点
for (Element element : list) { // 遍历节点
map.put(element.getName(), element.getText()); // 节点的name为map的key,text为map的value
}
} catch (DocumentException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return map;
}
// 支付回调验证签名
public static boolean wxPayChack(Map map, String key) throws Exception {
String stringA = "appid=" + map.get("appid") + "&attach=" + map.get("attach") + "&bank_type="
+ map.get("bank_type") + "&cash_fee=" + map.get("cash_fee") + "" + "&fee_type=" + map.get("fee_type")
+ "&is_subscribe=" + map.get("is_subscribe") + "&mch_id=" + map.get("mch_id") + "&nonce_str="
+ map.get("nonce_str") + "&openid=" + map.get("openid") + "&out_trade_no=" + map.get("out_trade_no")
+ "&result_code=" + map.get("result_code") + "&return_code=" + map.get("return_code") + "&time_end="
+ map.get("time_end") + "&total_fee=" + map.get("total_fee") + "&trade_type=" + map.get("trade_type")
+ "&transaction_id=" + map.get("transaction_id");
String stringSignTemp = stringA + "&key=" + key;
String stringSignTemp1 = new String(stringSignTemp.getBytes("iso8859-1"));
String sign = LogisticsInfoMD5.encode(stringSignTemp1).toUpperCase();
String retSign = (String) map.get("sign");
if (retSign.equals(sign)) {
return true;
}
return false;
}
// 接收微信回调request 获取xml参数信息
public static Map<String, String> inputStream2String(HttpServletRequest request) throws Exception {
InputStream is = request.getInputStream();
String xml = WxSignUtil.inputStream2String(is, "utf-8");
return WxSignUtil.readStringXmlOut(xml);
}
/**
* InputStream流转换成String字符串
*
* @param inStream
* InputStream流
* @param encoding
* 编码格式
* @return String字符串
*/
public static String inputStream2String(InputStream inStream, String encoding) {
String result = null;
try {
if (inStream != null) {
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
byte[] tempBytes = new byte[1000];
int count = -1;
while ((count = inStream.read(tempBytes, 0, 1000)) != -1) {
outStream.write(tempBytes, 0, count);
}
tempBytes = null;
outStream.flush();
result = new String(outStream.toByteArray(), encoding);
}
} catch (Exception e) {
result = null;
}
return result;
}
// 获取用户的openid
public static String getUserOpenId(Map<String, String> map) {
String param = "appid=" + map.get("openappid") + "&secret=" + map.get("opensecret") + "&code=" + map.get("code")
+ "&grant_type=authorization_code";
String ret = HttpUtil.doGet(map.get("openidurl"), param);
JSONObject jon = JSONObject.parseObject(ret);
String openId = jon.getString("openid");
return openId;
}
// 微信公众号预下单
public static Map WxH5Md5Sign(Map map, String key) throws Exception {
// //公众账号ID
// String appid="";
// //商品描述
// String body="";
// //商户号
// String mch_id="";
// //随机字符串
// String nonce_str="";
// //通知地址
// String notify_url="";
// //用户标识
// String openid="";
// //商户订单号
// String out_trade_no="";
// //终端IP
// String spbill_create_ip="";
// //订单总金额
// int total_fee=0;
// //交易类型
// String trade_type="";
String stringA = "appid=" + map.get("openappid") + "&body=" + map.get("body") + "&mch_id="
+ map.get("openmchid") + "&nonce_str=" + map.get("nonce_str") + "¬ify_url="
+ map.get("opencallbackurl") + "&openid=" + map.get("openid") + "&out_trade_no="
+ map.get("out_trade_no") + "&spbill_create_ip=127.0.0.1&total_fee=" + map.get("total_fee")
+ "&trade_type=JSAPI";
String stringSignTemp = stringA + "&key=" + key;
// String stringSignTemp1=new String(stringSignTemp.getBytes("iso8859-1"));
String stringSignTemp1 = new String(stringSignTemp.getBytes("utf-8"));
String sign = LogisticsInfoMD5.encode(stringSignTemp1).toUpperCase();
String par = "<xml>" + "<appid><![CDATA[" + map.get("openappid") + "]]></appid>" + "<mch_id><![CDATA["
+ map.get("openmchid") + "]]></mch_id>" + "<openid><![CDATA[" + map.get("openid") + "]]></openid>"
+ "<body><![CDATA[" + map.get("body") + "]]></body>" + "<nonce_str><![CDATA[" + map.get("nonce_str")
+ "]]></nonce_str>" + "<notify_url><![CDATA[" + map.get("opencallbackurl") + "]]></notify_url>"
+ "<out_trade_no><![CDATA[" + map.get("out_trade_no") + "]]></out_trade_no>"
+ "<spbill_create_ip><![CDATA[127.0.0.1]]></spbill_create_ip>" + "<total_fee><![CDATA["
+ map.get("total_fee") + "]]></total_fee>" + "<trade_type><![CDATA[JSAPI]]></trade_type>" + "<sign>"
+ sign + "</sign>" + "</xml>";
// B8971A5E8220F8B9A1C314FDDA7440C4
String ret = WxSignUtil.post("https://api.mch.weixin.qq.com/pay/unifiedorder", par);
Map<String, String> mapret = readStringXmlOut(ret);
return mapret;
}
// 公众号预下单回调验证签名
public static boolean orderPayCallbackChack(Map map, String key) throws Exception {
String stringA = "appid=" + map.get("appid") + "&bank_type=" + map.get("bank_type") + "&cash_fee="
+ map.get("cash_fee") + "&fee_type=" + map.get("fee_type") + "&is_subscribe=" + map.get("is_subscribe")
+ "&mch_id=" + map.get("mch_id") + "&nonce_str=" + map.get("nonce_str") + "&openid=" + map.get("openid")
+ "&out_trade_no=" + map.get("out_trade_no") + "&result_code=" + map.get("result_code")
+ "&return_code=" + map.get("return_code") + "&time_end=" + map.get("time_end") + "&total_fee="
+ map.get("total_fee") + "&trade_type=" + map.get("trade_type") + "&transaction_id="
+ map.get("transaction_id");
String stringSignTemp = stringA + "&key=" + key;
String stringSignTemp1 = new String(stringSignTemp.getBytes("utf-8"));
String sign = LogisticsInfoMD5.encode(stringSignTemp1).toUpperCase();
String retsign = map.get("sign") + "";
if (sign.equals(retsign)) {
return true;
}
return false;
}
// 公众号调起支付签名
public static String openSignPayMd5(Map map, String key) throws Exception {
// 公众号id
String appId = "";
// 时间戳
String timeStamp = "";
// 随机字符串
String nonceStr = "";
// 订单详情扩展字符串
String packageout = "";
// 签名方式
String signType = "";
// String
// stringA="appid=wx8731a2e298f48739&nonceStr=123456&package=123456&signType=MD5&timeStamp=123456";
String stringA = "appId=" + map.get("appId") + "&nonceStr=" + map.get("nonceStr") + "&package="
+ map.get("package") + "&signType=" + map.get("signType") + "&timeStamp=" + map.get("timeStamp");
String stringSignTemp = stringA + "&key=" + key;
// String stringSignTemp1=new String(stringSignTemp.getBytes("iso8859-1"));
String stringSignTemp1 = new String(stringSignTemp.getBytes("utf-8"));
String sign = LogisticsInfoMD5.encode(stringSignTemp1).toUpperCase();
return sign;
}
// 微信支付商户退款
public static Map wxPayMachBackToUser(Map map, String key) throws Exception {
// //公众账号ID
// String appid="";
// //商户号
// String mch_id="";
// //随机字符串
// String nonce_str="";
// //微信订单号 流水号
// String transaction_id="";
//// //商户订单号
//// String out_trade_no="";
// //商户退款单号
// String out_refund_no="";
// //订单金额 订单总金额,单位为分,只能为整数
// String total_fee="";
// //退款金额
// String refund_fee="";
// 退款结果通知url
// String notify_url="";
String stringA = "appid=" + map.get("appid") + "&mch_id=" + map.get("mch_id") + "&nonce_str="
+ map.get("nonce_str") + "¬ify_url=" + map.get("notify_url") + "&out_refund_no="
+ map.get("out_refund_no") + "&refund_fee=" + map.get("refund_fee") + "&total_fee="
+ map.get("total_fee") + "&transaction_id=" + map.get("transaction_id");
String stringSignTemp = stringA + "&key=" + key;
// String stringSignTemp1=new String(stringSignTemp.getBytes("iso8859-1"));
String stringSignTemp1 = new String(stringSignTemp.getBytes("utf-8"));
String sign = LogisticsInfoMD5.encode(stringSignTemp1).toUpperCase();
String par = "<xml>" + " <appid><![CDATA[" + map.get("appid") + "]]></appid>" + " <mch_id><![CDATA["
+ map.get("mch_id") + "]]></mch_id>" + " <nonce_str><![CDATA[" + map.get("nonce_str")
+ "]]></nonce_str>" + " <notify_url><![CDATA[" + map.get("notify_url") + "]]></notify_url>"
+ " <out_refund_no><![CDATA[" + map.get("out_refund_no") + "]]></out_refund_no>"
+ " <refund_fee><![CDATA[" + map.get("refund_fee") + "]]></refund_fee>" + " <total_fee><![CDATA["
+ map.get("total_fee") + "]]></total_fee>" + " <transaction_id><![CDATA[" + map.get("transaction_id")
+ "]]></transaction_id>" + " <sign>" + sign + "</sign>" + "</xml>";
// String ret=WxSignUtil.post("https://api.mch.weixin.qq.com/secapi/pay/refund",
// par);
String ret = WxSignUtil.postData("https://api.mch.weixin.qq.com/secapi/pay/refund", par, map.get("mch_id") + "",
map.get("keyPath") + "");
Map<String, String> mapret = readStringXmlOut(ret);
return mapret;
}
// 解密微信退款加密字段
public static Map desDecodeWxPayCallBack(Map<String, String> map, String key) throws Exception {
// 对商户key做md5,得到32位小写key*
// String mdkey=LogisticsInfoMD5.encode(key).toLowerCase();
SecretKeySpec mdkey = new SecretKeySpec(LogisticsInfoMD5.encode(key).toLowerCase().getBytes(), "AES");
// 微信订单号
String transaction_id = map.get("transaction_id");
if (transaction_id != null) {
// 对加密串A做base64解码,得到加密串B
transaction_id = new String(Base64Util.decode(transaction_id));
transaction_id = AESUtil.decryptData(transaction_id, mdkey);
map.put(transaction_id, transaction_id);
}
return map;
}
private static int socketTimeout = 10000;// 连接超时时间,默认10秒
private static int connectTimeout = 30000;// 传输超时时间,默认30秒
private static RequestConfig requestConfig;// 请求器的配置
private static CloseableHttpClient httpClient;// HTTP请求器
/**
* 通过Https往API post xml数据
*
* @param url
* API地址
* @param xmlObj
* 要提交的XML数据对象
* @param mchId
* 商户ID
* @param certPath
* 证书位置
* @return
*/
public static String postData(String url, String xmlObj, String mchId, String certPath) {
// 加载证书
try {
initCert(mchId, certPath);
} catch (Exception e) {
e.printStackTrace();
}
String result = null;
HttpPost httpPost = new HttpPost(url);
// 得指明使用UTF-8编码,否则到API服务器XML的中文不能被成功识别
StringEntity postEntity = new StringEntity(xmlObj, "UTF-8");
httpPost.addHeader("Content-Type", "text/xml");
httpPost.setEntity(postEntity);
// 根据默认超时限制初始化requestConfig
requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout).setConnectTimeout(connectTimeout)
.build();
// 设置请求器的配置
httpPost.setConfig(requestConfig);
try {
HttpResponse response = null;
try {
response = httpClient.execute(httpPost);
} catch (IOException e) {
e.printStackTrace();
}
HttpEntity entity = response.getEntity();
try {
result = EntityUtils.toString(entity, "UTF-8");
} catch (IOException e) {
e.printStackTrace();
}
} finally {
httpPost.abort();
}
return result;
}
/**
* 加载证书
*
* @param mchId
* 商户ID
* @param certPath
* 证书位置
* @throws Exception
*/
private static void initCert(String mchId, String certPath) throws Exception {
// 证书密码,默认为商户ID
String key = mchId;
// 证书的路径
String path = certPath;
// 指定读取证书格式为PKCS12
KeyStore keyStore = KeyStore.getInstance("PKCS12");
// 读取本机存放的PKCS12证书文件
FileInputStream instream = new FileInputStream(new File(path));
try {
// 指定PKCS12的密码(商户ID)
keyStore.load(instream, key.toCharArray());
} finally {
instream.close();
}
SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, key.toCharArray()).build();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1" }, null,
SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
}
// 微信小程序統一下單
public static Map WxSmallProgramMd5Sign(Map map, String key) throws Exception {
String stringA = "appid=" + map.get("appid") + "&attach=" + map.get("attach") + "&body=" + map.get("body")
+ "&mch_id=" + map.get("mch_id") + "&nonce_str=" + map.get("nonce_str") + "¬ify_url="
+ map.get("notify_url") + "&openid=" + map.get("openid") + "&out_trade_no=" + map.get("out_trade_no")
+ "&spbill_create_ip=" + map.get("spbill_create_ip") + "&total_fee=" + map.get("total_fee")
+ "&trade_type=" + map.get("trade_type");
String stringSignTemp = stringA + "&key=" + key;
String stringSignTemp1 = new String(stringSignTemp.getBytes("iso8859-1"));
// String stringSignTemp1=new String(stringSignTemp.getBytes("utf-8"));
String sign = LogisticsInfoMD5.encode(stringSignTemp1).toUpperCase();
String par = "<xml>" + "<appid>" + map.get("appid") + "</appid>" + "<attach>" + map.get("attach") + "</attach>"
+ "<body>" + map.get("body") + "</body>" + "<mch_id>" + map.get("mch_id") + "</mch_id>" + "<nonce_str>"
+ map.get("nonce_str") + "</nonce_str>" + "<notify_url>" + map.get("notify_url") + "</notify_url>"
+ "<openid>" + map.get("openid") + "</openid>" + "<out_trade_no>" + map.get("out_trade_no")
+ "</out_trade_no>" + "<spbill_create_ip>" + map.get("spbill_create_ip") + "</spbill_create_ip>"
+ "<total_fee>" + map.get("total_fee") + "</total_fee>" + "<trade_type>" + "JSAPI" + "</trade_type>"
+ "<sign>" + sign + "</sign>" + "</xml>";
String ret = WxSignUtil.post(smallprogramorderurl, par);
Map<String, String> retmap = readStringXmlOut(ret);
return retmap;
}
// 微信小程序调起支付签名
public static Map wxSmallProgramPaySign(Map map, String key) throws Exception {
String stringA = "appId=" + map.get("appid") + "&nonceStr=" + map.get("nonceStr") + "&package=prepay_id="
+ map.get("prepay_id") + "&signType=MD5&timeStamp=" + map.get("timeStamp");
String stringSignTemp = stringA + "&key=" + key;
String stringSignTemp1 = new String(stringSignTemp.getBytes("iso8859-1"));
// String stringSignTemp1=new String(stringSignTemp.getBytes("utf-8"));
String sign = LogisticsInfoMD5.encode(stringSignTemp1).toUpperCase();
Map retmap = new HashMap();
retmap.put("time", map.get("timeStamp"));
retmap.put("package", "prepay_id=" + map.get("prepay_id"));
retmap.put("paySign", sign);
retmap.put("signType", "MD5");
retmap.put("nonceStr", map.get("nonceStr"));
return retmap;
}
// 微信小程序获得openid
public static String wxSmallProgramGetOpenId(Map map, String secret) throws Exception {
String getUrl = "https://api.weixin.qq.com/sns/jscode2session";
String param = "appid=" + map.get("appid") + "&secret=" + secret + "&js_code=" + map.get("code")
+ "&grant_type=authorization_code";
String ret = HttpUtil.doGet(getUrl, param);
// {"session_key":"vz5yE67kF3p8CKpTtLgobw==","openid":"oMEFK5M53RmMPTow1_GoBRKkrOI4"}
JSONObject json = JSONObject.parseObject(ret);
String openid = json.getString("openid");
String session_key = json.getString("session_key");
return openid + "," + session_key;
}
// 查询微信订单
public static void queryOrderPayInfo() throws Exception {
String stringA = "appid=wx608bbf2ae0956623&mch_id=1512285851&nonce_str=456168546545&out_trade_no=0a3f639a3f174529a7ca236632f36d4d&key=9dffe0f7a65bb1976d4b33d7a8b1f7ac";
String stringSignTemp = stringA;
String stringSignTemp1 = new String(stringSignTemp.getBytes("utf-8"));
String sign = LogisticsInfoMD5.encode(stringSignTemp1).toUpperCase();
String par = "<xml>" + "<appid><![CDATA[wx608bbf2ae0956623]]></appid>"
+ "<mch_id><![CDATA[1512285851]]></mch_id>" + "<nonce_str><![CDATA[456168546545]]></nonce_str>"
+ "<out_trade_no><![CDATA[0a3f639a3f174529a7ca236632f36d4d]]></out_trade_no>" + "<sign>" + sign
+ "</sign>" + "</xml>";
String ret = WxSignUtil.post("https://api.mch.weixin.qq.com/pay/orderquery", par);
Map<String, String> mapret = readStringXmlOut(ret);
System.out.println(mapret);
}
}
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.0</modelVersion>
<groupId>isweb</groupId>
<artifactId>ccunix.is</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<srping.version>4.0.2.RELEASE</srping.version>
<mybatis.version>3.2.8</mybatis.version>
<slf4j.version>1.7.12</slf4j.version>
<log4j.version>1.2.17</log4j.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<scope>provided</scope>
<version>7.0</version>
</dependency>
<!-- spring框架包 start -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${srping.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${srping.version}</version>
</dependency>
<!-- google zxing 生成二维码 -->
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>javase</artifactId>
<version>3.3.3</version>
</dependency>
<!-- 长链接转短链接 相关 -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
<version>${srping.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${srping.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${srping.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${srping.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${srping.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${srping.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${srping.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${srping.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${srping.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${srping.version}</version>
</dependency>
<!-- spring框架包 end -->
<!-- mybatis框架包 start -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.2.2</version>
</dependency>
<!-- mybatis框架包 end -->
<!-- 数据库驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.35</version>
</dependency>
<!-- 导入dbcp的jar包,用来在applicationContext.xml中配置数据库 -->
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
<!-- jstl标签类 -->
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- 中文转拼音jar -->
<dependency>
<groupId>com.belerweb</groupId>
<artifactId>pinyin4j</artifactId>
<version>2.5.0</version>
</dependency>
<!-- log start -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
</dependency>
<!-- log END -->
<!-- Json -->
<!-- 格式化对象,方便输出日志 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.6</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.13</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.4.2</version>
</dependency>
<!-- 上传组件包 start -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.10</version>
</dependency>
<!-- 上传组件包 end -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.12</version>
</dependency>
<!-- redis -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>1.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>3.1.2.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.1.0</version>
</dependency>
<!-- apollo相关 -->
<dependency>
<groupId>org.eclipse.paho</groupId>
<artifactId>org.eclipse.paho.client.mqttv3</artifactId>
<version>1.2.0</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.10</version>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20090211</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.3.5</version>
</dependency>
<!-- poi excel导入导出 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.9</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.9</version>
</dependency>
<!-- springMVC 数据校验 -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.3.0.Alpha1</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.21</version>
</dependency>
<!-- 解密 -->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.55</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.10</version>
</dependency>
<!-- https://mvnrepository.com/artifact/dom4j/dom4j -->
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>com.baidu.aip</groupId>
<artifactId>java-sdk</artifactId>
<version>4.8.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.0.0</version>
</plugin>
</plugins>
<finalName>maven_project</finalName>
</build>
</project>
点击支付页面:demo.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@include file="/WEB-INF/html/base/baseurl.jsp"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<script src="<%=baseurl%>/js/jquery.js"></script>
<script src="<%=baseurl%>/bootstrap/js/bootstrap.min.js"></script>
</head>
<body>
<script type="text/javascript"
src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>
<h2>微信支付</h2>
<script>
$(document).ready(function() {
$("#yuzhifu").click(function() {
alert(6)
//js方法的调用
yuzhifu();
});
});
function yuzhifu() {
//通过Ajax调用
$.ajax({
url : getRootPath() + "/Pay_Controller/yuxiadan.action",
data : null,
success : info
});
}
function info(data) {
var d = $(data);
//页面跳转,并将code_url传到另一个页面中
location.href = getRootPath()
+ "/BaseMultiController/toPage.action?page=main/demo/qrcode¶m="
+ d[0].code_url;
}
</script>
<input type="button" value=支付 id="yuzhifu">
</body>
</html>
生成二维码页面:qrcode.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@include file="/WEB-INF/html/base/baseurl.jsp"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ko" lang="ko">
<head>
<title>Javascript 二维码生成库:QRCode</title>
<%
out.print("<input type=\"hidden\" id=\"hidden\" value=\"");%><%=request.getAttribute("param") %><% out.print("\"");
%>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="viewport"
content="width=device-width,initial-scale=1,user-scalable=no" />
<script type="text/javascript"
src="http://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
<script type="text/javascript"
src="http://static.runoob.com/assets/qrcode/qrcode.min.js"></script>
</head>
<body>
<!-- <input id="text" type="text" value="http://www.runoob.com"
style="width: 80%" /> -->
<br />
<div id="qrcode" style="width: 100px; height: 100px; margin-top: 15px;"></div>
<script type="text/javascript">
var qrcode = new QRCode(document.getElementById("qrcode"), {
width : 300,
height : 300
});
function makeCode() {
var elText = document.getElementById("hidden");
if (!elText.value) {
alert("Input a text");
elText.focus();
return;
}
qrcode.makeCode(elText.value);
}
makeCode();
$("#text").on("blur", function() {
makeCode();
}).on("keydown", function(e) {
if (e.keyCode == 13) {
makeCode();
}
});
</script>
</body>
</html>
注意:appid需要跟商户号绑定