PayController.java 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494
  1. package com.ylx.web.controller.massage;
  2. import cn.hutool.core.date.DatePattern;
  3. import cn.hutool.core.date.DateUtil;
  4. import cn.hutool.core.io.file.FileWriter;
  5. import cn.hutool.core.util.StrUtil;
  6. import cn.hutool.http.ContentType;
  7. import cn.hutool.json.JSONArray;
  8. import cn.hutool.json.JSONObject;
  9. import cn.hutool.json.JSONUtil;
  10. import com.ijpay.core.IJPayHttpResponse;
  11. import com.ijpay.core.enums.AuthTypeEnum;
  12. import com.ijpay.core.enums.RequestMethodEnum;
  13. import com.ijpay.core.kit.AesUtil;
  14. import com.ijpay.core.kit.HttpKit;
  15. import com.ijpay.core.kit.PayKit;
  16. import com.ijpay.core.kit.WxPayKit;
  17. import com.ijpay.core.utils.DateTimeZoneUtil;
  18. import com.ijpay.wxpay.WxPayApi;
  19. import com.ijpay.wxpay.WxPayApiConfigKit;
  20. import com.ijpay.wxpay.enums.WxDomainEnum;
  21. import com.ijpay.wxpay.enums.v3.BasePayApiEnum;
  22. import com.ijpay.wxpay.enums.v3.CertAlgorithmTypeEnum;
  23. import com.ijpay.wxpay.enums.v3.TransferApiEnum;
  24. import com.ijpay.wxpay.model.v3.*;
  25. import com.wechat.pay.java.service.partnerpayments.jsapi.JsapiServiceExtension;
  26. import com.ylx.common.config.WxPayConfig;
  27. import com.ylx.common.core.domain.R;
  28. import com.ylx.massage.domain.TRecharge;
  29. import com.ylx.massage.enums.BillTypeEnum;
  30. import com.ylx.massage.service.RefundVoucherService;
  31. import com.ylx.massage.service.TOrderService;
  32. import com.ylx.massage.service.TRechargeService;
  33. import io.swagger.annotations.Api;
  34. import io.swagger.annotations.ApiOperation;
  35. import lombok.extern.slf4j.Slf4j;
  36. import org.springframework.beans.factory.annotation.Autowired;
  37. import org.springframework.web.bind.annotation.*;
  38. import javax.annotation.Resource;
  39. import javax.servlet.http.HttpServletRequest;
  40. import javax.servlet.http.HttpServletResponse;
  41. import java.io.ByteArrayInputStream;
  42. import java.math.BigDecimal;
  43. import java.nio.charset.StandardCharsets;
  44. import java.security.cert.X509Certificate;
  45. import java.util.*;
  46. import static com.ylx.common.constant.HttpStatus.SUCCESS;
  47. /**
  48. * @author jianlong
  49. * @date 2024-04-03 15:27
  50. */
  51. @RestController
  52. @Slf4j
  53. @RequestMapping("/wx/pay")
  54. @Api(tags = {"微信支付"})
  55. public class PayController {
  56. @Autowired
  57. private WxPayConfig wxPayProperties;
  58. @Resource
  59. private TRechargeService rechargeService;
  60. @Resource
  61. private TOrderService orderService;
  62. @Resource
  63. private RefundVoucherService refundVoucherService;
  64. // @Resource
  65. // private JsapiServiceExtension service;
  66. String serialNo;
  67. String platSerialNo;
  68. /**
  69. * 小程序微信支付的第一步,统一下单
  70. */
  71. @PostMapping("/pay")
  72. @ApiOperation("AIPV3微信支付充值")
  73. public R createUnifiedOrder(@RequestBody TRecharge recharge) throws Exception {
  74. TRecharge rechargeResp = rechargeService.recharge(recharge);
  75. return rechargeService.getPay(rechargeResp.getRechargeNo(), recharge.getdMoney(), recharge.getcOpenId(), BillTypeEnum.RECHARGE.getInfo(), BillTypeEnum.RECHARGE.getCode().toString());
  76. }
  77. /**
  78. * 支付
  79. * @param setOutTradeNo
  80. * @param amount
  81. * @param openId
  82. * @param description
  83. * @return
  84. * @throws Exception
  85. */
  86. public R<String> getPay(String setOutTradeNo, BigDecimal amount, String openId, String description) throws Exception {
  87. String timeExpire = DateTimeZoneUtil.dateToTimeZone(System.currentTimeMillis() + 1000 * 60 * 3);
  88. UnifiedOrderModel unifiedOrderModel = new UnifiedOrderModel()
  89. .setAppid(wxPayProperties.getAppId())
  90. .setMchid(wxPayProperties.getMchId())
  91. //商品描述
  92. .setDescription(description)
  93. //订单号
  94. .setOut_trade_no(setOutTradeNo)
  95. //交易结束时间
  96. .setTime_expire(timeExpire)
  97. //附加数据
  98. .setAttach("夜来香")
  99. //通知地址异步接收微信支付结果通知的回调地址,通知url必须为外网可访问的url,不能携带参数。 公网域名必须为https,如果是走专线接入,使用专线NAT IP或者私有回调域名可使用http
  100. //示例值:https://www.weixin.qq.com/wxpay/pay.php
  101. .setNotify_url(wxPayProperties.getNotifyUrl())
  102. //支付金额以分为单位
  103. .setAmount(new Amount().setTotal(amount.multiply(new BigDecimal(100)).intValue()))
  104. //交易人
  105. .setPayer(new Payer().setOpenid(openId));
  106. log.info("统一下单参数 {}", JSONUtil.toJsonStr(unifiedOrderModel));
  107. IJPayHttpResponse response = WxPayApi.v3(
  108. RequestMethodEnum.POST,
  109. WxDomainEnum.CHINA.toString(),
  110. BasePayApiEnum.JS_API_PAY.toString(),
  111. wxPayProperties.getMchId(),
  112. getSerialNumber(),
  113. null,
  114. wxPayProperties.getCertKeyPath(),
  115. JSONUtil.toJsonStr(unifiedOrderModel)
  116. );
  117. log.info("统一下单响应 {}", response);
  118. // 根据证书序列号查询对应的证书来验证签名结果
  119. boolean verifySignature = WxPayKit.verifySignature(response, wxPayProperties.getPlatFormPath());
  120. log.info("verifySignature: {}", verifySignature);
  121. if (response.getStatus() == SUCCESS && verifySignature) {
  122. String body = response.getBody();
  123. JSONObject jsonObject = JSONUtil.parseObj(body);
  124. String prepayId = jsonObject.getStr("prepay_id");
  125. Map<String, String> map = WxPayKit.jsApiCreateSign(wxPayProperties.getAppId(), prepayId, wxPayProperties.getCertKeyPath());
  126. log.info("唤起支付参数:{}", map);
  127. return R.ok(JSONUtil.toJsonStr(map));
  128. }
  129. return R.ok(JSONUtil.toJsonStr(response));
  130. }
  131. //服务商模式下单
  132. public R<String> getPay1(String setOutTradeNo, BigDecimal amount, String openId, String description) throws Exception {
  133. String timeExpire = DateTimeZoneUtil.dateToTimeZone(System.currentTimeMillis() + 1000 * 60 * 3);
  134. UnifiedOrderModel unifiedOrderModel = new UnifiedOrderModel()
  135. .setSp_appid(wxPayProperties.getAppId())
  136. .setSp_mchid(wxPayProperties.getMchId())
  137. .setSub_mchid("123")//子商户号
  138. //商品描述
  139. .setDescription(description)
  140. //订单号
  141. .setOut_trade_no(setOutTradeNo)
  142. //交易结束时间
  143. .setTime_expire(timeExpire)
  144. //附加数据
  145. .setAttach("夜来香")
  146. //通知地址异步接收微信支付结果通知的回调地址,通知url必须为外网可访问的url,不能携带参数。 公网域名必须为https,如果是走专线接入,使用专线NAT IP或者私有回调域名可使用http
  147. //示例值:https://www.weixin.qq.com/wxpay/pay.php
  148. .setNotify_url(wxPayProperties.getNotifyUrl())
  149. //分账标识
  150. .setSettle_info(new SettleInfo().setProfit_sharing(true))
  151. //支付金额以分为单位
  152. .setAmount(new Amount().setTotal(amount.multiply(new BigDecimal(100)).intValue()))
  153. //交易人
  154. .setPayer(new Payer().setSp_openid(openId));
  155. log.info("统一下单参数 {}", JSONUtil.toJsonStr(unifiedOrderModel));
  156. IJPayHttpResponse response = WxPayApi.v3(
  157. RequestMethodEnum.POST,
  158. WxDomainEnum.CHINA.toString(),
  159. BasePayApiEnum.PARTNER_JS_API_PAY.toString(),
  160. wxPayProperties.getMchId(),
  161. getSerialNumber(),
  162. null,
  163. wxPayProperties.getCertKeyPath(),
  164. JSONUtil.toJsonStr(unifiedOrderModel)
  165. );
  166. log.info("统一下单响应 {}", response);
  167. // 根据证书序列号查询对应的证书来验证签名结果
  168. boolean verifySignature = WxPayKit.verifySignature(response, wxPayProperties.getPlatFormPath());
  169. log.info("verifySignature: {}", verifySignature);
  170. if (response.getStatus() == SUCCESS && verifySignature) {
  171. String body = response.getBody();
  172. JSONObject jsonObject = JSONUtil.parseObj(body);
  173. String prepayId = jsonObject.getStr("prepay_id");
  174. Map<String, String> map = WxPayKit.jsApiCreateSign(wxPayProperties.getAppId(), prepayId, wxPayProperties.getCertKeyPath());
  175. log.info("唤起支付参数:{}", map);
  176. return R.ok(JSONUtil.toJsonStr(map));
  177. }
  178. return R.ok(JSONUtil.toJsonStr(response));
  179. }
  180. private String getSerialNumber() {
  181. if (StrUtil.isEmpty(serialNo)) {
  182. // 获取证书序列号
  183. X509Certificate certificate = PayKit.getCertificate(wxPayProperties.getCertPath());
  184. if (null != certificate) {
  185. serialNo = certificate.getSerialNumber().toString(16).toUpperCase();
  186. // 提前两天检查证书是否有效
  187. boolean isValid = PayKit.checkCertificateIsValid(certificate, wxPayProperties.getMchId(), -2);
  188. log.info("证书是否可用 {} 证书有效期为 {}", isValid, DateUtil.format(certificate.getNotAfter(), DatePattern.NORM_DATETIME_PATTERN));
  189. }
  190. // System.out.println("输出证书信息:\n" + certificate.toString());
  191. // // 输出关键信息,截取部分并进行标记
  192. // System.out.println("证书序列号:" + certificate.getSerialNumber().toString(16));
  193. // System.out.println("版本号:" + certificate.getVersion());
  194. // System.out.println("签发者:" + certificate.getIssuerDN());
  195. // System.out.println("有效起始日期:" + certificate.getNotBefore());
  196. // System.out.println("有效终止日期:" + certificate.getNotAfter());
  197. // System.out.println("主体名:" + certificate.getSubjectDN());
  198. // System.out.println("签名算法:" + certificate.getSigAlgName());
  199. // System.out.println("签名:" + certificate.getSignature().toString());
  200. }
  201. System.out.println("serialNo:" + serialNo);
  202. return serialNo;
  203. }
  204. @RequestMapping(value = "/payNotify", method = {org.springframework.web.bind.annotation.RequestMethod.POST, org.springframework.web.bind.annotation.RequestMethod.GET})
  205. @ResponseBody
  206. @ApiOperation("微信支付回调接口")
  207. public void payNotify(HttpServletRequest request, HttpServletResponse response) {
  208. log.info("微信支付回调接口====================================>>>>微信支付回调接口");
  209. Map<String, String> map = new HashMap<>(12);
  210. try {
  211. String timestamp = request.getHeader("Wechatpay-Timestamp");
  212. String nonce = request.getHeader("Wechatpay-Nonce");
  213. String serialNo = request.getHeader("Wechatpay-Serial");
  214. String signature = request.getHeader("Wechatpay-Signature");
  215. log.info("timestamp:{} nonce:{} serialNo:{} signature:{}", timestamp, nonce, serialNo, signature);
  216. String result = HttpKit.readData(request);
  217. log.info("支付通知密文 {}", result);
  218. // 需要通过证书序列号查找对应的证书,verifyNotify 中有验证证书的序列号
  219. String plainText = WxPayKit.verifyNotify(serialNo, result, signature, nonce, timestamp,
  220. wxPayProperties.getMchKey(), wxPayProperties.getPlatFormPath());
  221. log.info("支付通知明文 {}", plainText);
  222. if (StrUtil.isNotEmpty(plainText)) {
  223. response.setStatus(200);
  224. map.put("code", "SUCCESS");
  225. map.put("message", "SUCCESS");
  226. // 处理业务逻辑
  227. JSONObject jsonObject = new JSONObject(plainText);
  228. if (jsonObject.get("attach").equals(BillTypeEnum.WX_PAY.getCode().toString())) {
  229. // 订单支付成功
  230. orderService.payNotifyOrder(jsonObject.get("out_trade_no").toString());
  231. } else {
  232. TRecharge outTradeNo = rechargeService.increaseAmount(jsonObject.get("out_trade_no").toString());
  233. }
  234. } else {
  235. response.setStatus(500);
  236. map.put("code", "ERROR");
  237. map.put("message", "签名错误");
  238. }
  239. response.setHeader("Content-type", ContentType.JSON.toString());
  240. response.getOutputStream().write(JSONUtil.toJsonStr(map).getBytes(StandardCharsets.UTF_8));
  241. response.flushBuffer();
  242. } catch (Exception e) {
  243. log.error("系统异常", e);
  244. }
  245. }
  246. @RequestMapping(value = "/test", method = {org.springframework.web.bind.annotation.RequestMethod.POST, org.springframework.web.bind.annotation.RequestMethod.GET})
  247. @ResponseBody
  248. @ApiOperation("测试")
  249. public void test(HttpServletRequest request, HttpServletResponse response) {
  250. System.out.println("test=======================>");
  251. }
  252. @RequestMapping("/get")
  253. @ResponseBody
  254. public String v3Get() throws Exception {
  255. // 获取平台证书列表
  256. try {
  257. IJPayHttpResponse response = WxPayApi.v3(
  258. RequestMethodEnum.GET,
  259. WxDomainEnum.CHINA.toString(),
  260. CertAlgorithmTypeEnum.getCertSuffixUrl(CertAlgorithmTypeEnum.RSA.getCode()),
  261. wxPayProperties.getMchId(),
  262. getSerialNumber(),
  263. null,
  264. wxPayProperties.getCertKeyPath(),
  265. "",
  266. AuthTypeEnum.RSA.getCode()
  267. );
  268. Map<String, List<String>> headers = response.getHeaders();
  269. log.info("请求头: {}", headers);
  270. String timestamp = response.getHeader("Wechatpay-Timestamp");
  271. String nonceStr = response.getHeader("Wechatpay-Nonce");
  272. String serialNumber = response.getHeader("Wechatpay-Serial");
  273. String signature = response.getHeader("Wechatpay-Signature");
  274. String body = response.getBody();
  275. int status = response.getStatus();
  276. log.info("serialNumber: {}", serialNumber);
  277. log.info("status: {}", status);
  278. log.info("body: {}", body);
  279. int isOk = 200;
  280. if (status == isOk) {
  281. JSONObject jsonObject = JSONUtil.parseObj(body);
  282. JSONArray dataArray = jsonObject.getJSONArray("data");
  283. // 默认认为只有一个平台证书
  284. JSONObject encryptObject = dataArray.getJSONObject(0);
  285. JSONObject encryptCertificate = encryptObject.getJSONObject("encrypt_certificate");
  286. String associatedData = encryptCertificate.getStr("associated_data");
  287. String cipherText = encryptCertificate.getStr("ciphertext");
  288. String nonce = encryptCertificate.getStr("nonce");
  289. String algorithm = encryptCertificate.getStr("algorithm");
  290. String serialNo = encryptObject.getStr("serial_no");
  291. final String platSerialNo = savePlatformCert(associatedData, nonce, cipherText, algorithm, wxPayProperties.getPlatFormPath());
  292. log.info("平台证书序列号: {} serialNo: {}", platSerialNo, serialNo);
  293. // 根据证书序列号查询对应的证书来验证签名结果
  294. boolean verifySignature = WxPayKit.verifySignature(response, wxPayProperties.getPlatFormPath());
  295. log.info("verifySignature:{}", verifySignature);
  296. }
  297. return body;
  298. } catch (Exception e) {
  299. log.error("获取平台证书列表异常", e);
  300. return null;
  301. }
  302. }
  303. private String savePlatformCert(String associatedData, String nonce, String cipherText, String algorithm, String certPath) {
  304. try {
  305. String key3 = wxPayProperties.getMchKey();
  306. String publicKey;
  307. if (StrUtil.equals(algorithm, AuthTypeEnum.SM2.getPlatformCertAlgorithm())) {
  308. publicKey = PayKit.sm4DecryptToString(key3, cipherText, nonce, associatedData);
  309. } else {
  310. AesUtil aesUtil = new AesUtil(wxPayProperties.getMchKey().getBytes(StandardCharsets.UTF_8));
  311. // 平台证书密文解密
  312. // encrypt_certificate 中的 associated_data nonce ciphertext
  313. publicKey = aesUtil.decryptToString(
  314. associatedData.getBytes(StandardCharsets.UTF_8),
  315. nonce.getBytes(StandardCharsets.UTF_8),
  316. cipherText
  317. );
  318. }
  319. if (StrUtil.isNotEmpty(publicKey)) {
  320. // 保存证书
  321. FileWriter writer = new FileWriter(certPath);
  322. writer.write(publicKey);
  323. // 获取平台证书序列号
  324. X509Certificate certificate = PayKit.getCertificate(new ByteArrayInputStream(publicKey.getBytes()));
  325. return certificate.getSerialNumber().toString(16).toUpperCase();
  326. }
  327. return "";
  328. } catch (Exception e) {
  329. log.error("保存平台证书异常", e);
  330. return e.getMessage();
  331. }
  332. }
  333. @RequestMapping("/batchTransfer")
  334. @ApiOperation("微信批量提现")
  335. @ResponseBody
  336. public String batchTransfer(@RequestParam(value = "openId", required = false, defaultValue = "o-_-itxuXeGW3O1cxJ7FXNmq8Wf8") String openId) {
  337. try {
  338. BatchTransferModel batchTransferModel = new BatchTransferModel()
  339. .setAppid(wxPayProperties.getAppId())
  340. .setOut_batch_no(PayKit.generateStr())
  341. .setBatch_name("IJPay 测试微信转账到零钱")
  342. .setBatch_remark("IJPay 测试微信转账到零钱")
  343. .setTotal_amount(1)
  344. .setTotal_num(1)
  345. .setTransfer_detail_list(Collections.singletonList(
  346. new TransferDetailInput()
  347. .setOut_detail_no(PayKit.generateStr())
  348. .setTransfer_amount(1)
  349. .setTransfer_remark("IJPay 测试微信转账到零钱")
  350. .setOpenid(openId)));
  351. log.info("发起商家转账请求参数 {}", JSONUtil.toJsonStr(batchTransferModel));
  352. IJPayHttpResponse response = WxPayApi.v3(
  353. RequestMethodEnum.POST,
  354. WxDomainEnum.CHINA.toString(),
  355. TransferApiEnum.TRANSFER_BATCHES.toString(),
  356. wxPayProperties.getMchId(),
  357. getSerialNumber(),
  358. null,
  359. wxPayProperties.getCertKeyPath(),
  360. JSONUtil.toJsonStr(batchTransferModel)
  361. );
  362. log.info("发起商家转账响应 {}", response);
  363. // 根据证书序列号查询对应的证书来验证签名结果
  364. boolean verifySignature = WxPayKit.verifySignature(response, wxPayProperties.getPlatFormPath());
  365. log.info("verifySignature: {}", verifySignature);
  366. if (response.getStatus() == SUCCESS && verifySignature) {
  367. return response.getBody();
  368. }
  369. return JSONUtil.toJsonStr(response);
  370. } catch (Exception e) {
  371. log.error("系统异常", e);
  372. return e.getMessage();
  373. }
  374. }
  375. /**
  376. * 退款
  377. * @param outRefundNo 退款订单号
  378. * @param amount 退款金额
  379. * @param transactionId 微信支付订单号
  380. * @param outTradeNo 商户订单号
  381. * @return String
  382. */
  383. @RequestMapping("/refund")
  384. @ResponseBody
  385. public String refund(@RequestParam(required = false) String outRefundNo, @RequestParam(required = false) BigDecimal amount,@RequestParam(required = false) String transactionId, @RequestParam(required = false) String outTradeNo) {
  386. return rechargeService.refund(outRefundNo,transactionId,outTradeNo,amount);
  387. }
  388. // /**
  389. // * 退款通知
  390. // */
  391. // @RequestMapping(value = "/refundNotify", method = {RequestMethod.POST, RequestMethod.GET})
  392. // @ResponseBody
  393. // @ApiOperation("微信退款回调接口")
  394. // public String refundNotify(HttpServletRequest request) {
  395. // String xmlMsg = HttpKit.readData(request);
  396. // log.info("退款通知=" + xmlMsg);
  397. // Map<String, String> params = WxPayKit.xmlToMap(xmlMsg);
  398. // log.info("退款通知parms:{}",params);
  399. // String returnCode = params.get("event_type");
  400. // // 注意重复通知的情况,同一订单号可能收到多次通知,请注意一定先判断订单状态
  401. // if (returnCode.equals("REFUND.SUCCESS")) {
  402. // String reqInfo = params.get("resource");
  403. // String decryptData = WxPayKit.decryptData(reqInfo, WxPayApiConfigKit.getWxPayApiConfig().getPartnerKey());
  404. // log.info("退款通知解密后的数据=" + decryptData);
  405. //// refundVoucherService.
  406. // // 更新订单信息
  407. // // 发送通知等
  408. // Map<String, String> xml = new HashMap<String, String>(2);
  409. // xml.put("return_code", "SUCCESS");
  410. // xml.put("return_msg", "OK");
  411. // return WxPayKit.toXml(xml);
  412. // }
  413. // return null;
  414. // }
  415. @ApiOperation("微信退款回调接口")
  416. @RequestMapping(value = "/refundNotify", method = {org.springframework.web.bind.annotation.RequestMethod.POST, org.springframework.web.bind.annotation.RequestMethod.GET})
  417. public void refundWechatCallback(HttpServletRequest request, HttpServletResponse response) {
  418. log.info("微信退款回调接口====================================>>>>微信退款回调接口");
  419. Map<String, String> map = new HashMap<>(12);
  420. try {
  421. String timestamp = request.getHeader("Wechatpay-Timestamp");
  422. String nonce = request.getHeader("Wechatpay-Nonce");
  423. String serialNo = request.getHeader("Wechatpay-Serial");
  424. String signature = request.getHeader("Wechatpay-Signature");
  425. log.info("timestamp:{} nonce:{} serialNo:{} signature:{}", timestamp, nonce, serialNo, signature);
  426. String result = HttpKit.readData(request);
  427. log.info("退款通知密文 {}", result);
  428. // 需要通过证书序列号查找对应的证书,verifyNotify 中有验证证书的序列号
  429. String plainText = WxPayKit.verifyNotify(serialNo, result, signature, nonce, timestamp,
  430. wxPayProperties.getMchKey(), wxPayProperties.getPlatFormPath());
  431. log.info("退款通知明文 {}", plainText);
  432. if (StrUtil.isNotEmpty(plainText)) {
  433. response.setStatus(200);
  434. map.put("code", "SUCCESS");
  435. map.put("message", "SUCCESS");
  436. // 处理业务逻辑
  437. JSONObject jsonObject = new JSONObject(plainText);
  438. //退款单号
  439. String refundNo = jsonObject.get("out_refund_no").toString();
  440. refundVoucherService.refundWechatCallback(refundNo);
  441. } else {
  442. response.setStatus(500);
  443. map.put("code", "ERROR");
  444. map.put("message", "签名错误");
  445. }
  446. response.setHeader("Content-type", ContentType.JSON.toString());
  447. response.getOutputStream().write(JSONUtil.toJsonStr(map).getBytes(StandardCharsets.UTF_8));
  448. response.flushBuffer();
  449. } catch (Exception e) {
  450. log.error("系统异常", e);
  451. }
  452. }
  453. }