微信官方文档,地址如下: https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=1_1
导入微信官方的三个工具类WXPayUtil, WxPayContants,WxPayXmlUtil
//统一下单
public AppWxPay wxPay(AppWxPayInfo info) {
String APPID = ""; //填写自己的
String MCHID = ""; //填写自己的
String APISECRET = ""; //填写自己的
Map<String, String> map = new HashMap<>();
String nonceStr = WXPayUtil.generateNonceStr();
//小程序ID
map.put("appid", APPID);
//商户ID
map.put("mch_id", MCHID);
//随机字符串
map.put("nonce_str", nonceStr);
//商品描述
map.put("body", info.getBody());
//商户订单号
map.put("out_trade_no", info.getOutTradeNo());
//标价金额(单位为分)
map.put("total_fee", "1");
//终端IP
map.put("spbill_create_ip", info.getSpbillCreateIp());
//通知地址
map.put("notify_url", "http://**/noticeUrl");//回调地址自己项目的接口
//交易类型
map.put("trade_type", "JSAPI");
//用户标识
map.put("openid", info.getOpenId());
//交易起始时间
Date startDate = new Date();
map.put("time_start", DateUtils.dateFormat(startDate, "yyyyMMddHHmmss"));
//交易结束时间
Date endDate = DateUtils.dateAddMinutes(startDate, 5);
map.put("time_expire", DateUtils.dateFormat(endDate, "yyyyMMddHHmmss"));
//获取签名并生成xml字符串
String formData = WXPayUtil.generateSignedXml(map, APISECRET);
//这里调用下单的接口
map = this.doPost("https://" + WXPayConstants.DOMAIN_API + WXPayConstants.UNIFIEDORDER_URL_SUFFIX, formData);
//app调用支付的参数
AppWxPay wxPay = new AppWxPay();
wxPay.setNonceStr(nonceStr);
wxPay.setPrepayId(map.get("prepay_id"));
wxPay.setTimeStamp(WXPayUtil.getCurrentTimestamp() + "");
//生成二次签名
String sign = this.getWxPaySign(wxPay);
wxPay.setPaySign(sign);
wxPay.setOutTradeNo(info.getOutTradeNo());
return wxPay;
}
public String getWxPaySign(AppWxPay wxPay){
Map<String, String> map = new HashMap<>();
String APISECRET = "";//填写自己的
String APPID = "";//填写自己的
map.put("appId", APPID);
map.put("nonceStr", wxPay.getNonceStr());
map.put("package", "prepay_id=" + wxPay.getPrepayId());
map.put("signType", "MD5");
map.put("timeStamp", wxPay.getTimeStamp());
String sign = WXPayUtil.generateSignature(map, APISECRET);
return sign;
}
public class AppWxPay {
private String nonceStr;
private String prepayId;
private String timeStamp;
private String paySign;
private String outTradeNo;
private String ip;
//get set
}
/**
* 返回成功xml
*/
private String resSuccessXml = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
/**
* 返回失败xml
*/
private String resFailXml = "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[报文为空]]></return_msg></xml>";
@ApiOperation( value = "支付回调" )
@RequestMapping( value = "/noticeUrl", method = RequestMethod.POST )
public void noticeUrl(HttpServletRequest request, HttpServletResponse response) {
System.out.println("------------------进入微信通知地址-----------------");
SysConfig config = configService.findSysConfig();
DataInputStream in;
String wxNotifyXml;
//通知微信回调成功 否则微信将请求八次
String resXml = resFailXml;
try {
in = new DataInputStream(request.getInputStream());
byte[] dataOrigin = new byte[request.getContentLength()];
in.readFully(dataOrigin); // 根据长度,将消息实体的内容读入字节数组dataOrigin中
in.close(); // 关闭数据流
wxNotifyXml = new String(dataOrigin); // 从字节数组中得到表示实体的字符串
Map<String, String> map = WXPayUtil.xmlToMap(wxNotifyXml);
System.out.println(map);
//判断支付是否成功
if (WXPayConstants.SUCCESS.equalsIgnoreCase(map.get("result_code"))) {
//判断签名是否正确
if (WXPayUtil.isSignatureValid(map, config.getWxApiSecret())) {
resXml = resSuccessXml;
//更改订单状态
String orderNum = map.get("out_trade_no");
} else {
WXPayUtil.getLogger().info("微信支付:判断签名错误");
}
} else {
WXPayUtil.getLogger().info("微信支付:支付失败");
}
} catch (Exception e) {
WXPayUtil.getLogger().error("微信支付:支付回调发布异常:", e);
} finally {
try {
BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
out.write(resXml.getBytes());
out.flush();
out.close();
} catch (IOException e) {
WXPayUtil.getLogger().error("微信支付:支付回调发布异常:out", e);
}
}
}
以下是微信退款https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_4
// 退款 需要证书
public void refund(AppWxRefund refund) {
Map<String, String> map = new HashMap<>();
String APPID = "";//填写自己的
String MCHID = "";//填写自己的
String APISECRET = "";//填写自己的
String nonceStr = WXPayUtil.generateNonceStr();
Random rand = new Random();
//退款单号
int randNum = rand.nextInt(9999);
String refundNo = "rf-" + System.currentTimeMillis() + randNum;
map.put("appid", APPID);
map.put("mch_id", MCHID);
map.put("nonce_str", nonceStr);
map.put("out_trade_no", refund.getOutTradeNo());
map.put("out_refund_no", refundNo);
//金额 自己设置 分为单位
map.put("total_fee", "1");
map.put("refund_fee", "1");
map.put("notify_url", "http://wx.buluofangzhou.com/app/pay/refund");
//获取签名并生成xml字符串
KeyStore keyStore = KeyStore.getInstance("PKCS12");
InputStream inputStream; // 这是自己的证书 商户名台配置得到一个证书文件
keyStore.load(inputStream, password.toCharArray());
SSLContext sslcontext = SSLContexts.custom()
.loadKeyMaterial(keyStore, password.toCharArray())//这里也是写密码的
.build();
// Allow TLSv1 protocol only
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
sslcontext,
new String[]{"TLSv1"},
null,
SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
CloseableHttpClient httpclient = HttpClients.custom()
.setSSLSocketFactory(sslsf)
.build();
String data = WXPayUtil.generateSignedXml(map, APISECRET);
try {
HttpPost httpost = new HttpPost("https://" + WXPayConstants.DOMAIN_API + WXPayConstants.REFUND_URL_SUFFIX); // 设置响应头信息
httpost.addHeader("Connection", "keep-alive");
httpost.addHeader("Accept", "*/*");
httpost.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
httpost.addHeader("Host", "api.mch.weixin.qq.com");
httpost.addHeader("X-Requested-With", "XMLHttpRequest");
httpost.addHeader("Cache-Control", "max-age=0");
httpost.addHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) ");
httpost.setEntity(new StringEntity(data, "UTF-8"));
CloseableHttpResponse response = httpclient.execute(httpost);
try {
HttpEntity entity = response.getEntity();
String jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8");
EntityUtils.consume(entity);
} finally {
response.close();
}
} finally {
httpclient.close();
}
}
微信退款需要AES 解密
java中的AES 256算法遇到 Illegal key size or default parameters错的解决办法
需要更换jre lib security 下的包local_policy.jar,US_export_policy.jar
官网下载https://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html java8
@ApiOperation( value = "微信退款回调接口" )
@RequestMapping( value = "/refund", method = RequestMethod.POST )
public void refund(HttpServletRequest request, HttpServletResponse response) {
String resXml = "";
InputStream inStream;
try {
inStream = request.getInputStream();
ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = 0;
while ((len = inStream.read(buffer)) != -1) {
outSteam.write(buffer, 0, len);
}
WXPayUtil.getLogger().info("refund:微信退款----start----");
// 获取微信调用我们notify_url的返回信息
String result = new String(outSteam.toByteArray(), "utf-8");
WXPayUtil.getLogger().info("refund:微信退款----result----=" + result);
// 关闭流
outSteam.close();
inStream.close();
// xml转换为map
Map<String, String> map = WXPayUtil.xmlToMap(result);
if (WXPayConstants.SUCCESS.equalsIgnoreCase(map.get("return_code"))) {
WXPayUtil.getLogger().info("refund:微信退款----返回成功");
String req_info = map.get("req_info");
String resultStr = AESUtil.decryptData(req_info);
Map<String, String> aesMap = WXPayUtil.xmlToMap(resultStr);
String refund_status = aesMap.get("refund_status");
String orderNum = aesMap.get("out_trade_no");
if (!WXPayConstants.SUCCESS.equals(refund_status)) {
resXml = resFailXml;
} else {
resXml = resSuccessXml;
//do something
}
} else {
WXPayUtil.getLogger().error("refund:支付失败,错误信息:" + map.get("return_msg"));
resXml = resFailXml;
}
} catch (Exception e) {
WXPayUtil.getLogger().error("refund:微信退款回调发布异常:", e);
} finally {
try {
BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
out.write(resXml.getBytes());
out.flush();
out.close();
} catch (IOException e) {
WXPayUtil.getLogger().error("refund:微信退款回调发布异常:out:", e);
}
}
}