springboot项目中实现微信支付以及退款

项目背景

微信小程序中调用微信支付

微信支付开通

申请微信支付过程。。。

申请证书和秘钥

登录微信支付平台-API安全按照指示操作,v3秘钥可以不申请
在这里插入图片描述

导包

使用封装好的微信支付的jar

  <!-- 微信支付 -->
        <dependency>
            <groupId>com.github.binarywang</groupId>
            <artifactId>weixin-java-pay</artifactId>
            <version>4.6.0</version>
        </dependency>

支付代码

wx:
  appId: 
  appSecret: 
  mchId: 
  mchSerialNo: 
  apiKey: 
  apiV3Key: 
  keyPath:
  notifyUrl:
  refundNotify: 
@Component
@ConfigurationProperties(prefix = "wx")
@Data
@ToString
public class WxPayProperties {
    //小程序appid
    private String appId;
    //小程序秘钥
    private String appSecret;

    //商户号
    private String mchId;
    //证书序列号
    private String mchSerialNo;
    //api秘钥-v2
    private String apiKey;
    //apiV3秘钥
    private String apiV3Key;
    //回调接口地址
    private String notifyUrl;
    //证书地址
    private String keyPath;

    //退款回调地址
    private String refundNotify;
}


配置


@Configuration
@ConditionalOnClass(WxPayService.class)
@EnableConfigurationProperties(WxPayProperties.class)
@AllArgsConstructor
public class WxPayConfiguration {

    @Resource
    private WxPayProperties wxPayProperties;


    @Bean
    @ConditionalOnMissingBean
    public WxPayService wxPayService() {
        WxPayConfig payConfig = new WxPayConfig();
        payConfig.setAppId(StringUtils.trimToNull(this.wxPayProperties.getAppId()));
        payConfig.setMchId(StringUtils.trimToNull(this.wxPayProperties.getMchId()));
        payConfig.setMchKey(StringUtils.trimToNull(this.wxPayProperties.getApiKey()));
        payConfig.setKeyPath(StringUtils.trimToNull(this.wxPayProperties.getKeyPath()));
        payConfig.setApiV3Key(StringUtils.trimToNull(this.wxPayProperties.getApiV3Key()));
        payConfig.setNotifyUrl(wxPayProperties.getNotifyUrl());
        //交易类型
        payConfig.setTradeType("JSAPI");

        // 可以指定是否使用沙箱环境
        payConfig.setUseSandboxEnv(false);

        WxPayService wxPayService = new WxPayServiceImpl();
        wxPayService.setConfig(payConfig);
        return wxPayService;
    }

}

创建预支付订单

 try {
         String tradeNo = seqUtil.getIncrByTime("WM");
         String start = DateUtil.getCurrentDate("yyyyMMddHHmmss");
         String expire = DateUtil.dateToStr("yyyyMMddHHmmss", DateUtil.add(DateUtil.getNow(), 1, Calendar.HOUR));
            // 创建预支付订单的请求对象
            WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest();
            //订单备注
            orderRequest.setBody("膳食点餐");
            //订单号
            orderRequest.setOutTradeNo(tradeNo);
            //元转成分
          orderRequest.setTotalFee(BaseWxPayRequest.yuanToFen(realAmount.toString()));
            orderRequest.setOpenid(openId);
            orderRequest.setSpbillCreateIp(ip);
            orderRequest.setTimeStart(start);
            orderRequest.setTimeExpire(expire);

            Object order = wxPayService.createOrder(orderRequest);

            JSONObject res = JSONUtil.parseObj(order);
            //处理业务逻辑

        
            return new JsonResultResponse<>(res);
        } catch (Exception e) {
            log.error("微信支付失败!订单号:{},原因:{}", tradeNo, e.getMessage());
            e.printStackTrace();
            return new JsonResultResponse<>(ReturnCode.EXCEPTION.getCode(), "支付失败:" + e.getMessage());
        }

支付回调

 @Transactional(rollbackFor = Exception.class)
    public JsonResultResponse payNotify(HttpServletRequest req) {
        try {
            log.info("进入微信支付回调");

            String xmlResult = IOUtils.toString(req.getInputStream(), req.getCharacterEncoding());
            WxPayOrderNotifyResult result = wxPayService.parseOrderNotifyResult(xmlResult);
            log.info("微信支付回调结果:{}", result);

            // 加入自己处理订单的业务逻辑,需要判断订单是否已经支付过,否则可能会重复调用
            String orderId = result.getOutTradeNo();
            String transactionId = result.getTransactionId();
            String totalFee = BaseWxPayResult.fenToYuan(result.getTotalFee());

                MealsOrder mealsOrder = mealsOrderDao.selectByCode(orderId);
                if (mealsOrder == null) {
                    return new JsonResultResponse(ReturnCode.EXCEPTION.getCode(), orderId + "订单不存在");
                }
                if (mealsOrder.getStatus() != CommonEnum.OrderStatus.NOPAY.getId()) {
                    return new JsonResultResponse(ReturnCode.EXCEPTION.getCode(), orderId + "已经进行回调,不可重复回调");
                }
                mealsOrder.setStatus(CommonEnum.OrderStatus.PAY.getId());
                mealsOrder.setOrderDate(DateUtil.getNow());
                mealsOrder.setTransactionId(transactionId);
                mealsOrderDao.updateById(mealsOrder);
            return new JsonResultResponse("处理成功!");
        } catch (Exception e) {
            log.error("微信支付回调结果异常,异常原因{}", e.getMessage());
            e.printStackTrace();
            return new JsonResultResponse(ReturnCode.EXCEPTION.getCode(), "微信支付回调结果异常,异常原因:" + e.getMessage());
        }
    }


申请退款

  @Override
    @Transactional(rollbackFor = Exception.class)
    public JsonResultResponse orderRefund(Integer id) {
        String tradeNo = seqUtil.getIncrByDateTime("TK");
        MealsOrder mealsOrder = mealsOrderDao.selectById(id);
        if (mealsOrder == null) {
            return new JsonResultResponse(ReturnCode.EXCEPTION.getCode(), "订单不存在");
        }
        if (mealsOrder.getStatus() != CommonEnum.OrderStatus.PAY.getId() && mealsOrder.getStatus() != CommonEnum.OrderStatus.NOPAY.getId()) {
            return new JsonResultResponse(ReturnCode.EXCEPTION.getCode(), "订单已经制作不能取消,请联系商家");
        }
        try {

            WxPayRefundRequest wxPayRefundRequest = new WxPayRefundRequest();
            wxPayRefundRequest.setOutTradeNo(mealsOrder.getCode());
            wxPayRefundRequest.setTransactionId(wxPayRefundRequest.getOpUserId());
            wxPayRefundRequest.setOutRefundNo(tradeNo);
            wxPayRefundRequest.setRefundFee(BaseWxPayRequest.yuanToFen(mealsOrder.getRealAmount().toString()));
            wxPayRefundRequest.setTotalFee(BaseWxPayRequest.yuanToFen(mealsOrder.getRealAmount().toString()));
            wxPayRefundRequest.setNotifyUrl(wxPayProperties.getRefundNotify());
            WxPayRefundResult refund = this.wxPayService.refund(wxPayRefundRequest);

         
            mealsOrder.setOutRefundNo(tradeNo);
            mealsOrder.setStatus(CommonEnum.OrderStatus.CANCEL.getId());
            mealsOrderDao.updateById(mealsOrder);
            return new JsonResultResponse("取消成功,等待退款");
        } catch (Exception e) {
            e.printStackTrace();
            log.error("取消订单失败,订单号{}", mealsOrder.getCode());
            return new JsonResultResponse(ReturnCode.EXCEPTION.getCode(), "取消失败");
        }
    }

退款回调

 @Override
    @Transactional(rollbackFor = Exception.class)
    public JsonResultResponse refundNotify(String jsonData) {
        try {
            log.info("进入微信退款回调{}", jsonData);
            WxPayRefundNotifyResult result = wxPayService.parseRefundNotifyResult(jsonData);
            String outRefundNo = result.getReqInfo().getOutRefundNo();
            String transactionId = result.getReqInfo().getTransactionId();
            MealsOrder mealsOrder = mealsOrderDao.selectByTransactionId(transactionId);

            log.info("退款回调结果:{}", result);
            log.info("transactionId:{}", transactionId);

            if (mealsOrder == null) {
                return new JsonResultResponse(ReturnCode.EXCEPTION.getCode(), "退款失败,找不到该订单");
            }

            if ("SUCCESS".equals(result.getReqInfo().getRefundStatus())) {
                if (mealsOrder.getStatus() == CommonEnum.OrderStatus.REFUND.getId()) {
                    return new JsonResultResponse(ReturnCode.EXCEPTION.getCode(), "该订单已退款");
                }
                //已退款状态
                mealsOrder.setStatus(CommonEnum.OrderStatus.REFUND.getId());
                mealsOrder.setOutRefundInfo(JSONUtil.toJsonStr(result.getReqInfo()));
                mealsOrderDao.updateById(mealsOrder);
            } else {
                mealsOrder.setOutRefundInfo(JSONUtil.toJsonStr(result.getReqInfo()));
                mealsOrderDao.updateById(mealsOrder);
                return new JsonResultResponse(ReturnCode.EXCEPTION.getCode(), "退款失败" + result.getErrCodeDes());
            }
            return new JsonResultResponse("退款成功");
        } catch (Exception e) {
            e.printStackTrace();
            log.error("退款回调异常,异常原因{}", e.getMessage());
            return new JsonResultResponse(ReturnCode.EXCEPTION.getCode(), "退款失败" + e.getMessage());
        }
    }

发布坑

微信退款的过程中出现本地可以解密,线上一直报错解密失败
最后采用更换JDK的jar包解决

问题分析:微信相关API接入过程需要进行AES解密操作,Sun公司通过权限文件(local_policy.jar、US_export_policy.jar)做了相应限制,在解密操作过程中可能出现问题。因此Oracle在官网提供无政策全线文件进行下载。

下载地址:

JDK8下载地址:http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html

其他版本下载地址 :http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html

以下是Linux系统下处理方式,其他系统同理

如果安装了JRE,将下载后文件中的两个jar文件放到%JRE_HOME%libsecurity目录下覆盖原来的文件 如果安装了JDK,将下载后文件中的两个jar文件放到%JDK_HOME%jrelibsecurity目录下覆盖原来文件

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值