123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416 |
- package com.miaxis.app.controller.wx;
- import com.alibaba.fastjson.JSONObject;
- import com.miaxis.common.config.WxpayConfig;
- import com.miaxis.common.constant.Constants;
- import com.miaxis.common.exception.CustomException;
- import com.miaxis.common.utils.AesUtil;
- import com.miaxis.common.utils.DateUtils;
- import com.miaxis.newgzpt.domain.GzptUserInfo;
- import com.miaxis.newgzpt.domain.GzptVideoVip;
- import com.miaxis.newgzpt.dto.GzptVideoVipDTO;
- import com.miaxis.newgzpt.service.IGzptUserInfoService;
- import com.miaxis.newgzpt.service.IGzptVideoVipService;
- import com.miaxis.system.service.ISysUserService;
- import com.miaxis.wx.domain.RefundRecord;
- import com.miaxis.wx.domain.WxJsOrder;
- import com.miaxis.wx.domain.WxOrder;
- import com.miaxis.wx.dto.*;
- import com.miaxis.wx.service.IRefundRecordService;
- import com.miaxis.wx.service.IWxJsOrderService;
- import com.wechat.pay.contrib.apache.httpclient.auth.AutoUpdateCertificatesVerifier;
- import io.swagger.annotations.Api;
- import io.swagger.annotations.ApiOperation;
- import lombok.Data;
- import lombok.RequiredArgsConstructor;
- import lombok.extern.slf4j.Slf4j;
- import org.joda.time.DateTime;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.beans.factory.annotation.Value;
- import org.springframework.transaction.annotation.Transactional;
- import org.springframework.util.Base64Utils;
- import org.springframework.web.bind.annotation.PostMapping;
- import org.springframework.web.bind.annotation.RequestBody;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RestController;
- import javax.servlet.http.HttpServletRequest;
- import java.io.BufferedReader;
- import java.io.IOException;
- import java.nio.charset.StandardCharsets;
- import java.security.*;
- import java.security.cert.X509Certificate;
- import java.util.Date;
- @RestController
- @RequiredArgsConstructor
- @RequestMapping(Constants.OPEN_PREFIX+"/wx/notify")
- @Api(tags = {"【APP-微信回调】"})
- @Slf4j
- public class WxNotifyController {
- @Autowired
- private WxpayConfig wxpayConfig;
- @Autowired
- private IWxJsOrderService wxJsOrderService;
- @Autowired
- private IRefundRecordService refundRecordService;
- @Autowired
- private AutoUpdateCertificatesVerifier verifier;
- @Autowired
- private IGzptUserInfoService userInfoService;
- @Autowired
- private IGzptVideoVipService videoVipService;
- /**
- * 微信支付回调接口
- */
- @PostMapping(value = "/wxpay")
- @ApiOperation("微信支付回调")
- public WxNotifyReturnDTO wxpayNotify(@RequestBody WxpayNotifyDTO wxpayNotifyDTO, HttpServletRequest request) throws GeneralSecurityException, IOException {
- String bodyString = getBodyString(request);
- if (!validate(request,bodyString)){
- throw new CustomException("签名失败");
- }
- String resourceString = getSourString(wxpayNotifyDTO);
- log.info(resourceString);
- JSONObject jsonObject = JSONObject.parseObject(resourceString);
- //将回调数据写入数据库
- writeNotifyDataToDb(jsonObject);
- WxNotifyReturnDTO wxNotifyReturnDTO = new WxNotifyReturnDTO();
- wxNotifyReturnDTO.setCode("SUCCESS");
- wxNotifyReturnDTO.setMessage("成功");
- return wxNotifyReturnDTO;
- }
- private String getBodyString(HttpServletRequest request) {
- BufferedReader br = null;
- StringBuilder sb = new StringBuilder("");
- try
- {
- br = request.getReader();
- String str;
- while ((str = br.readLine()) != null)
- {
- sb.append(str);
- }
- br.close();
- }
- catch (IOException e)
- {
- e.printStackTrace();
- }
- finally
- {
- if (null != br)
- {
- try
- {
- br.close();
- }
- catch (IOException e)
- {
- e.printStackTrace();
- }
- }
- }
- return sb.toString();
- }
- private Boolean validate(HttpServletRequest request, String bodyString) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
- String sign = request.getHeader("Wechatpay-Signature");
- String timestamp = request.getHeader("Wechatpay-Timestamp");
- String nonce = request.getHeader("Wechatpay-Nonce");
- StringBuffer sb = new StringBuffer();
- sb.append(timestamp + "\n");
- sb.append(nonce + "\n");
- sb.append(bodyString + "\n");
- X509Certificate validCertificate = verifier.getValidCertificate();
- // 进行签名服务
- Signature signature = Signature.getInstance("SHA256withRSA");
- // 用微信平台公钥对签名器进行初始化
- signature.initVerify(validCertificate);
- // 把我们构造的验签名串更新到签名器中
- signature.update(sb.toString().getBytes(StandardCharsets.UTF_8));
- Boolean result = signature.verify(Base64Utils.decodeFromString(sign));
- log.info("微信支付回调验签:"+result.toString());
- return result;
- }
- /**
- * 微信退款回调
- */
- @PostMapping(value = "/refund")
- @ApiOperation("微信退款回调")
- public WxNotifyReturnDTO refundNotify(@RequestBody WxpayNotifyDTO wxpayNotifyDTO, HttpServletRequest request) throws GeneralSecurityException, IOException {
- String bodyString = getBodyString(request);
- if (!validate(request,bodyString)){
- throw new CustomException("签名失败");
- }
- String resourceString = getSourString(wxpayNotifyDTO);
- log.info(resourceString);
- JSONObject jsonObject = JSONObject.parseObject(resourceString);
- //将回调数据写入数据库
- writeRefundNotifyDataToDb(jsonObject);
- WxNotifyReturnDTO wxNotifyReturnDTO = new WxNotifyReturnDTO();
- wxNotifyReturnDTO.setCode("SUCCESS");
- wxNotifyReturnDTO.setMessage("成功");
- return wxNotifyReturnDTO;
- }
- private void writeRefundNotifyDataToDb(JSONObject jsonObject) {
- String refundId = jsonObject.getString("refund_id");
- String outTradeNo = jsonObject.getString("out_trade_no");
- RefundRecord refundRecord = refundRecordService.getByRefundId(refundId);
- if (refundRecord == null) {
- log.error("该退款订单不存在");
- return;
- }
- refundRecord.setTransactionId(jsonObject.getString("transaction_id"));
- refundRecord.setUserReceivedAccount(jsonObject.getString("user_received_account"));
- refundRecord.setStatus(jsonObject.getString("refund_status"));
- refundRecordService.updateById(refundRecord);
- if("SUCCESS".equals(refundRecord.getStatus())){
- //退款成功
- long oneYearLong = 1000*60*60*24*365l;
- WxJsOrder wxJsOrder= wxJsOrderService.getByOutTradeNo(outTradeNo);
- if ("科目二视频".equals(wxJsOrder.getGoodsName())){
- GzptVideoVipDTO gzptVideoVipDTO = new GzptVideoVipDTO();
- gzptVideoVipDTO.setUserId(wxJsOrder.getUserId());
- GzptVideoVip gv = videoVipService.getGzptVideoVipByUserIdForLocal(gzptVideoVipDTO);
- if(gv!=null) {
- //修改会员信息
- Date km2Date = gv.getSubject2();
- if(km2Date!=null) { //扣掉一年时间
- long x = km2Date.getTime() - oneYearLong;
- Date km2oneYear = new Date(x);
- gv.setSubject2(km2oneYear);
- videoVipService.updateGzptVideoVipByUserId(gv);
- }
- }
- } else if ("科目三视频".equals(wxJsOrder.getGoodsName())) {
- GzptVideoVipDTO gzptVideoVipDTO = new GzptVideoVipDTO();
- gzptVideoVipDTO.setUserId(wxJsOrder.getUserId());
- GzptVideoVip gv = videoVipService.getGzptVideoVipByUserIdForLocal(gzptVideoVipDTO);
- if(gv!=null) {
- //修改会员信息
- Date km3Date = gv.getSubject3();
- if(km3Date!=null) { //扣掉一年时间
- long x = km3Date.getTime() - oneYearLong;
- Date km3oneYear = new Date(x);
- gv.setSubject3(km3oneYear);
- videoVipService.updateGzptVideoVipByUserId(gv);
- }
- }
- } else if ("全套实操视频".equals(wxJsOrder.getGoodsName())) {
- GzptVideoVipDTO gzptVideoVipDTO = new GzptVideoVipDTO();
- gzptVideoVipDTO.setUserId(wxJsOrder.getUserId());
- GzptVideoVip gv = videoVipService.getGzptVideoVipByUserIdForLocal(gzptVideoVipDTO);
- if(gv!=null) {
- //修改会员信息
- Date km2Date = gv.getSubject2();
- Date km3Date = gv.getSubject3();
- if(km2Date!=null) { //扣掉一年时间
- long x = km2Date.getTime() - oneYearLong;
- Date km2oneYear = new Date(x);
- gv.setSubject2(km2oneYear);
- }
- if(km3Date!=null) { //扣掉一年时间
- long x = km3Date.getTime() - oneYearLong;
- Date km3oneYear = new Date(x);
- gv.setSubject3(km3oneYear);
- }
- videoVipService.updateGzptVideoVipByUserId(gv);
- }
- }
- }
- }
- @Transactional
- public void writeNotifyDataToDb(JSONObject jsonObject) {
- System.out.println(jsonObject);
- String outTradeNo = jsonObject.getString("out_trade_no");
- WxJsOrder wxJsOrder = wxJsOrderService.getByOutTradeNo(outTradeNo);
- if (wxJsOrder == null) {
- log.error("该订单不存在");
- return;
- }
- if("SUCCESS".equals(wxJsOrder.getTradeState())){
- log.info("订单号为"+wxJsOrder.getOutTradeNo()+"的订单已完成操作,无法重复操作!");
- return;
- }
- wxJsOrder.setTransactionId(jsonObject.getString("transaction_id"));
- JSONObject amount = jsonObject.getJSONObject("amount");
- wxJsOrder.setPayerTotal(amount.getInteger("payer_total"));
- wxJsOrder.setTotal(amount.getInteger("total"));
- wxJsOrder.setCurrency(amount.getString("currency"));
- wxJsOrder.setPayerCurrency(amount.getString("payer_currency"));
- wxJsOrder.setTradeState(jsonObject.getString("trade_state"));
- wxJsOrder.setBankType(jsonObject.getString("bank_type"));
- DateTime dateTime = new DateTime(jsonObject.getString("success_time"));
- wxJsOrder.setSuccessTime(dateTime.toDate());
- wxJsOrder.setTradeStateDesc(jsonObject.getString("trade_state_desc"));
- wxJsOrder.setTradeType(jsonObject.getString("trade_type"));
- wxJsOrder.setAttach(jsonObject.getString("attach"));
- //插入VIP信息
- writeVipDataToDb(wxJsOrder);
- wxJsOrderService.updateById(wxJsOrder);
- }
- @Transactional
- public void writeVipDataToDb(WxJsOrder wxJsOrder) {
- long oneYearLong = 1000*60*60*24*365l;
- Date now = new Date();
- if ("科目二视频".equals(wxJsOrder.getGoodsName())){
- GzptVideoVipDTO gzptVideoVipDTO = new GzptVideoVipDTO();
- gzptVideoVipDTO.setUserId(wxJsOrder.getUserId());
- GzptVideoVip gv = videoVipService.getGzptVideoVipByUserIdForLocal(gzptVideoVipDTO);
- if(gv!=null) {
- //修改会员信息
- Date km2Date = gv.getSubject2();
- if(km2Date!=null) { //存在会员时间
- if(km2Date.compareTo(now)<0) { //会员已过期
- long x = now.getTime() + oneYearLong;
- Date km2oneYear = new Date(x);
- gv.setSubject2(km2oneYear);
- videoVipService.updateGzptVideoVipByUserId(gv);
- } else { //会员时间延长
- long x = km2Date.getTime() + oneYearLong;
- Date km2oneYear = new Date(x);
- gv.setSubject2(km2oneYear);
- videoVipService.updateGzptVideoVipByUserId(gv);
- }
- } else {
- long x = now.getTime() + oneYearLong;
- Date km2oneYear = new Date(x);
- gv.setSubject2(km2oneYear);
- videoVipService.updateGzptVideoVipByUserId(gv);
- }
- } else {
- //新增会员信息
- GzptVideoVip videoVip = new GzptVideoVip();
- videoVip.setUserId(wxJsOrder.getUserId());
- videoVip.setUserName(wxJsOrder.getUserName());
- long x = now.getTime() + oneYearLong;
- Date km2oneYear = new Date(x);
- videoVip.setSubject2(km2oneYear);
- videoVipService.saveGzptVideoVip(videoVip);
- }
- } else if ("科目三视频".equals(wxJsOrder.getGoodsName())) {
- GzptVideoVipDTO gzptVideoVipDTO = new GzptVideoVipDTO();
- gzptVideoVipDTO.setUserId(wxJsOrder.getUserId());
- GzptVideoVip gv = videoVipService.getGzptVideoVipByUserIdForLocal(gzptVideoVipDTO);
- if(gv!=null) {
- //修改会员信息
- Date km3Date = gv.getSubject3();
- if(km3Date!=null) { //存在会员时间
- if(km3Date.compareTo(now)<0) { //会员已过期
- long x = now.getTime() + oneYearLong;
- Date km3oneYear = new Date(x);
- gv.setSubject3(km3oneYear);
- videoVipService.updateGzptVideoVipByUserId(gv);
- } else { //会员时间延长
- long x = km3Date.getTime() + oneYearLong;
- Date km3oneYear = new Date(x);
- gv.setSubject3(km3oneYear);
- videoVipService.updateGzptVideoVipByUserId(gv);
- }
- } else {
- long x = now.getTime() + oneYearLong;
- Date km3oneYear = new Date(x);
- gv.setSubject3(km3oneYear);
- videoVipService.updateGzptVideoVipByUserId(gv);
- }
- } else {
- //新增会员信息
- GzptVideoVip videoVip = new GzptVideoVip();
- videoVip.setUserId(wxJsOrder.getUserId());
- videoVip.setUserName(wxJsOrder.getUserName());
- long x = now.getTime() + oneYearLong;
- Date km3oneYear = new Date(x);
- videoVip.setSubject3(km3oneYear);
- videoVipService.saveGzptVideoVip(videoVip);
- }
- } else if ("全套实操视频".equals(wxJsOrder.getGoodsName())) {
- GzptVideoVipDTO gzptVideoVipDTO = new GzptVideoVipDTO();
- gzptVideoVipDTO.setUserId(wxJsOrder.getUserId());
- GzptVideoVip gv = videoVipService.getGzptVideoVipByUserIdForLocal(gzptVideoVipDTO);
- if(gv!=null) {
- //修改会员信息
- Date km2Date = gv.getSubject2();
- Date km3Date = gv.getSubject3();
- if(km2Date!=null) { //科目二处理
- long x = km2Date.getTime() + oneYearLong;
- Date km2oneYear = new Date(x);
- gv.setSubject2(km2oneYear);
- } else {
- long x = now.getTime() + oneYearLong;
- Date km2oneYear = new Date(x);
- gv.setSubject2(km2oneYear);
- }
- if(km3Date!=null) { //科目三处理
- long x = km3Date.getTime() + oneYearLong;
- Date km3oneYear = new Date(x);
- gv.setSubject3(km3oneYear);
- } else {
- long x = now.getTime() + oneYearLong;
- Date km3oneYear = new Date(x);
- gv.setSubject3(km3oneYear);
- }
- videoVipService.updateGzptVideoVipByUserId(gv);
- } else {
- //新增会员信息
- GzptVideoVip videoVip = new GzptVideoVip();
- videoVip.setUserId(wxJsOrder.getUserId());
- videoVip.setUserName(wxJsOrder.getUserName());
- long x = now.getTime() + oneYearLong;
- Date oneYear = new Date(x);
- videoVip.setSubject2(oneYear);
- videoVip.setSubject3(oneYear);
- videoVipService.saveGzptVideoVip(videoVip);
- }
- }
- }
- private String getSourString(WxpayNotifyDTO wxpayNotifyDTO) throws GeneralSecurityException, IOException {
- AesUtil aesUtil = new AesUtil(wxpayConfig.getV3key().getBytes());
- WxpayNotifyDTO.WxpaySource wxpaySource = wxpayNotifyDTO.getResource();
- return aesUtil.decryptToString(wxpaySource.getAssociated_data().getBytes(), wxpaySource.getNonce().getBytes(), wxpaySource.getCiphertext());
- }
- @Data
- public class FilmNotifyReturnDTO {
- String code;
- String message;
- Boolean success;
- }
- }
|