WxNotifyController.java 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  1. package com.miaxis.app.controller.wx;
  2. import com.alibaba.fastjson.JSONObject;
  3. import com.miaxis.common.config.WxpayConfig;
  4. import com.miaxis.common.constant.Constants;
  5. import com.miaxis.common.exception.CustomException;
  6. import com.miaxis.common.utils.AesUtil;
  7. import com.miaxis.common.utils.DateUtils;
  8. import com.miaxis.newgzpt.domain.GzptUserInfo;
  9. import com.miaxis.newgzpt.domain.GzptVideoVip;
  10. import com.miaxis.newgzpt.dto.GzptVideoVipDTO;
  11. import com.miaxis.newgzpt.service.IGzptUserInfoService;
  12. import com.miaxis.newgzpt.service.IGzptVideoVipService;
  13. import com.miaxis.system.service.ISysUserService;
  14. import com.miaxis.wx.domain.RefundRecord;
  15. import com.miaxis.wx.domain.WxJsOrder;
  16. import com.miaxis.wx.domain.WxOrder;
  17. import com.miaxis.wx.dto.*;
  18. import com.miaxis.wx.service.IRefundRecordService;
  19. import com.miaxis.wx.service.IWxJsOrderService;
  20. import com.wechat.pay.contrib.apache.httpclient.auth.AutoUpdateCertificatesVerifier;
  21. import io.swagger.annotations.Api;
  22. import io.swagger.annotations.ApiOperation;
  23. import lombok.Data;
  24. import lombok.RequiredArgsConstructor;
  25. import lombok.extern.slf4j.Slf4j;
  26. import org.joda.time.DateTime;
  27. import org.springframework.beans.factory.annotation.Autowired;
  28. import org.springframework.beans.factory.annotation.Value;
  29. import org.springframework.transaction.annotation.Transactional;
  30. import org.springframework.util.Base64Utils;
  31. import org.springframework.web.bind.annotation.PostMapping;
  32. import org.springframework.web.bind.annotation.RequestBody;
  33. import org.springframework.web.bind.annotation.RequestMapping;
  34. import org.springframework.web.bind.annotation.RestController;
  35. import javax.servlet.http.HttpServletRequest;
  36. import java.io.BufferedReader;
  37. import java.io.IOException;
  38. import java.nio.charset.StandardCharsets;
  39. import java.security.*;
  40. import java.security.cert.X509Certificate;
  41. import java.util.Date;
  42. @RestController
  43. @RequiredArgsConstructor
  44. @RequestMapping(Constants.OPEN_PREFIX+"/wx/notify")
  45. @Api(tags = {"【APP-微信回调】"})
  46. @Slf4j
  47. public class WxNotifyController {
  48. @Autowired
  49. private WxpayConfig wxpayConfig;
  50. @Autowired
  51. private IWxJsOrderService wxJsOrderService;
  52. @Autowired
  53. private IRefundRecordService refundRecordService;
  54. @Autowired
  55. private AutoUpdateCertificatesVerifier verifier;
  56. @Autowired
  57. private IGzptUserInfoService userInfoService;
  58. @Autowired
  59. private IGzptVideoVipService videoVipService;
  60. /**
  61. * 微信支付回调接口
  62. */
  63. @PostMapping(value = "/wxpay")
  64. @ApiOperation("微信支付回调")
  65. public WxNotifyReturnDTO wxpayNotify(@RequestBody WxpayNotifyDTO wxpayNotifyDTO, HttpServletRequest request) throws GeneralSecurityException, IOException {
  66. String bodyString = getBodyString(request);
  67. if (!validate(request,bodyString)){
  68. throw new CustomException("签名失败");
  69. }
  70. String resourceString = getSourString(wxpayNotifyDTO);
  71. log.info(resourceString);
  72. JSONObject jsonObject = JSONObject.parseObject(resourceString);
  73. //将回调数据写入数据库
  74. writeNotifyDataToDb(jsonObject);
  75. WxNotifyReturnDTO wxNotifyReturnDTO = new WxNotifyReturnDTO();
  76. wxNotifyReturnDTO.setCode("SUCCESS");
  77. wxNotifyReturnDTO.setMessage("成功");
  78. return wxNotifyReturnDTO;
  79. }
  80. private String getBodyString(HttpServletRequest request) {
  81. BufferedReader br = null;
  82. StringBuilder sb = new StringBuilder("");
  83. try
  84. {
  85. br = request.getReader();
  86. String str;
  87. while ((str = br.readLine()) != null)
  88. {
  89. sb.append(str);
  90. }
  91. br.close();
  92. }
  93. catch (IOException e)
  94. {
  95. e.printStackTrace();
  96. }
  97. finally
  98. {
  99. if (null != br)
  100. {
  101. try
  102. {
  103. br.close();
  104. }
  105. catch (IOException e)
  106. {
  107. e.printStackTrace();
  108. }
  109. }
  110. }
  111. return sb.toString();
  112. }
  113. private Boolean validate(HttpServletRequest request, String bodyString) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
  114. String sign = request.getHeader("Wechatpay-Signature");
  115. String timestamp = request.getHeader("Wechatpay-Timestamp");
  116. String nonce = request.getHeader("Wechatpay-Nonce");
  117. StringBuffer sb = new StringBuffer();
  118. sb.append(timestamp + "\n");
  119. sb.append(nonce + "\n");
  120. sb.append(bodyString + "\n");
  121. X509Certificate validCertificate = verifier.getValidCertificate();
  122. // 进行签名服务
  123. Signature signature = Signature.getInstance("SHA256withRSA");
  124. // 用微信平台公钥对签名器进行初始化
  125. signature.initVerify(validCertificate);
  126. // 把我们构造的验签名串更新到签名器中
  127. signature.update(sb.toString().getBytes(StandardCharsets.UTF_8));
  128. Boolean result = signature.verify(Base64Utils.decodeFromString(sign));
  129. log.info("微信支付回调验签:"+result.toString());
  130. return result;
  131. }
  132. /**
  133. * 微信退款回调
  134. */
  135. @PostMapping(value = "/refund")
  136. @ApiOperation("微信退款回调")
  137. public WxNotifyReturnDTO refundNotify(@RequestBody WxpayNotifyDTO wxpayNotifyDTO, HttpServletRequest request) throws GeneralSecurityException, IOException {
  138. String bodyString = getBodyString(request);
  139. if (!validate(request,bodyString)){
  140. throw new CustomException("签名失败");
  141. }
  142. String resourceString = getSourString(wxpayNotifyDTO);
  143. log.info(resourceString);
  144. JSONObject jsonObject = JSONObject.parseObject(resourceString);
  145. //将回调数据写入数据库
  146. writeRefundNotifyDataToDb(jsonObject);
  147. WxNotifyReturnDTO wxNotifyReturnDTO = new WxNotifyReturnDTO();
  148. wxNotifyReturnDTO.setCode("SUCCESS");
  149. wxNotifyReturnDTO.setMessage("成功");
  150. return wxNotifyReturnDTO;
  151. }
  152. private void writeRefundNotifyDataToDb(JSONObject jsonObject) {
  153. String refundId = jsonObject.getString("refund_id");
  154. String outTradeNo = jsonObject.getString("out_trade_no");
  155. RefundRecord refundRecord = refundRecordService.getByRefundId(refundId);
  156. if (refundRecord == null) {
  157. log.error("该退款订单不存在");
  158. return;
  159. }
  160. refundRecord.setTransactionId(jsonObject.getString("transaction_id"));
  161. refundRecord.setUserReceivedAccount(jsonObject.getString("user_received_account"));
  162. refundRecord.setStatus(jsonObject.getString("refund_status"));
  163. refundRecordService.updateById(refundRecord);
  164. if("SUCCESS".equals(refundRecord.getStatus())){
  165. //退款成功
  166. long oneYearLong = 1000*60*60*24*365l;
  167. WxJsOrder wxJsOrder= wxJsOrderService.getByOutTradeNo(outTradeNo);
  168. if ("科目二视频".equals(wxJsOrder.getGoodsName())){
  169. GzptVideoVipDTO gzptVideoVipDTO = new GzptVideoVipDTO();
  170. gzptVideoVipDTO.setUserId(wxJsOrder.getUserId());
  171. GzptVideoVip gv = videoVipService.getGzptVideoVipByUserIdForLocal(gzptVideoVipDTO);
  172. if(gv!=null) {
  173. //修改会员信息
  174. Date km2Date = gv.getSubject2();
  175. if(km2Date!=null) { //扣掉一年时间
  176. long x = km2Date.getTime() - oneYearLong;
  177. Date km2oneYear = new Date(x);
  178. gv.setSubject2(km2oneYear);
  179. videoVipService.updateGzptVideoVipByUserId(gv);
  180. }
  181. }
  182. } else if ("科目三视频".equals(wxJsOrder.getGoodsName())) {
  183. GzptVideoVipDTO gzptVideoVipDTO = new GzptVideoVipDTO();
  184. gzptVideoVipDTO.setUserId(wxJsOrder.getUserId());
  185. GzptVideoVip gv = videoVipService.getGzptVideoVipByUserIdForLocal(gzptVideoVipDTO);
  186. if(gv!=null) {
  187. //修改会员信息
  188. Date km3Date = gv.getSubject3();
  189. if(km3Date!=null) { //扣掉一年时间
  190. long x = km3Date.getTime() - oneYearLong;
  191. Date km3oneYear = new Date(x);
  192. gv.setSubject3(km3oneYear);
  193. videoVipService.updateGzptVideoVipByUserId(gv);
  194. }
  195. }
  196. } else if ("全套实操视频".equals(wxJsOrder.getGoodsName())) {
  197. GzptVideoVipDTO gzptVideoVipDTO = new GzptVideoVipDTO();
  198. gzptVideoVipDTO.setUserId(wxJsOrder.getUserId());
  199. GzptVideoVip gv = videoVipService.getGzptVideoVipByUserIdForLocal(gzptVideoVipDTO);
  200. if(gv!=null) {
  201. //修改会员信息
  202. Date km2Date = gv.getSubject2();
  203. Date km3Date = gv.getSubject3();
  204. if(km2Date!=null) { //扣掉一年时间
  205. long x = km2Date.getTime() - oneYearLong;
  206. Date km2oneYear = new Date(x);
  207. gv.setSubject2(km2oneYear);
  208. }
  209. if(km3Date!=null) { //扣掉一年时间
  210. long x = km3Date.getTime() - oneYearLong;
  211. Date km3oneYear = new Date(x);
  212. gv.setSubject3(km3oneYear);
  213. }
  214. videoVipService.updateGzptVideoVipByUserId(gv);
  215. }
  216. }
  217. }
  218. }
  219. @Transactional
  220. public void writeNotifyDataToDb(JSONObject jsonObject) {
  221. System.out.println(jsonObject);
  222. String outTradeNo = jsonObject.getString("out_trade_no");
  223. WxJsOrder wxJsOrder = wxJsOrderService.getByOutTradeNo(outTradeNo);
  224. if (wxJsOrder == null) {
  225. log.error("该订单不存在");
  226. return;
  227. }
  228. if("SUCCESS".equals(wxJsOrder.getTradeState())){
  229. log.info("订单号为"+wxJsOrder.getOutTradeNo()+"的订单已完成操作,无法重复操作!");
  230. return;
  231. }
  232. wxJsOrder.setTransactionId(jsonObject.getString("transaction_id"));
  233. JSONObject amount = jsonObject.getJSONObject("amount");
  234. wxJsOrder.setPayerTotal(amount.getInteger("payer_total"));
  235. wxJsOrder.setTotal(amount.getInteger("total"));
  236. wxJsOrder.setCurrency(amount.getString("currency"));
  237. wxJsOrder.setPayerCurrency(amount.getString("payer_currency"));
  238. wxJsOrder.setTradeState(jsonObject.getString("trade_state"));
  239. wxJsOrder.setBankType(jsonObject.getString("bank_type"));
  240. DateTime dateTime = new DateTime(jsonObject.getString("success_time"));
  241. wxJsOrder.setSuccessTime(dateTime.toDate());
  242. wxJsOrder.setTradeStateDesc(jsonObject.getString("trade_state_desc"));
  243. wxJsOrder.setTradeType(jsonObject.getString("trade_type"));
  244. wxJsOrder.setAttach(jsonObject.getString("attach"));
  245. //插入VIP信息
  246. writeVipDataToDb(wxJsOrder);
  247. wxJsOrderService.updateById(wxJsOrder);
  248. }
  249. @Transactional
  250. public void writeVipDataToDb(WxJsOrder wxJsOrder) {
  251. long oneYearLong = 1000*60*60*24*365l;
  252. Date now = new Date();
  253. if ("科目二视频".equals(wxJsOrder.getGoodsName())){
  254. GzptVideoVipDTO gzptVideoVipDTO = new GzptVideoVipDTO();
  255. gzptVideoVipDTO.setUserId(wxJsOrder.getUserId());
  256. GzptVideoVip gv = videoVipService.getGzptVideoVipByUserIdForLocal(gzptVideoVipDTO);
  257. if(gv!=null) {
  258. //修改会员信息
  259. Date km2Date = gv.getSubject2();
  260. if(km2Date!=null) { //存在会员时间
  261. if(km2Date.compareTo(now)<0) { //会员已过期
  262. long x = now.getTime() + oneYearLong;
  263. Date km2oneYear = new Date(x);
  264. gv.setSubject2(km2oneYear);
  265. videoVipService.updateGzptVideoVipByUserId(gv);
  266. } else { //会员时间延长
  267. long x = km2Date.getTime() + oneYearLong;
  268. Date km2oneYear = new Date(x);
  269. gv.setSubject2(km2oneYear);
  270. videoVipService.updateGzptVideoVipByUserId(gv);
  271. }
  272. } else {
  273. long x = now.getTime() + oneYearLong;
  274. Date km2oneYear = new Date(x);
  275. gv.setSubject2(km2oneYear);
  276. videoVipService.updateGzptVideoVipByUserId(gv);
  277. }
  278. } else {
  279. //新增会员信息
  280. GzptVideoVip videoVip = new GzptVideoVip();
  281. videoVip.setUserId(wxJsOrder.getUserId());
  282. videoVip.setUserName(wxJsOrder.getUserName());
  283. long x = now.getTime() + oneYearLong;
  284. Date km2oneYear = new Date(x);
  285. videoVip.setSubject2(km2oneYear);
  286. videoVipService.saveGzptVideoVip(videoVip);
  287. }
  288. } else if ("科目三视频".equals(wxJsOrder.getGoodsName())) {
  289. GzptVideoVipDTO gzptVideoVipDTO = new GzptVideoVipDTO();
  290. gzptVideoVipDTO.setUserId(wxJsOrder.getUserId());
  291. GzptVideoVip gv = videoVipService.getGzptVideoVipByUserIdForLocal(gzptVideoVipDTO);
  292. if(gv!=null) {
  293. //修改会员信息
  294. Date km3Date = gv.getSubject3();
  295. if(km3Date!=null) { //存在会员时间
  296. if(km3Date.compareTo(now)<0) { //会员已过期
  297. long x = now.getTime() + oneYearLong;
  298. Date km3oneYear = new Date(x);
  299. gv.setSubject3(km3oneYear);
  300. videoVipService.updateGzptVideoVipByUserId(gv);
  301. } else { //会员时间延长
  302. long x = km3Date.getTime() + oneYearLong;
  303. Date km3oneYear = new Date(x);
  304. gv.setSubject3(km3oneYear);
  305. videoVipService.updateGzptVideoVipByUserId(gv);
  306. }
  307. } else {
  308. long x = now.getTime() + oneYearLong;
  309. Date km3oneYear = new Date(x);
  310. gv.setSubject3(km3oneYear);
  311. videoVipService.updateGzptVideoVipByUserId(gv);
  312. }
  313. } else {
  314. //新增会员信息
  315. GzptVideoVip videoVip = new GzptVideoVip();
  316. videoVip.setUserId(wxJsOrder.getUserId());
  317. videoVip.setUserName(wxJsOrder.getUserName());
  318. long x = now.getTime() + oneYearLong;
  319. Date km3oneYear = new Date(x);
  320. videoVip.setSubject3(km3oneYear);
  321. videoVipService.saveGzptVideoVip(videoVip);
  322. }
  323. } else if ("全套实操视频".equals(wxJsOrder.getGoodsName())) {
  324. GzptVideoVipDTO gzptVideoVipDTO = new GzptVideoVipDTO();
  325. gzptVideoVipDTO.setUserId(wxJsOrder.getUserId());
  326. GzptVideoVip gv = videoVipService.getGzptVideoVipByUserIdForLocal(gzptVideoVipDTO);
  327. if(gv!=null) {
  328. //修改会员信息
  329. Date km2Date = gv.getSubject2();
  330. Date km3Date = gv.getSubject3();
  331. if(km2Date!=null) { //科目二处理
  332. long x = km2Date.getTime() + oneYearLong;
  333. Date km2oneYear = new Date(x);
  334. gv.setSubject2(km2oneYear);
  335. } else {
  336. long x = now.getTime() + oneYearLong;
  337. Date km2oneYear = new Date(x);
  338. gv.setSubject2(km2oneYear);
  339. }
  340. if(km3Date!=null) { //科目三处理
  341. long x = km3Date.getTime() + oneYearLong;
  342. Date km3oneYear = new Date(x);
  343. gv.setSubject3(km3oneYear);
  344. } else {
  345. long x = now.getTime() + oneYearLong;
  346. Date km3oneYear = new Date(x);
  347. gv.setSubject3(km3oneYear);
  348. }
  349. videoVipService.updateGzptVideoVipByUserId(gv);
  350. } else {
  351. //新增会员信息
  352. GzptVideoVip videoVip = new GzptVideoVip();
  353. videoVip.setUserId(wxJsOrder.getUserId());
  354. videoVip.setUserName(wxJsOrder.getUserName());
  355. long x = now.getTime() + oneYearLong;
  356. Date oneYear = new Date(x);
  357. videoVip.setSubject2(oneYear);
  358. videoVip.setSubject3(oneYear);
  359. videoVipService.saveGzptVideoVip(videoVip);
  360. }
  361. }
  362. }
  363. private String getSourString(WxpayNotifyDTO wxpayNotifyDTO) throws GeneralSecurityException, IOException {
  364. AesUtil aesUtil = new AesUtil(wxpayConfig.getV3key().getBytes());
  365. WxpayNotifyDTO.WxpaySource wxpaySource = wxpayNotifyDTO.getResource();
  366. return aesUtil.decryptToString(wxpaySource.getAssociated_data().getBytes(), wxpaySource.getNonce().getBytes(), wxpaySource.getCiphertext());
  367. }
  368. @Data
  369. public class FilmNotifyReturnDTO {
  370. String code;
  371. String message;
  372. Boolean success;
  373. }
  374. }