| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925 |
- package com.dtb.portal.service.impl;
- import com.dtb.portal.config.WxPayAppConfig;
- import com.dtb.portal.config.WxPayMiniprogramConfig;
- import com.dtb.portal.config.interceptor.TokenUtils;
- import com.dtb.portal.controller.view.response.ResultMap;
- import com.dtb.portal.entity.AppPayData;
- import com.dtb.portal.entity.MiniprogramPayData;
- import com.dtb.portal.entity.VipGoodsData;
- import com.dtb.portal.entity.VipOrderData;
- import com.dtb.portal.entity.VipUserData;
- import com.dtb.portal.entity.SysUser;
- import com.dtb.portal.mapper.SysUserMapper;
- import com.dtb.portal.service.VipGoodsService;
- import com.dtb.portal.service.WxPayService;
- import com.dtb.portal.util.DateUtils;
- import com.dtb.portal.util.PrimaryIdUtils;
- import com.github.wxpay.sdk.WXPay;
- import com.github.wxpay.sdk.WXPayConstants;
- import com.github.wxpay.sdk.WXPayUtil;
- import com.wechat.pay.java.core.Config;
- import com.wechat.pay.java.core.RSAAutoCertificateConfig;
- import com.wechat.pay.java.core.cipher.SignatureResult;
- import com.wechat.pay.java.service.payments.app.AppService;
- import com.wechat.pay.java.service.payments.app.AppServiceExtension;
- import com.wechat.pay.java.service.payments.app.model.*;
- import com.wechat.pay.java.service.payments.jsapi.JsapiService;
- import com.wechat.pay.java.service.payments.jsapi.model.*;
- import com.wechat.pay.java.service.payments.jsapi.model.Payer;
- import com.wechat.pay.java.service.payments.model.Transaction;
- import org.apache.commons.lang3.StringUtils;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.beans.factory.annotation.Value;
- import org.springframework.stereotype.Service;
- import java.io.IOException;
- import java.time.LocalDateTime;
- import java.util.*;
- import static java.util.Objects.requireNonNull;
- @Service
- public class WxPayServiceImpl implements WxPayService {
- private final Logger logger = LoggerFactory.getLogger(WxPayServiceImpl.class);
- @Value("${wxpay.app.v3-key}")
- private String v3Key;
- @Autowired
- private SysUserMapper sysUserMapper;
- /* private HttpClient httpClient;
- private WxPayServiceImpl(HttpClient httpClient) {
- this.httpClient = httpClient;
- }*/
- @Autowired
- private WxPayAppConfig wxPayAppConfig;
- @Autowired
- private WxPayMiniprogramConfig wxPayMiniprogramConfig;
- @Autowired
- private VipGoodsService vipGoodsService;
- /**
- * @param vipGoodsId : 订单编号
- * @return
- */
- @Override
- public ResultMap unifiedOrder(String vipGoodsId) {
- Map<String, String> returnMap = new HashMap<>();
- Map<String, String> responseMap = new HashMap<>();
- Map<String, String> requestMap = new HashMap<>();
- String orderNo = "";
- try {
- VipGoodsData vipGoodsData = vipGoodsService.getById(vipGoodsId);
- if (Objects.isNull(vipGoodsData)) {
- throw new RuntimeException("商品不存在");
- }
- String vipMoney = vipGoodsData.getVipMoney();
- double amount = Double.parseDouble(vipMoney);
- orderNo = PrimaryIdUtils.getId().toString();
- WXPay wxpay = new WXPay(wxPayAppConfig);
- requestMap.put("body", vipGoodsData.getName()); // 商品描述
- requestMap.put("out_trade_no", orderNo); // 商户订单号
- requestMap.put("total_fee", String.valueOf((int) (amount * 100))); // 总金额
- //requestMap.put("spbill_create_ip", HttpContextUtils.getIpAddr()); // 终端IP
- requestMap.put("trade_type", "APP"); // App支付类型
- requestMap.put("notify_url", wxPayAppConfig.getPayNotifyUrl()); // 接收微信支付异步通知回调地址
- Map<String, String> resultMap = wxpay.unifiedOrder(requestMap);
- logger.info("下单返回的信息是:{}", resultMap);
- //获取返回码
- String returnCode = resultMap.get("return_code");
- //String returnMsg = resultMap.get("return_msg");
- //若返回码为SUCCESS,则会返回一个result_code,再对该result_code进行判断
- if ("SUCCESS".equals(returnCode)) {
- String resultCode = resultMap.get("result_code");
- String errCodeDes = resultMap.get("err_code_des");
- if ("SUCCESS".equals(resultCode)) {
- responseMap = resultMap;
- }
- }
- if (responseMap.isEmpty()) {
- return ResultMap.error("获取预支付交易会话标识失败");
- }
- // 3、签名生成算法
- Long time = System.currentTimeMillis() / 1000;
- String timestamp = time.toString();
- returnMap.put("appid", wxPayAppConfig.getAppID());
- returnMap.put("partnerid", wxPayAppConfig.getMchID());
- returnMap.put("prepayid", responseMap.get("prepay_id"));
- returnMap.put("noncestr", responseMap.get("nonce_str"));
- returnMap.put("timestamp", timestamp);
- returnMap.put("package", "Sign=WXPay");
- returnMap.put("sign", responseMap.get("sign"));
- returnMap.put("out_trade_no", orderNo);
- String signMD5 = WXPayUtil.generateSignature(returnMap, wxPayAppConfig.getKey(), WXPayConstants.SignType.MD5);
- String signSHA256 = WXPayUtil.generateSignature(returnMap, wxPayAppConfig.getKey(), WXPayConstants.SignType.HMACSHA256);
- returnMap.put("signMD5", signMD5);
- returnMap.put("signSHA256", signSHA256);
- returnMap.put("base64SignMD5", Base64.getEncoder().encodeToString(signMD5.getBytes()));
- returnMap.put("base64SignSHA256", Base64.getEncoder().encodeToString(signSHA256.getBytes()));
- returnMap.put("key", wxPayAppConfig.getKey());
- logger.info("返回的信息是:{}", returnMap);
- return ResultMap.ok().put("data", returnMap);
- } catch (Exception e) {
- logger.error("订单号:{},错误信息:{}", orderNo, e.getMessage());
- return ResultMap.error("微信支付统一下单失败");
- } finally {
- //生成订单在数据库
- VipOrderData data = new VipOrderData();
- data.setId(PrimaryIdUtils.getId().toString());
- data.setOutTradeNo(orderNo);
- data.setStatus("1");
- data.setVipGoodsId(vipGoodsId);
- data.setCreateTime(LocalDateTime.now());
- data.setUpdateTime(LocalDateTime.now());
- vipGoodsService.insertVipOrderData(data);
- }
- }
- @Override
- public String notify(String notifyStr) {
- String xmlBack = "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[报文为空]]></return_msg></xml> ";
- try {
- // 转换成map
- Map<String, String> resultMap = WXPayUtil.xmlToMap(notifyStr);
- WXPay wxpayApp = new WXPay(wxPayAppConfig);
- if (wxpayApp.isPayResultNotifySignatureValid(resultMap)) {
- String returnCode = resultMap.get("return_code"); //状态
- String outTradeNo = resultMap.get("out_trade_no");//商户订单号
- String transactionId = resultMap.get("transaction_id");
- if (returnCode.equals("SUCCESS")) {
- if (StringUtils.isNotBlank(outTradeNo)) {
- /**
- * 注意!!!
- * 请根据业务流程,修改数据库订单支付状态,和其他数据的相应状态
- *
- */
- logger.info("微信手机支付回调成功,订单号:{}", outTradeNo);
- xmlBack = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
- }
- }
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- return xmlBack;
- }
- @Override
- public ResultMap refund(String orderNo, double amount, String refundReason) {
- if (StringUtils.isBlank(orderNo)) {
- return ResultMap.error("订单编号不能为空");
- }
- if (amount <= 0) {
- return ResultMap.error("退款金额必须大于0");
- }
- Map<String, String> responseMap = new HashMap<>();
- Map<String, String> requestMap = new HashMap<>();
- WXPay wxpay = new WXPay(wxPayAppConfig);
- requestMap.put("out_trade_no", orderNo);
- requestMap.put("out_refund_no", UUID.randomUUID().toString().replaceAll("-", ""));
- requestMap.put("total_fee", "订单支付时的总金额,需要从数据库查");
- requestMap.put("refund_fee", String.valueOf((int) (amount * 100)));//所需退款金额
- requestMap.put("refund_desc", refundReason);
- try {
- responseMap = wxpay.refund(requestMap);
- } catch (Exception e) {
- e.printStackTrace();
- }
- String return_code = responseMap.get("return_code"); //返回状态码
- String return_msg = responseMap.get("return_msg"); //返回信息
- if ("SUCCESS".equals(return_code)) {
- String result_code = responseMap.get("result_code"); //业务结果
- String err_code_des = responseMap.get("err_code_des"); //错误代码描述
- if ("SUCCESS".equals(result_code)) {
- //表示退款申请接受成功,结果通过退款查询接口查询
- //修改用户订单状态为退款申请中或已退款。退款异步通知根据需求,可选
- return ResultMap.ok("退款申请成功");
- } else {
- logger.info("订单号:{}错误信息:{}", orderNo, err_code_des);
- return ResultMap.error(err_code_des);
- }
- } else {
- logger.info("订单号:{}错误信息:{}", orderNo, return_msg);
- return ResultMap.error(return_msg);
- }
- }
- /**
- * @param vipGoodsId 商品主键
- * @return
- */
- @Override
- public AppPayData unifiedOrder2(String vipGoodsId) {
- logger.info("微信APP支付基础信息:{}", wxPayAppConfig);
- //查询商品是否存在,存在则下单,不存在则不下单
- VipGoodsData data = vipGoodsService.getById(vipGoodsId);
- if (Objects.isNull(data)) {
- throw new RuntimeException("VIP商品不存在");
- }
- // 使用自动更新平台证书的RSA配置
- // 一个商户号只能初始化一个配置,否则会因为重复的下载任务报错
- Config config =
- new RSAAutoCertificateConfig.Builder()
- .merchantId(wxPayAppConfig.getMchID())
- .privateKeyFromPath(wxPayAppConfig.getCertPath())
- .merchantSerialNumber(wxPayAppConfig.getMerchantSerialNumber())
- //.apiV3Key(wxPayAppConfig.getKey())
- .apiV3Key(v3Key)
- .build();
- // 构建service
- AppService service = new AppService.Builder().config(config).build();
- String orderNo = PrimaryIdUtils.getId().toString();
- com.wechat.pay.java.service.payments.app.model.PrepayRequest request = new com.wechat.pay.java.service.payments.app.model.PrepayRequest();
- com.wechat.pay.java.service.payments.app.model.Amount amount = new com.wechat.pay.java.service.payments.app.model.Amount();
- //金额计算 ,乘以100
- String money = data.getVipMoney();
- //int orderAmount = Integer.parseInt(money) * 100;
- int orderAmount = (int) (Double.parseDouble(money) * 100);
- amount.setTotal(orderAmount);
- request.setAmount(amount);
- request.setAppid(wxPayAppConfig.getAppID());
- request.setMchid(wxPayAppConfig.getMchID());
- request.setDescription(data.getName());
- request.setNotifyUrl(wxPayAppConfig.getPayNotifyUrl());
- request.setOutTradeNo(orderNo);
- // 调用下单方法,得到应答
- com.wechat.pay.java.service.payments.app.model.PrepayResponse response = service.prepay(request);
- logger.info("调用微信app下单返回的信息是:{}", response);
- String prepayId = response.getPrepayId();
- AppPayData appPayData = new AppPayData();
- appPayData.setAppid(wxPayAppConfig.getAppID());
- appPayData.setPrepayid(prepayId);
- appPayData.setPartnerid(wxPayAppConfig.getMchID());
- String noncestr = UUID.randomUUID().toString().replaceAll("-", "");
- appPayData.setNoncestr(noncestr);
- //appPayData.setTimestamp(String.valueOf(System.currentTimeMillis()));
- //生成签名
- Map<String, String> returnMap = new HashMap<>();
- Long time = System.currentTimeMillis() / 1000;
- String timestamp = time.toString();
- returnMap.put("appid", wxPayAppConfig.getAppID());
- returnMap.put("timestamp", timestamp);
- returnMap.put("noncestr", noncestr);
- returnMap.put("prepayid", prepayId);
- //returnMap.put("package", "Sign=WXPay");
- //returnMap.put("package", "prepay_id="+prepayId);
- AppServiceExtension appServiceExtension = new AppServiceExtension.Builder().config(config).build();
- com.wechat.pay.java.service.payments.app.model.PrepayRequest prepayRequest = new com.wechat.pay.java.service.payments.app.model.PrepayRequest();
- prepayRequest.setAmount(amount);
- prepayRequest.setAppid(wxPayAppConfig.getAppID());
- prepayRequest.setMchid(wxPayAppConfig.getMchID());
- prepayRequest.setDescription(data.getName());
- prepayRequest.setNotifyUrl(wxPayAppConfig.getPayNotifyUrl());
- prepayRequest.setOutTradeNo(orderNo);
- com.wechat.pay.java.service.payments.app.model.PrepayWithRequestPaymentResponse prepayWithRequestPaymentResponse = appServiceExtension.prepayWithRequestPayment(prepayRequest);
- appPayData.setPrepayWithRequestPaymentResponse(prepayWithRequestPaymentResponse);
- SignatureResult signatureResult = config.createSigner().sign(wxPayAppConfig.getAppID() + "\n" + timestamp + "\n" + noncestr + "\n" + "prepay_id=" + prepayId + "\n");
- String sign = signatureResult.getSign();
- logger.info("签名值是:{}", sign);
- appPayData.setSign(sign);
- appPayData.setBase64Sign(Base64.getEncoder().encodeToString(sign.getBytes()));
- try {
- String signMD5 = WXPayUtil.generateSignature(returnMap, v3Key, WXPayConstants.SignType.MD5);
- String signSHA256 = WXPayUtil.generateSignature(returnMap, v3Key, WXPayConstants.SignType.HMACSHA256);
- //生成微信签名
- appPayData.setSignMD5(signMD5);
- appPayData.setBase64SignMD5(Base64.getEncoder().encodeToString(signMD5.getBytes()));
- appPayData.setSignSHA256(signSHA256);
- appPayData.setBase64SignSHA256(Base64.getEncoder().encodeToString(signSHA256.getBytes()));
- appPayData.setTimestamp(timestamp);
- } catch (Exception e) {
- logger.error("生成微信签名失败:", e);
- throw new RuntimeException("生成微信签名失败");
- } finally {
- }
- return appPayData;
- }
- /**
- * APP支付成功后调用,主要计算VIP时长
- *
- * @param vipGoodsId 商品主键
- * @param out_trade_no
- * @return
- */
- @Override
- public SysUser success(String vipGoodsId, String out_trade_no) {
- //查询商品是否存在,存在则下单,不存在则不下单
- VipGoodsData data = vipGoodsService.getById(vipGoodsId);
- if (Objects.isNull(data)) {
- throw new RuntimeException("VIP商品不存在");
- }
- VipOrderData vipOrderData = vipGoodsService.getOrderByOutTradeNo(out_trade_no);
- if (Objects.isNull(vipOrderData)) {
- throw new RuntimeException("订单不存在");
- }
- //查询订单是否支付成功,支付成功:生成VIP时长,失败异常
- /* QueryOrderByOutTradeNoRequest queryOrderByOutTradeNoRequest = new QueryOrderByOutTradeNoRequest();
- queryOrderByOutTradeNoRequest.setOutTradeNo(out_trade_no);
- queryOrderByOutTradeNoRequest.setMchid(wxPayAppConfig.getMchID());
- Transaction transaction = queryOrderByOutTradeNo(queryOrderByOutTradeNoRequest);*/
- Transaction transaction = queryOrderByOutTradeNo(out_trade_no);
- Transaction.TradeStateEnum tradeState = transaction.getTradeState();
- //logger.info("支付返回的信息是:{}", transaction);
- //logger.info("根据订单号查询是否支付成功:{}", tradeState.name());
- if ("SUCCESS".equals(tradeState.name())) {
- logger.info("支付成功:{}", transaction);
- //查询用户是否已经开通过,开通过则续费,没有开通过怎插新数据
- String userId = TokenUtils.getUserId();
- VipUserData vipUserData = vipGoodsService.selectByUserId(userId, vipGoodsId);
- //VIP时长
- String vipStartDate = "";
- String vipEndDate = "";
- String vipDate = data.getVipDate();
- if (Objects.isNull(vipUserData)) {
- //没有开通过,新开通,开始时间=当天时间,结束时间=会员时长+当前时间
- vipStartDate = DateUtils.toStringYMD(new Date());
- vipEndDate = DateUtils.getAfterDate(Integer.parseInt(vipDate));
- } else {
- //开通过,查看有没有过期,过期:新开通,不过期,续费
- String vipEndDateStr = vipUserData.getVipEndDate();
- Date vipEndDate1 = DateUtils.toDateYMDHMS(vipEndDateStr);
- Date todayDate = DateUtils.toDateYMDHMS(DateUtils.toStringYMD(new Date()));
- int compareTo = todayDate.compareTo(vipEndDate1);
- //0:到当天 1:过期 -1:不过期
- if (compareTo == 0 || compareTo == -1) {
- //不过期,续费,计算VIP结束时间
- vipEndDate = DateUtils.getDesignDateStr(vipEndDate1, DateUtils.sdfyyyyMMdd, Integer.parseInt(vipDate));
- vipStartDate = vipUserData.getVipStartDate();
- } else {
- //过期,删除原来的数据,在重新添加
- vipGoodsService.deleteVipUser(vipUserData.getId());
- //过期重新开通,设置新的开始和结束时间
- vipStartDate = DateUtils.toStringYMD(new Date());
- vipEndDate = DateUtils.getAfterDate(Integer.parseInt(vipDate));
- }
- }
- VipUserData saveVipUserData = new VipUserData();
- saveVipUserData.setId(PrimaryIdUtils.getId().toString());
- saveVipUserData.setUserId(userId);
- saveVipUserData.setVipGoodsId(vipGoodsId);
- saveVipUserData.setVipStartDate(vipStartDate);
- saveVipUserData.setVipEndDate(vipEndDate);
- saveVipUserData.setCreateTime(LocalDateTime.now());
- saveVipUserData.setUpdateTime(LocalDateTime.now());
- vipGoodsService.saveVipUserData(saveVipUserData);
- //修改用户表,添加是VIP用户,VIP最后时间,剩余时长
- Long vipResidueDate = DateUtils.getDifferenceTime(DateUtils.toDateYMDHMS(vipStartDate), DateUtils.toDateYMDHMS(vipEndDate));
- SysUser sysUser = sysUserMapper.selectOne(userId);
- sysUser.setIsVip(true);
- sysUser.setVipResidueDate(vipResidueDate);
- sysUser.setVipEndDate(vipEndDate);
- sysUser.setUpdateTime(new Date());
- sysUserMapper.update(sysUser);
-
- //更新订单状态为已支付
- vipOrderData.setStatus("2"); // 1:待支付 2:已支付 3:已取消
- vipOrderData.setUpdateTime(LocalDateTime.now());
- vipGoodsService.updateVipOrderData(vipOrderData);
-
- logger.info("VIP支付成功处理完成,用户ID:{},订单号:{},VIP结束时间:{}", userId, out_trade_no, vipEndDate);
-
- return sysUser;
- } else {
- throw new RuntimeException("订单支付失败");
- }
- }
- @Override
- public Transaction queryOrderByOutTradeNo(String out_trade_no) {
- return queryOrderByOutTradeNo(out_trade_no, "app");
- }
-
- /**
- * 根据订单号和支付类型查询订单状态
- * @param out_trade_no 订单号
- * @param payType 支付类型:app 或 miniprogram
- * @return 交易信息
- */
- public Transaction queryOrderByOutTradeNo(String out_trade_no, String payType) {
- Config config;
-
- if ("miniprogram".equals(payType)) {
- // 使用小程序配置
- config = new RSAAutoCertificateConfig.Builder()
- .merchantId(wxPayMiniprogramConfig.getMchID())
- .privateKeyFromPath(wxPayMiniprogramConfig.getCertPath())
- .merchantSerialNumber(wxPayMiniprogramConfig.getMerchantSerialNumber())
- .apiV3Key(wxPayMiniprogramConfig.getV3Key())
- .build();
- } else {
- // 使用APP配置
- config = new RSAAutoCertificateConfig.Builder()
- .merchantId(wxPayAppConfig.getMchID())
- .privateKeyFromPath(wxPayAppConfig.getCertPath())
- .merchantSerialNumber(wxPayAppConfig.getMerchantSerialNumber())
- .apiV3Key(v3Key)
- .build();
- }
-
- // 构建service - 对于查询订单,使用JsapiService即可(小程序和APP都支持)
- JsapiService service = new JsapiService.Builder().config(config).build();
- com.wechat.pay.java.service.payments.jsapi.model.QueryOrderByOutTradeNoRequest queryOrderByOutTradeNoRequest = new com.wechat.pay.java.service.payments.jsapi.model.QueryOrderByOutTradeNoRequest();
- queryOrderByOutTradeNoRequest.setOutTradeNo(out_trade_no);
- queryOrderByOutTradeNoRequest.setMchid("miniprogram".equals(payType) ?
- wxPayMiniprogramConfig.getMchID() : wxPayAppConfig.getMchID());
-
- Transaction transaction = service.queryOrderByOutTradeNo(queryOrderByOutTradeNoRequest);
- Transaction.TradeStateEnum tradeState = transaction.getTradeState();
- logger.info("{}支付订单查询结果 - 订单号:{},状态:{}", payType, out_trade_no, tradeState.name());
-
- if ("SUCCESS".equals(tradeState.name())) {
- logger.info("支付成功:{}", transaction);
- }
- return transaction;
- }
- // ============= 小程序支付相关实现 =============
-
- @Override
- public Object miniprogramUnifiedOrder(String vipGoodsId, String openid) {
- logger.info("小程序支付基础信息:{}", wxPayMiniprogramConfig);
- logger.info("用户openid:{}", openid);
-
- //查询商品是否存在,存在则下单,不存在则不下单
- VipGoodsData data = vipGoodsService.getById(vipGoodsId);
- if (Objects.isNull(data)) {
- throw new RuntimeException("VIP商品不存在");
- }
-
- if (StringUtils.isBlank(openid)) {
- throw new RuntimeException("用户openid不能为空");
- }
-
- try {
- // 使用自动更新平台证书的RSA配置
- Config config = new RSAAutoCertificateConfig.Builder()
- .merchantId(wxPayMiniprogramConfig.getMchID())
- .privateKeyFromPath(wxPayMiniprogramConfig.getCertPath())
- .merchantSerialNumber(wxPayMiniprogramConfig.getMerchantSerialNumber())
- .apiV3Key(wxPayMiniprogramConfig.getV3Key())
- .build();
- // 构建service
- JsapiService service = new JsapiService.Builder().config(config).build();
- String orderNo = PrimaryIdUtils.getId().toString();
-
- // 构建小程序支付请求
- com.wechat.pay.java.service.payments.jsapi.model.PrepayRequest request = new com.wechat.pay.java.service.payments.jsapi.model.PrepayRequest();
- com.wechat.pay.java.service.payments.jsapi.model.Amount amount = new com.wechat.pay.java.service.payments.jsapi.model.Amount();
-
- //金额计算,乘以100转换为分
- String money = data.getVipMoney();
- int orderAmount = (int) (Double.parseDouble(money) * 100);
-
- amount.setTotal(orderAmount);
- request.setAmount(amount);
- request.setAppid(wxPayMiniprogramConfig.getAppID());
- request.setMchid(wxPayMiniprogramConfig.getMchID());
- request.setDescription(data.getName());
- request.setNotifyUrl(wxPayMiniprogramConfig.getPayNotifyUrl());
- request.setOutTradeNo(orderNo);
-
- // 设置支付者信息
- Payer payer = new Payer();
- payer.setOpenid(openid);
- request.setPayer(payer);
-
- // 调用下单方法,得到应答
- com.wechat.pay.java.service.payments.jsapi.model.PrepayResponse response = service.prepay(request);
- logger.info("调用微信小程序下单返回的信息是:{}", response);
-
- String prepayId = response.getPrepayId();
-
- // 构建小程序支付参数
- MiniprogramPayData payData = new MiniprogramPayData();
-
- // 生成时间戳
- long timestamp = System.currentTimeMillis() / 1000;
- String timeStamp = String.valueOf(timestamp);
-
- // 生成随机字符串
- String nonceStr = UUID.randomUUID().toString().replaceAll("-", "");
-
- // 构建package参数
- String packageParam = "prepay_id=" + prepayId;
-
- // 生成签名
- String signStr = wxPayMiniprogramConfig.getAppID() + "\n" + timeStamp + "\n" + nonceStr + "\n" + packageParam + "\n";
- SignatureResult signatureResult = config.createSigner().sign(signStr);
- String paySign = signatureResult.getSign();
-
- // 设置小程序支付参数
- payData.setTimeStamp(timeStamp);
- payData.setNonceStr(nonceStr);
- payData.setPackage_(packageParam);
- payData.setPackageParam(packageParam); // 设置用于uni.requestPayment的package字段
- payData.setSignType("MD5");
- payData.setPaySign(paySign);
- payData.setOut_trade_no(orderNo);
- payData.setPrepay_id(prepayId);
- payData.setDescription(data.getName());
- payData.setTotal(orderAmount);
- payData.setRawData(response);
-
- logger.info("小程序支付参数:{}", payData);
-
- // 通过openid查询用户ID
- String userId = null;
- try {
- SysUser user = sysUserMapper.selectByOpenId(openid);
- if (user != null) {
- userId = user.getId();
- }
- } catch (Exception e) {
- logger.warn("根据openid查询用户失败: {}", openid, e);
- }
-
- // 生成订单记录
- VipOrderData orderData = new VipOrderData();
- orderData.setId(PrimaryIdUtils.getId().toString());
- orderData.setOutTradeNo(orderNo);
- orderData.setStatus("1");
- orderData.setVipGoodsId(vipGoodsId);
- orderData.setUserId(userId); // 记录用户ID
- orderData.setOpenid(openid); // 记录openid
- orderData.setCreateTime(LocalDateTime.now());
- orderData.setUpdateTime(LocalDateTime.now());
- vipGoodsService.insertVipOrderData(orderData);
-
- return payData;
-
- } catch (Exception e) {
- logger.error("小程序支付下单失败 - vipGoodsId: {}, openid: {}", vipGoodsId, openid, e);
- String errorMsg = e.getMessage();
- if (errorMsg == null || errorMsg.trim().isEmpty()) {
- errorMsg = e.getClass().getSimpleName() + ": " + e.toString();
- }
- throw new RuntimeException("小程序支付下单失败: " + errorMsg);
- }
- }
-
- @Override
- public String miniprogramNotify(String notifyStr) {
- String xmlBack = "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[报文为空]]></return_msg></xml>";
- try {
- // 转换成map
- Map<String, String> resultMap = WXPayUtil.xmlToMap(notifyStr);
- WXPay wxpayMiniprogram = new WXPay(wxPayMiniprogramConfig);
- if (wxpayMiniprogram.isPayResultNotifySignatureValid(resultMap)) {
- String returnCode = resultMap.get("return_code"); //状态
- String outTradeNo = resultMap.get("out_trade_no");//商户订单号
- String transactionId = resultMap.get("transaction_id");
- if ("SUCCESS".equals(returnCode)) {
- if (StringUtils.isNotBlank(outTradeNo)) {
- logger.info("小程序支付异步通知成功,订单号:{}", outTradeNo);
-
- try {
- // 查询订单信息
- VipOrderData vipOrderData = vipGoodsService.getOrderByOutTradeNo(outTradeNo);
- if (vipOrderData != null && "1".equals(vipOrderData.getStatus())) {
- // 订单状态为待支付,进行VIP处理
- String vipGoodsId = vipOrderData.getVipGoodsId();
- String userId = vipOrderData.getUserId();
-
- if (StringUtils.isNotBlank(userId)) {
- // 有用户ID,执行完整的VIP处理逻辑
- logger.info("开始处理小程序支付异步通知VIP逻辑 - 用户ID: {}, 订单号: {}", userId, outTradeNo);
-
- // 查询VIP商品信息
- VipGoodsData vipGoodsData = vipGoodsService.getById(vipGoodsId);
- if (vipGoodsData != null) {
- // 处理VIP逻辑(复用success方法的逻辑)
- handleVipLogic(userId, vipGoodsId, vipGoodsData, outTradeNo);
- logger.info("小程序支付异步通知VIP处理完成 - 用户ID: {}, 订单号: {}", userId, outTradeNo);
- } else {
- logger.warn("VIP商品不存在 - vipGoodsId: {}, 订单号: {}", vipGoodsId, outTradeNo);
- }
- } else {
- logger.warn("订单中缺少用户ID,无法处理VIP逻辑 - 订单号: {}", outTradeNo);
- }
-
- // 更新订单状态为已支付
- vipOrderData.setStatus("2"); // 已支付
- vipOrderData.setUpdateTime(LocalDateTime.now());
- vipGoodsService.updateVipOrderData(vipOrderData);
-
- logger.info("小程序支付异步通知处理完成,订单号:{}", outTradeNo);
- } else {
- logger.info("小程序支付异步通知 - 订单已处理或不存在,订单号:{}", outTradeNo);
- }
- } catch (Exception e) {
- logger.error("小程序支付异步通知业务处理失败,订单号:{}", outTradeNo, e);
- // 即使业务处理失败,也要返回SUCCESS,避免微信重复通知
- }
-
- xmlBack = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
- }
- }
- } else {
- logger.warn("小程序支付异步通知签名验证失败");
- }
- } catch (Exception e) {
- logger.error("小程序支付通知处理失败", e);
- }
- return xmlBack;
- }
-
- @Override
- public SysUser miniprogramSuccess(String vipGoodsId, String out_trade_no) {
- //查询商品是否存在,存在则下单,不存在则不下单
- VipGoodsData data = vipGoodsService.getById(vipGoodsId);
- if (Objects.isNull(data)) {
- throw new RuntimeException("VIP商品不存在");
- }
- VipOrderData vipOrderData = vipGoodsService.getOrderByOutTradeNo(out_trade_no);
- if (Objects.isNull(vipOrderData)) {
- throw new RuntimeException("订单不存在");
- }
-
- //查询订单是否支付成功,支付成功:生成VIP时长,失败异常
- Transaction transaction = queryOrderByOutTradeNo(out_trade_no, "miniprogram");
- Transaction.TradeStateEnum tradeState = transaction.getTradeState();
- logger.info("小程序支付订单查询结果 - 订单号:{},状态:{}", out_trade_no, tradeState.name());
- if ("SUCCESS".equals(tradeState.name())) {
- logger.info("小程序支付成功:{}", transaction);
- //查询用户是否已经开通过,开通过则续费,没有开通过怎插新数据
- String userId = TokenUtils.getUserId();
- VipUserData vipUserData = vipGoodsService.selectByUserId(userId, vipGoodsId);
- //VIP时长
- String vipStartDate = "";
- String vipEndDate = "";
- String vipDate = data.getVipDate();
- if (Objects.isNull(vipUserData)) {
- //没有开通过,新开通,开始时间=当天时间,结束时间=会员时长+当前时间
- vipStartDate = DateUtils.toStringYMD(new Date());
- vipEndDate = DateUtils.getAfterDate(Integer.parseInt(vipDate));
- } else {
- //开通过,查看有没有过期,过期:新开通,不过期,续费
- String vipEndDateStr = vipUserData.getVipEndDate();
- Date vipEndDate1 = DateUtils.toDateYMDHMS(vipEndDateStr);
- Date todayDate = DateUtils.toDateYMDHMS(DateUtils.toStringYMD(new Date()));
- int compareTo = todayDate.compareTo(vipEndDate1);
- //0:到当天 1:过期 -1:不过期
- if (compareTo == 0 || compareTo == -1) {
- //不过期,续费,计算VIP结束时间
- vipEndDate = DateUtils.getDesignDateStr(vipEndDate1, DateUtils.sdfyyyyMMdd, Integer.parseInt(vipDate));
- vipStartDate = vipUserData.getVipStartDate();
- } else {
- //过期,删除原来的数据,在重新添加
- vipGoodsService.deleteVipUser(vipUserData.getId());
- //过期重新开通,设置新的开始和结束时间
- vipStartDate = DateUtils.toStringYMD(new Date());
- vipEndDate = DateUtils.getAfterDate(Integer.parseInt(vipDate));
- }
- }
- VipUserData saveVipUserData = new VipUserData();
- saveVipUserData.setId(PrimaryIdUtils.getId().toString());
- saveVipUserData.setUserId(userId);
- saveVipUserData.setVipGoodsId(vipGoodsId);
- saveVipUserData.setVipStartDate(vipStartDate);
- saveVipUserData.setVipEndDate(vipEndDate);
- saveVipUserData.setCreateTime(LocalDateTime.now());
- saveVipUserData.setUpdateTime(LocalDateTime.now());
- vipGoodsService.saveVipUserData(saveVipUserData);
- //修改用户表,添加是VIP用户,VIP最后时间,剩余时长
- Long vipResidueDate = DateUtils.getDifferenceTime(DateUtils.toDateYMDHMS(vipStartDate), DateUtils.toDateYMDHMS(vipEndDate));
- SysUser sysUser = sysUserMapper.selectOne(userId);
- sysUser.setIsVip(true);
- sysUser.setVipResidueDate(vipResidueDate);
- sysUser.setVipEndDate(vipEndDate);
- sysUser.setUpdateTime(new Date());
- sysUserMapper.update(sysUser);
-
- //更新订单状态为已支付
- vipOrderData.setStatus("2"); // 1:待支付 2:已支付 3:已取消
- vipOrderData.setUpdateTime(LocalDateTime.now());
- vipGoodsService.updateVipOrderData(vipOrderData);
-
- logger.info("小程序VIP支付成功处理完成,用户ID:{},订单号:{},VIP结束时间:{}", userId, out_trade_no, vipEndDate);
-
- return sysUser;
- } else {
- throw new RuntimeException("小程序订单支付失败,状态:" + tradeState.name());
- }
- }
-
- /**
- * 处理VIP逻辑(抽取的公共方法,供success和异步通知使用)
- * @param userId 用户ID
- * @param vipGoodsId VIP商品ID
- * @param vipGoodsData VIP商品信息
- * @param outTradeNo 订单号
- */
- private void handleVipLogic(String userId, String vipGoodsId, VipGoodsData vipGoodsData, String outTradeNo) {
- try {
- //查询用户是否已经开通过,开通过则续费,没有开通过则插新数据
- VipUserData vipUserData = vipGoodsService.selectByUserId(userId, vipGoodsId);
- //VIP时长
- String vipStartDate = "";
- String vipEndDate = "";
- String vipDate = vipGoodsData.getVipDate();
-
- if (Objects.isNull(vipUserData)) {
- //没有开通过,新开通,开始时间=当天时间,结束时间=会员时长+当前时间
- vipStartDate = DateUtils.toStringYMD(new Date());
- vipEndDate = DateUtils.getAfterDate(Integer.parseInt(vipDate));
- } else {
- //开通过,查看有没有过期,过期:新开通,不过期,续费
- String vipEndDateStr = vipUserData.getVipEndDate();
- Date vipEndDate1 = DateUtils.toDateYMDHMS(vipEndDateStr);
- Date todayDate = DateUtils.toDateYMDHMS(DateUtils.toStringYMD(new Date()));
- int compareTo = todayDate.compareTo(vipEndDate1);
- //0:到当天 1:过期 -1:不过期
- if (compareTo == 0 || compareTo == -1) {
- //不过期,续费,计算VIP结束时间
- vipEndDate = DateUtils.getDesignDateStr(vipEndDate1, DateUtils.sdfyyyyMMdd, Integer.parseInt(vipDate));
- vipStartDate = vipUserData.getVipStartDate();
- } else {
- //过期,删除原来的数据,在重新添加
- vipGoodsService.deleteVipUser(vipUserData.getId());
- //过期重新开通,设置新的开始和结束时间
- vipStartDate = DateUtils.toStringYMD(new Date());
- vipEndDate = DateUtils.getAfterDate(Integer.parseInt(vipDate));
- }
- }
- VipUserData saveVipUserData = new VipUserData();
- saveVipUserData.setId(PrimaryIdUtils.getId().toString());
- saveVipUserData.setUserId(userId);
- saveVipUserData.setVipGoodsId(vipGoodsId);
- saveVipUserData.setVipStartDate(vipStartDate);
- saveVipUserData.setVipEndDate(vipEndDate);
- saveVipUserData.setCreateTime(LocalDateTime.now());
- saveVipUserData.setUpdateTime(LocalDateTime.now());
- vipGoodsService.saveVipUserData(saveVipUserData);
- //修改用户表,添加是VIP用户,VIP最后时间,剩余时长
- Long vipResidueDate = DateUtils.getDifferenceTime(DateUtils.toDateYMDHMS(vipStartDate), DateUtils.toDateYMDHMS(vipEndDate));
- SysUser sysUser = sysUserMapper.selectOne(userId);
- if (sysUser != null) {
- sysUser.setIsVip(true);
- sysUser.setVipResidueDate(vipResidueDate);
- sysUser.setVipEndDate(vipEndDate);
- sysUser.setUpdateTime(new Date());
- sysUserMapper.update(sysUser);
-
- logger.info("VIP处理完成 - 用户ID: {}, 订单号: {}, VIP结束时间: {}", userId, outTradeNo, vipEndDate);
- } else {
- logger.warn("用户不存在,无法更新VIP状态 - 用户ID: {}", userId);
- }
- } catch (Exception e) {
- logger.error("VIP逻辑处理失败 - 用户ID: {}, 订单号: {}", userId, outTradeNo, e);
- throw e;
- }
- }
- public static void main(String[] args) throws IOException {
- /** Native 支付下单为例 */
- /* *//** 商户号 *//*
- String merchantId = "1659536133";
- *//** 商户API私钥路径 *//*
- String privateKeyPath = "D:\\soft\\WXCertUtil\\WXCertUtil\\cert\\1659536133_20240224_cert\\apiclient_key.pem";
- *//** 商户证书序列号 *//*
- String merchantSerialNumber = "2C9364545EF9C4C82700563B8C398451E14743B3";
- *//** 商户APIV3密钥 *//*
- String apiV3Key = "A123456789B123456789C1234567890D";
- // 使用自动更新平台证书的RSA配置
- // 一个商户号只能初始化一个配置,否则会因为重复的下载任务报错
- Config config =
- new RSAAutoCertificateConfig.Builder()
- .merchantId(merchantId)
- .privateKeyFromPath(privateKeyPath)
- .merchantSerialNumber(merchantSerialNumber)
- .apiV3Key(apiV3Key)
- .build();
- // 构建service
- AppService service = new AppService.Builder().config(config).build();
- // request.setXxx(val)设置所需参数,具体参数可见Request定义
- String orderNo = PrimaryIdUtils.getId().toString();
- PrepayRequest request = new PrepayRequest();
- Amount amount = new Amount();
- amount.setTotal(100);
- request.setAmount(amount);
- request.setAppid("wx8fdb27b97ed17533");
- request.setMchid("1659536133");
- request.setDescription("VIP一个月商品");
- request.setNotifyUrl("http://120.46.40.61:18885/api/swagger-ui.html");
- request.setOutTradeNo(orderNo);
- // 调用下单方法,得到应答
- PrepayResponse response = service.prepay(request);
- // 使用微信扫描 code_url 对应的二维码,即可体验Native支付
- System.out.println(">>>>>>>>>>>:" + response);*/
- String noncestr = UUID.randomUUID().toString().replaceAll("-", "");
- long currentTimeMillis = System.currentTimeMillis() / 1000;
- System.out.println(currentTimeMillis);
- // System.out.println(noncestr.length());
- /* Calendar calendar = Calendar.getInstance();
- calendar.add(Calendar.DAY_OF_MONTH, 2);
- int year = calendar.get(Calendar.YEAR);
- int month = calendar.get(Calendar.MONTH) + 1;
- int day = calendar.get(Calendar.DAY_OF_MONTH);
- System.out.println("7天后的日期为:" + year + "-" + month + "-" + day);*/
- //Base64.getDecoder().decode("NDU1ODAwNjk2M0QyOTE2QTMwNjBGNUQwMTEwNkU4ODA0OTcyQTkyOTVDRkJGRTYzQUMzOUYyRkE5Q0RGQ0Y1Qg==");
- String vipEndDateStr = "2024-03-3";
- Date vipEndDate = DateUtils.toDateYMDHMS(vipEndDateStr);
- Date date = DateUtils.toDateYMDHMS(DateUtils.toStringYMD(new Date()));
- int compareTo = vipEndDate.compareTo(date);
- System.out.println(compareTo);
- }
- /* public Transaction queryOrderByOutTradeNo(QueryOrderByOutTradeNoRequest request) {
- String requestPath =
- "https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/{out_trade_no}";
- QueryOrderByOutTradeNoRequest realRequest = request;
- // 添加 path param
- requestPath =
- requestPath.replace("{" + "out_trade_no" + "}", urlEncode(realRequest.getOutTradeNo()));
- // 添加 query param
- QueryParameter queryParameter = new QueryParameter();
- if (realRequest.getMchid() != null) {
- queryParameter.add("mchid", urlEncode(realRequest.getMchid()));
- }
- requestPath += queryParameter.getQueryStr();
- HttpHeaders headers = new HttpHeaders();
- headers.addHeader(Constant.ACCEPT, MediaType.APPLICATION_JSON.getValue());
- headers.addHeader(Constant.CONTENT_TYPE, MediaType.APPLICATION_JSON.getValue());
- HttpRequest httpRequest =
- new HttpRequest.Builder()
- .httpMethod(HttpMethod.GET)
- .url(requestPath)
- .headers(headers)
- .build();
- HttpResponse<Transaction> httpResponse = httpClient.execute(httpRequest, Transaction.class);
- return httpResponse.getServiceResponse();
- }*/
- }
|