SpringCloud集成微信支付
参照文档地址
代码里面有注释替换自己的微信参数即可
里面的加密直接搜MD5,AES加解密就可以,随机生成字符串
然后配置文件配置一下回调地址还有微信支付参数就ok了
我的支付是v2 ,也可以参考 v3支付
大概支付流程就是:生成订单 --> 调用统一API --> 生成预支付信息 --> 生成链接二维码 --> 用户打开微信扫一扫 --> 验证是否有效–>获取用户支付权限–> 确认支付–>完成支付后返回支付信息通知支付结果
直接上代码:
/**
-
@author z
*/
@Log4j2
@Api(tags = “微信支付”)
@RestController
@RequestMapping(“”)
public class WxPayController {/**
- 返回成功xml
*/
private String resSuccessXml = “<return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg>”;
/**
- 返回失败xml
*/
private String resFailXml = “<return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[报文为空]]></return_msg>”;
@Autowired
private WeixinPayProperties weixinPayProperties;@Autowired
private QrCodeRequest qrCodeRequest;/***
-
支付
-
@param data
-
@param openid
-
@return
*/
@PostMapping(“”)
@Transactional(rollbackFor = Exception.class)
public Map<String, String> payVip(@RequestBody ReportReqData data, @RequestParam(“openid”) String openid) {
Map<String, String> weixinMap = null;
try {
if (StringUtils.isEmpty(openid)) {
HashMap<String, String> map = new HashMap<>();
map.put(“data”, “openid为空”);
return map;
}
//支付信息封装对象
ReportReqData reqData = new ReportReqData();// openid reqData.setOpenid(openid); // 签约的类型JSAPI reqData.setTrade_type(weixinPayProperties.getType()); // 微信小程序的appid reqData.setAppid(weixinPayProperties.getAppid()); // 商户id reqData.setMch_id(weixinPayProperties.getMchid()); // 回调地址 如果是微信小程序不用配置也可以,最好配置 reqData.setNotify_url(weixinPayProperties.getNotifyPath()); //ip reqData.setSpbill_create_ip(IpUtil.getLocalIp4Address().get().toString().replaceAll("/", "")); //金额 reqData.setTotal_fee(getMoney(data.getTotal_fee())); //订单号 reqData.setOut_trade_no(data.getOut_trade_no()); //随机字符串 reqData.setNonce_str(getRandomStringByLength(32)); //支付信息对象 reqData.setBody(data.getBody()); log.info("操作完毕,开始发起支付"); //微信支付返回的结果 weixinMap = qrCodeRequest.submitWeixinMessage(reqData);
} catch (Exception e) {
log.error(“支付异常”);
e.printStackTrace();
}
return weixinMap;
}
/**
-
微信小程序支付成功回调函数
-
@param request
-
@param response
-
@throws Exception
*/
@PostMapping()
@Transactional(rollbackFor = Exception.class)
public Map<String, String> wxNotify(HttpServletRequest request, HttpServletResponse response) throws IOException {
Map<String, String> map = null;
String resXml = “”;
try {
BufferedReader br = new BufferedReader(new InputStreamReader((ServletInputStream) request.getInputStream()));
String line = null;
StringBuilder sb = new StringBuilder();
while ((line = br.readLine()) != null) {
sb.append(line);
}
br.close();
//sb为微信返回的xml
String notityXml = sb.toString();log.info("支付成功回调,接收到的报文:" + notityXml); if (StringUtils.isNotEmpty(notityXml)) { map = XMLParser.getMapFromXML(notityXml); String returnCode = map.get("return_code"); if ("SUCCESS".equals(returnCode)) { resXml = resSuccessXml; log.info("支付成功回调,最终信息 :" + map); } else { resXml = resFailXml; } } else { resXml = resFailXml; }
} catch (Exception e) {
log.error(“微信小程序支付回调异常”);
e.printStackTrace();
} finally {
BufferedOutputStream out = new BufferedOutputStream(
response.getOutputStream());
out.write(resXml.getBytes());
out.flush();
out.close();log.info("退款回调返回信息给微信:" + resXml);
}
return map;
}
/***
*@param outTradeNo 商户订单号
@param outrefundNo 商户退款单号 商户系统内部的退款单号,商户系统内部唯一,只能是数字、大小写字母_-|@ ,同一退款单号多次请求只退一笔
*@param refund 退款金额-
@param total 原订单金额
-
@return
*/
@GetMapping()
@Transactional(rollbackFor = Exception.class)
public Map<String, String> refund(String outTradeNo, String outrefundNo, String refund, String total, String refundRemark, String nickName) {HashMap<String, String> data = new HashMap<String, String>();
try {
data.put(“appid”, weixinPayProperties.getAppid());
data.put(“mch_id”, weixinPayProperties.getMchid());
//回调地址
data.put(“notify_url”, weixinPayProperties.getRefundPath());
data.put(“sign_type”, “MD5”);
data.put(“out_trade_no”, outTradeNo);
//商户退款单号
data.put(“out_refund_no”, outrefundNo);
//退款金额
data.put(“refund_fee”, getMoney(refund));
//原订单金额
data.put(“total_fee”, getMoney(total));
//退款币种
data.put(“refund_fee_type”, “CNY”);
//随机字符串
data.put(“nonce_str”, getRandomStringByLength(32));
//MD5运算生成签名,这里是第一次签名,用于调用统一下单接口
String sign = Signature.getSign(data, weixinPayProperties.getAppsecret());
data.put(“sign”, sign);
log.info(“操作完毕,发起退款请求”);
//发起退款请求
String returnData = doRefoud(weixinPayProperties.getRefund(), data);
if (StringUtils.isNotEmpty(returnData)) {
log.info(“当前退款成功返回的数据: ============>{}”, returnData);
//解析返回的字符串 并且组成map集合
Map<String, String> map = XMLParser.getMapFromXML(returnData);
if (null != map && !map.isEmpty()) {
String resultCode = (String) map.get(“result_code”);
//链接生成成功
if (“SUCCESS”.equals(resultCode)) {
HashMap<String, String> nmap = new HashMap<>();
nmap.put(“appId”, data.get(“appid”));
nmap.put(“mchId”, data.get(“mch_id”));
nmap.put(“nonceStr”, data.get(“notify_url”));
nmap.put(“timeStamp”, System.currentTimeMillis() + “”);
nmap.put(“signType”, “MD5”);
nmap.put(“paySign”, Signature.getSign(nmap, weixinPayProperties.getAppsecret()));
//transaction_id 微信支付订单号
nmap.put(“transactionId”, map.get(“transaction_id”));
//商户订单号
nmap.put(“outTradeNo”, data.get(“out_trade_no”) + “”);
//商户退款单号
nmap.put(“outRefundNo”, data.get(“out_refund_no”));
//微信退款单号
nmap.put(“refund_id”, map.get(“refund_id”));
//退款金额
nmap.put(“refundfee”, map.get(“refund_fee”));
//标价金额
nmap.put(“totalfee”, map.get(“total_fee”));log.info("退款请求完成"); return nmap; } else { return map; } } else { return map; } }
} catch (Exception e) {
log.error(“退款异常”);
e.printStackTrace();
}
return null;
}
/***
-
退款回调
-
@param request
-
@param response
*/
@PostMapping(“/weixin/callbackRefund”)
@Transactional(rollbackFor = Exception.class)
public Map<String, String> refund(HttpServletRequest request, HttpServletResponse response) throws Exception {
Map<String, String> aesMap = null;
String resXml = null;
try {
BufferedReader br = new BufferedReader(new InputStreamReader((ServletInputStream) request.getInputStream()));
String line;
StringBuilder sb = new StringBuilder();
while ((line = br.readLine()) != null) {
sb.append(line);
}
br.close();
//sb为微信返回的xml
String notityXml = sb.toString();log.info("退款回调接收到的报文:" + notityXml); if (StringUtils.isNotEmpty(notityXml)) { Map<String, String> map = XMLParser.getMapFromXML(notityXml); if (!map.isEmpty()) { String resultCode = (String) map.get("return_code"); if ("SUCCESS".equals(resultCode)) { resXml = resSuccessXml; String reqInfo = map.get("req_info"); String s = AESUtil.decryptData(reqInfo, WeixinPayProperties.WX_OPEN_APP_SECRET); Map<String, String> stringStringMap = WXPayUtil.xmlToMap(s); log.info("解密的数据:" + stringStringMap); } else { resXml = resFailXml; } } else { resXml = resFailXml; } }
} catch (Exception e) {
log.error("退款回调异常信息 ");
e.printStackTrace();
} finally {
BufferedOutputStream out = new BufferedOutputStream(
response.getOutputStream());
out.write(resXml.getBytes());
out.flush();
out.close();log.info("退款回调返回信息给微信:" + resXml);
}
return aesMap;
}
/**
- 退款
- @param dataMap
*/
public String doRefoud(String url, Map<String, String> dataMap) throws Exception {
String xmlString = WXPayUtil.mapToXml(dataMap);
//证书 是从微信商户平台-》账户设置-》 API安全 中下载的
KeyStore keyStore = KeyStore.getInstance(“”);
//TODO 证书
ClassPathResource classPathResource = new ClassPathResource(“”);
InputStream inputStream = classPathResource.getInputStream();
try {
//这里写密码,默认是MCHID
keyStore.load(inputStream, weixinPayProperties.getMchid().toCharArray());
} finally {
inputStream.close();
}
SSLContext sslContext = SSLContexts.custom().loadKeyMaterial(keyStore, weixinPayProperties.getMchid().toCharArray()).build();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, SSLConnectionSocketFactory.getDefaultHostnameVerifier());
CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
String jsonStr = null;
try {
//请求路径
HttpPost httpPost = new HttpPost(url);
httpPost.setEntity(new StringEntity(xmlString, “UTF-8”));
CloseableHttpResponse response = httpClient.execute(httpPost);
try {
HttpEntity entity = response.getEntity();
//接受到返回信息
jsonStr = EntityUtils.toString(response.getEntity(), “UTF-8”);
EntityUtils.consume(entity);
} finally {
response.close();
}
} finally {
httpClient.close();
}
return jsonStr;
}
- 返回成功xml
}