2019-12-09 支付集成(支付宝、微信)工具类

支付宝集成

注:payConfig为支付宝配置实体。至于如何初始化配置信息,按照实际情况选择(本项目为数据库查询)。

public class AliPayUtil {
    private static AlipayClient alipayClient;
    // 配置实体类
    private static BasePayConfig payConfig;

    static {
        // 查询支付宝配置信息
        QueryParamList params = new QueryParamList();
        params.addParam("appBusi", "WZGYL-ALIPAY");
        List<BasePayConfig> payConfigList = JPAUtil.load(BasePayConfig.class, params);
        if(payConfigList != null && payConfigList.size() > 0) {
            payConfig = payConfigList.get(0);
            System.out.println("初始化支付宝配置信息");
            alipayClient = new DefaultAlipayClient(payConfig.getGetWayUrl(), payConfig.getAppId(), 
                    payConfig.getAppPrivateKey(), payConfig.getBackFormat(), payConfig.getConfigCharset(), payConfig.getPlatPublicKey(),
                    payConfig.getSignType());
        } else {
            BasePayLog payLog = new BasePayLog();
            payLog.setLogId(SequenceUtil.genStringEntitySequenceNo(BasePayLog.class));
            payLog.setCreateTime(CommonDateTool.getInstance().getThisTime());
            payLog.setPayStep("6");
            payLog.setPayStepResult("0");
            payLog.setResultDes("支付宝初始化配置信息出错(没有查询到配置信息),操作人:" + UserViewTool.getEmId() + ",操作人名称:" + UserViewTool.getUserName(UserViewTool.getEmId()));
            JPAUtil.create(payLog);
            LogUtil.getAppLoger().info("查询支付宝配置信息出错,没有查询到配置信息", null);
//          payConfig.setAppId(AliPayConfig.app_id);
//          payConfig.setAppPrivateKey(AliPayConfig.merchant_private_key);
//          payConfig.setBackFormat("json");
//          payConfig.setConfigCharset(AliPayConfig.charset);
//          payConfig.setGetWayUrl(AliPayConfig.gatewayUrl);
//          payConfig.setInterfaceVersion(AliPayConfig.version);
//          payConfig.setNotifyUrl(AliPayConfig.notify_url);
//          payConfig.setReturnUrl(AliPayConfig.return_url);
//          payConfig.setPlatPublicKey(AliPayConfig.alipay_public_key);
//          payConfig.setProductCode(AliPayConfig.product_code);
//          payConfig.setQrPayMode(AliPayConfig.qr_pay_mode);
//          payConfig.setSignType(AliPayConfig.sign_type);
//          payConfig.setTimeoutExpress(AliPayConfig.timeout_express);
        }
    }

    /**
     * 支付宝PC端网页支付
     * @param payOrder 订单信息
     * @return
     */
    public static String aliPay(BasePayOrder payOrder) {
        String result = null;
        try {
            // 设置请求参数
            AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
            alipayRequest.setReturnUrl(payConfig.getReturnUrl());
            alipayRequest.setNotifyUrl(payConfig.getNotifyUrl());
            AlipayTradePagePayModel bizModel = new AlipayTradePagePayModel();
            bizModel.setOutTradeNo(payOrder.getOutTradeNo());
            bizModel.setTotalAmount(payOrder.getTotalAmount().toString());
            bizModel.setSubject(payOrder.getOrderSubjectt());
            bizModel.setBody(payOrder.getOrderBody());
            bizModel.setProductCode(payConfig.getProductCode());
            /*该笔订单允许的最晚付款时间,逾期将关闭交易。取值范围:1m~15d。m-分钟,h-小时,d-天,1c-当天(1c-当天的情况下,无论交易何时创建,都在0点关闭)。
            该参数数值不接受小数点, 如 1.5h,可转换为 90m*/
//          bizModel.setTimeoutExpress(payConfig.getTimeoutExpress()); 
//          long outTime = System.currentTimeMillis() + 1000*60*2;//获得系统当前时间的毫秒数
//          Date date = new Date(outTime);
//          SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//定义格式,不显示毫秒
//          bizModel.setTimeExpire(df.format(date));
            String passBackParams = "payPlat:aliPay";
            bizModel.setPassbackParams(URLEncoder.encode(passBackParams, "UTF-8")); // 公用回传参数,如:merchantBizType%3d3C%26merchantBizNo%3d2016010101111
                                                        // 如果请求时传递了该参数,则返回给商户时会回传该参数。支付宝只会在同步返回(包括跳转回商户网站)和异步通知时将该参数原样返回。本参数必须进行UrlEncode之后才可以发送给支付宝。
            /*PC扫码支付的方式,支持前置模式和 跳转模式。
            前置模式是将二维码前置到商户
            的订单确认页的模式。需要商户在
            自己的页面中以 iframe 方式请求
            支付宝页面。具体分为以下几种:
            0:订单码-简约前置模式,对应 iframe 宽度不能小于600px,高度不能小于300px;
            1:订单码-前置模式,对应iframe 宽度不能小于 300px,高度不能小于600px;
            3:订单码-迷你前置模式,对应 iframe 宽度不能小于 75px,高度不能小于75px;
            4:订单码-可定义宽度的嵌入式二维码,商户可根据需要设定二维码的大小。
            
            跳转模式下,用户的扫码界面是由支付宝生成的,不在商户的域名下。
            2:订单码-跳转模式*/
            bizModel.setQrPayMode(payConfig.getQrPayMode());
            alipayRequest.setBizModel(bizModel);
            // alipayRequest.setBizContent("{\"out_trade_no\":\""+ outTradeNo
            // +"\","
            // + "\"total_amount\":\""+ totalAmount +"\","
            // + "\"subject\":\""+ subject +"\","
            // + "\"body\":\""+ body +"\","
            // + "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");

            // 请求
            AlipayTradePagePayResponse alipayResonse = alipayClient.pageExecute(alipayRequest);
            result = alipayResonse.getBody();
            BasePayLog payLog = new BasePayLog();
            payLog.setLogId(SequenceUtil.genStringEntitySequenceNo(BasePayLog.class));
            payLog.setCreateTime(CommonDateTool.getInstance().getThisTime());
            payLog.setOutTradeNo(payOrder.getOutTradeNo());
            payLog.setPayStep("0");
            payLog.setPayStepResult("0");
            payLog.setResultDes("下单成功,平台:支付宝,outTradeNo:" + payOrder.getOutTradeNo() + ",操作人:" + UserViewTool.getEmId() + ",操作人名称:" + UserViewTool.getUserName(UserViewTool.getEmId()));
            JPAUtil.create(payLog);
            // 输出
            // HttpServletResponse response =
            // ServletActionContext.getResponse();
            // PrintWriter out = response.getWriter();
            // out.println(result);
            // responseData.setParameter("result", result);
//          try {
//              // 对字符串编码,由于编码会将空格编码为 + 号,需要替换调 + 号
//              result = URLEncoder.encode(result, "UTF-8").replace("+", "%20");
//          } catch (UnsupportedEncodingException e) {
//              e.printStackTrace();
//              // 由于前台eval()解析原字符串报错,替换调回车以及script标签。手动提交
//              result = result.replace("\n", "").replace("<script>document.forms[0].submit();</script>", "");
//          }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
    
    /**
     * 订单查询-返回值根据需要修改
     * 
     * @param outTradeNo
     *            订单支付时传入的商户订单号,和支付宝交易号不能同时为空。
     * @param tradeNo
     *            支付宝交易号,和商户订单号不能同时为空 trade_no,out_trade_no如果同时存在优先取trade_no
     * @return
     */
    public static AlipayTradeQueryResponse tradeQuery(String outTradeNo, String tradeNo) {
        AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
        AlipayTradeQueryModel model = new AlipayTradeQueryModel();
        model.setOutTradeNo(outTradeNo);
        model.setTradeNo(tradeNo);
        request.setBizModel(model);
        // 记录日志
        BasePayLog payLog = new BasePayLog();
        payLog.setLogId(SequenceUtil.genStringEntitySequenceNo(BasePayLog.class));
        payLog.setCreateTime(CommonDateTool.getInstance().getThisTime());
        payLog.setOutTradeNo(outTradeNo);
        payLog.setPayStep("3");
        try {
            AlipayTradeQueryResponse response = alipayClient.execute(request);
            payLog.setPayStepResult("0");
            payLog.setResultDes("支付宝查询订单信息成功,返回信息:" + JSONSerializer.toJSON(response));
            return response;
        } catch (AlipayApiException e) {
            e.printStackTrace();
            payLog.setPayStepResult("-1");
            payLog.setResultDes("支付宝查询订单信息失败,失败原因:" + e.getMessage());
        } finally {
            JPAUtil.create(payLog);
        }
        return null;
    }
    
    // 校验异步通知签名
    public static boolean verifyNotify(Map<String, String> params) throws AlipayApiException {
        return AlipaySignature.rsaCheckV1(params, payConfig.getPlatPublicKey(), payConfig.getConfigCharset(), payConfig.getSignType());
    }

    /**
     * 对账单下载
     * 
     * @param billDate
     *            账单时间:日账单格式为yyyy-MM-dd,最早可下载2016年1月1日开始的日账单;月账单格式为yyyy-MM,
     *            最早可下载2016年1月开始的月账单。
     */
    public static String billDownload(String billDate) {
        AlipayDataDataserviceBillDownloadurlQueryRequest request = new AlipayDataDataserviceBillDownloadurlQueryRequest();
        AlipayDataDataserviceBillDownloadurlQueryModel model = new AlipayDataDataserviceBillDownloadurlQueryModel();
        model.setBillType("trade");
        model.setBillDate(billDate);
        request.setBizModel(model);
        // 记录日志
        BasePayLog payLog = new BasePayLog();
        payLog.setLogId(SequenceUtil.genStringEntitySequenceNo(BasePayLog.class));
        payLog.setCreateTime(CommonDateTool.getInstance().getThisTime());
        payLog.setPayStep("5");
        payLog.setPayStepResult("0");
        try {
            AlipayDataDataserviceBillDownloadurlQueryResponse response = alipayClient.execute(request);
            if (response.isSuccess()) {
                // 获取下载地址url
                payLog.setResultDes("支付宝下载对账单成功,下载地址:" + response.getBillDownloadUrl());
                return response.getBillDownloadUrl();
            } else {
                // 如果账单不存在, 插入一条空数据到数据库
                payLog.setResultDes("支付宝下载对账单失败,返回信息:" + JSONSerializer.toJSON(response));
                String subCode = response.getSubCode();
                if("BILL_NOT_EXIST".equals(subCode)) {
                    return "对账单不存在";
                } else {
                    return "系统繁忙,请重试";
                }
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
            payLog.setResultDes("支付宝下载对账单失败,异常信息:" + e.getMessage());
            return "系统繁忙,请重试";
        } finally {
            JPAUtil.create(payLog);
        }
    }
    
    /**
     * 关闭支付宝订单
     * 
     * @param outTradeNo
     *            订单支付时传入的商户订单号,和支付宝交易号不能同时为空。
     * @param tradeNo
     *            支付宝交易号,和商户订单号不能同时为空 trade_no,out_trade_no如果同时存在优先取trade_no
     * @return
     */
    public static AlipayTradeCloseResponse tradeClose(String outTradeNo, String tradeNo) {
        AlipayTradeCloseRequest request = new AlipayTradeCloseRequest();
        AlipayTradeCloseModel model = new AlipayTradeCloseModel();
        model.setOutTradeNo(outTradeNo);
        model.setTradeNo(tradeNo);
        request.setBizModel(model);
        // 记录日志
        BasePayLog payLog = new BasePayLog();
        payLog.setLogId(SequenceUtil.genStringEntitySequenceNo(BasePayLog.class));
        payLog.setCreateTime(CommonDateTool.getInstance().getThisTime());
        payLog.setOutTradeNo(outTradeNo);
        payLog.setPayStep("4");
        try {
            AlipayTradeCloseResponse response = alipayClient.execute(request);
            payLog.setPayStepResult("0");
            payLog.setResultDes("支付宝关闭订单接口调用成功,返回信息:" + JSONSerializer.toJSON(response));
            return response;
        } catch (AlipayApiException e) {
            e.printStackTrace();
            payLog.setPayStepResult("-1");
            payLog.setResultDes("支付宝关闭订单失败,失败原因:" + e.getMessage());
        } finally {
            JPAUtil.create(payLog);
        }
        return null;
    }
    
    /**
     * 支付宝退款
     * @param order 订单信息
     * @param reason 退款原因(默认:正常退款)
     * @return
     */
    public static String tradeRefund(BasePayOrder order, String reason){
        // SDK已经封装掉了公共参数,这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
        if(StringUtils.isEmpty(reason)) {
            reason = "正常退款";
        }
        AlipayTradeRefundModel refundModel = new AlipayTradeRefundModel();
        refundModel.setOutTradeNo(order.getOutTradeNo());
        refundModel.setTradeNo(order.getTradeNo());
        refundModel.setRefundAmount(order.getTotalAmount().toString());
        refundModel.setRefundReason(reason);
        // 实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.app.pay
        AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
        request.setBizModel(refundModel);
        // 记录日志
        BasePayLog payLog = new BasePayLog();
        payLog.setLogId(SequenceUtil.genStringEntitySequenceNo(BasePayLog.class));
        payLog.setCreateTime(CommonDateTool.getInstance().getThisTime());
        payLog.setOutTradeNo(order.getOutTradeNo());
        payLog.setPayStep("5");
        try {
            AlipayTradeRefundResponse response = alipayClient.execute(request);
            System.out.println(response.getMsg());
            System.out.println(response.getBody());
            if (response.isSuccess()) {
                payLog.setPayStepResult("0");
                payLog.setResultDes("支付宝订单退款成功,返回信息:" + response.getBody());
                return "OK";
            } else {
                payLog.setPayStepResult("-1");
                payLog.setResultDes("支付宝订单退款失败,失败原因:" + response.getSubMsg());
                return response.getSubMsg();
            }
        } catch (Exception e) {
            e.printStackTrace();
            payLog.setPayStepResult("-4");
            payLog.setResultDes("支付宝订单退款失败,失败原因:" + e.getMessage());
            return "退款失败";
        } finally {
            JPAUtil.create(payLog);
        }   
    }
    
    // 返回支付宝AppId
    public static String getAppId() {
        return payConfig.getAppId();
    }
    
    public static BasePayConfig getAliPayConfig() {
        return payConfig;
    }
    
    private static AliPayUtil instance = new AliPayUtil();

    private AliPayUtil() {
    }

    /**
     * 获取实例
     */
    public static AliPayUtil getInstance() {
        return instance;
    }

微信集成

注:微信使用第三方SDK IJPay 让支付触手可及

public class WxPayUtil {
    private static BasePayConfig payConfig;

    static {
        // 查询微信配置信息
        QueryParamList params = new QueryParamList();
        params.addParam("appBusi", "WZGYL-WXPAY");
        List<BasePayConfig> payConfigList = JPAUtil.load(BasePayConfig.class, params);
        if(payConfigList != null && payConfigList.size() > 0) {
            payConfig = payConfigList.get(0);
            System.out.println("初始化微信配置信息");
        } else {
            BasePayLog payLog = new BasePayLog();
            payLog.setLogId(SequenceUtil.genStringEntitySequenceNo(BasePayLog.class));
            payLog.setCreateTime(CommonDateTool.getInstance().getThisTime());
            payLog.setPayStep("6");
            payLog.setPayStepResult("0");
            payLog.setResultDes("微信初始化配置信息出错(没有查询到配置信息),操作人:" + UserViewTool.getEmId() + ",操作人名称:" + UserViewTool.getUserName(UserViewTool.getEmId()));
            JPAUtil.create(payLog);
            LogUtil.getAppLoger().info("微信初始化配置信息出错,没有查询到配置信息", null);
//          payConfig.setAppId(WxPayConfig.app_id);
//          payConfig.setAppPrivateKey(WxPayConfig.partner_key);
//          payConfig.setMchId(WxPayConfig.mch_id);
//          payConfig.setNotifyUrl(WxPayConfig.notify_url);
        }
    }

    /**
     * 微信PC端网页支付
     * 
     * @param payOrder 订单信息
     * @return
     */
    public static String wxPay(BasePayOrder payOrder) {
        String ip = IpKit.getRealIp(ServletActionContext.getRequest());
        if (StringUtils.isBlank(ip)) {
            ip = "127.0.0.1";
        }
//        WxPayApiConfig wxPayApiConfig = WxPayApiConfigKit.getWxPayApiConfig();
        String passBackParams = "payPlat:wxPay";
        // body 为微信标题 对应库表 orderSubjectt字段,  detail 为商品详情 对应body字段, total_fee为订单金额 单位分 所以需要乘以100 并去掉小数
        String totalFee = payOrder.getTotalAmount().multiply(new BigDecimal("100")).toString().split("\\.")[0];
        System.out.println(payOrder.getOutTradeNo());
        Map<String, String> params = UnifiedOrderModel
                .builder()
                .appid(payConfig.getAppId())
                .mch_id(payConfig.getMchId())
                .nonce_str(Util.getUUID())
                .body(payOrder.getOrderSubjectt())
                .detail(payOrder.getOrderBody())
                .attach(passBackParams) // 额外参数
                .out_trade_no(payOrder.getOutTradeNo())
                .total_fee(totalFee)
                .spbill_create_ip(ip)
                .notify_url(payConfig.getNotifyUrl())
                .trade_type(TradeType.NATIVE.getTradeType())
                .build()
                .createSign(payConfig.getAppPrivateKey(), SignType.HMACSHA256);

        String xmlResult = WxPayApi.pushOrder(false, params);
        Map<String, String> result = WxPayKit.xmlToMap(xmlResult);

        String returnCode = result.get("return_code");
        String resultCode = result.get("result_code");
        if (WxPayKit.codeIsOk(returnCode) && WxPayKit.codeIsOk(resultCode)) {
            BasePayLog payLog = new BasePayLog();
            payLog.setLogId(SequenceUtil.genStringEntitySequenceNo(BasePayLog.class));
            payLog.setCreateTime(CommonDateTool.getInstance().getThisTime());
            payLog.setOutTradeNo(payOrder.getOutTradeNo());
            payLog.setPayStep("0");
            payLog.setPayStepResult("0");
            payLog.setResultDes("下单成功,平台:微信,outTradeNo:" + payOrder.getOutTradeNo() + ",操作人:" + UserViewTool.getEmId() + ",操作人名称:" + UserViewTool.getUserName(UserViewTool.getEmId()));
            JPAUtil.create(payLog);
            String qrCodeUrl = result.get("code_url");
            String qrCodeImg = "data:image/png;base64," + Util.creatQrCode(qrCodeUrl, 180, 180).replace("\n", "").replace("\r", "");
            return qrCodeImg;
        }
        //生成预付订单success
        return null;
    }
    
    /**
     * 订单查询-返回值根据需要修改
     * 
     * @param outTradeNo
     *            订单支付时传入的商户订单号,和微信订单号不能同时为空。
     * @param tradeNo
     *            微信订单号,和商户订单号不能同时为空 trade_no,out_trade_no如果同时存在优先取trade_no
     * @return
     */
    public static Map<String, String> tradeQuery(String outTradeNo, String tradeNo) {
        Map<String, String> params = OrderQueryModel.builder()
                .appid(payConfig.getAppId())
                .mch_id(payConfig.getMchId())
                .nonce_str(WxPayKit.generateStr())
                .transaction_id(tradeNo)
                .out_trade_no(outTradeNo)
                .build()
                .createSign(payConfig.getAppPrivateKey(), SignType.HMACSHA256);
        String xmlResult = WxPayApi.orderQuery(params);
        Map<String, String> result = WxPayKit.xmlToMap(xmlResult);
        for (Map.Entry<String, String> entry : result.entrySet()) {
            System.out.println(entry.getKey() + " = " + entry.getValue());
        }
        // 记录日志
        BasePayLog payLog = new BasePayLog();
        payLog.setLogId(SequenceUtil.genStringEntitySequenceNo(BasePayLog.class));
        payLog.setCreateTime(CommonDateTool.getInstance().getThisTime());
        payLog.setOutTradeNo(outTradeNo);
        payLog.setPayStep("3");
        payLog.setPayStepResult("0");
        payLog.setResultDes("微信查询订单信息成功,返回信息:" + JSONSerializer.toJSON(result));
        JPAUtil.create(payLog);
        return result;
    }
    
    /**
     * 对账单下载
     * 
     * @param billDate
     *            账单时间:日账单格式为yyyyMMdd,可下载三个月之内
     */
    public static String billDownload(String billDate) {
        // 记录日志
        BasePayLog payLog = new BasePayLog();
        payLog.setLogId(SequenceUtil.genStringEntitySequenceNo(BasePayLog.class));
        payLog.setCreateTime(CommonDateTool.getInstance().getThisTime());
        payLog.setPayStep("5");
        payLog.setPayStepResult("0");
        Map<String, String> params = DownloadBillModel.builder()
                .appid(payConfig.getAppId())
                .mch_id(payConfig.getMchId())
                .nonce_str(WxPayKit.generateStr())
                .bill_date(billDate)
                .bill_type("ALL")
                .build()
                .createSign(payConfig.getAppPrivateKey(), SignType.HMACSHA256);
        String result = WxPayApi.downloadBill(false, params);
        if(result.startsWith("<xml>")) {
            Map<String, String> mapResult = WxPayKit.xmlToMap(result);
            for (Map.Entry<String, String> entry : mapResult.entrySet()) {
                System.out.println(entry.getKey() + " = " + entry.getValue());
                if("error_code".equals(entry.getKey())) {
                    if("20001".equals(entry.getValue())) {
                        result = "参数错误,请联系管理员";
                    } else if("20002".equals(entry.getValue())) {
                        result = "账单不存在或未生成";
                    } else if("20003".equals(entry.getValue()) || "20100".equals(entry.getValue())) {
                        result = "下载对账单失败,请重试";
                    } else if("20007".equals(entry.getValue())) {
                        result = "当前商户号账单API权限已经关闭";
                    }
                    break;
                }
            }
            payLog.setResultDes("微信下载对账单失败,返回信息:" + JSONSerializer.toJSON(mapResult));
        } else {
            payLog.setResultDes("微信下载对账单成功");
        }
        JPAUtil.create(payLog);
        return result;
    }
    
    /**
     * 关闭订单
     * 
     * @param outTradeNo
     *            订单支付时传入的商户订单号,和微信订单号不能同时为空。
     * @param tradeNo
     *            微信订单号,和商户订单号不能同时为空 trade_no,out_trade_no如果同时存在优先取trade_no
     * @return
     */
    public static Map<String, String> tradeClose(String outTradeNo, String tradeNo) {
        Map<String, String> params = CloseOrderModel.builder()
                .appid(payConfig.getAppId())
                .mch_id(payConfig.getMchId())
                .nonce_str(WxPayKit.generateStr())
                .out_trade_no(outTradeNo)
                .build()
                .createSign(payConfig.getAppPrivateKey(), SignType.HMACSHA256);
        String xmlResult = WxPayApi.closeOrder(params);
        Map<String, String> result = WxPayKit.xmlToMap(xmlResult);
        for (Map.Entry<String, String> entry : result.entrySet()) {
            System.out.println(entry.getKey() + " = " + entry.getValue());
        }
        // 记录日志
        BasePayLog payLog = new BasePayLog();
        payLog.setLogId(SequenceUtil.genStringEntitySequenceNo(BasePayLog.class));
        payLog.setCreateTime(CommonDateTool.getInstance().getThisTime());
        payLog.setOutTradeNo(outTradeNo);
        payLog.setPayStep("4");
        payLog.setPayStepResult("0");
        payLog.setResultDes("微信关闭订单成功,返回信息:" + JSONSerializer.toJSON(result));
        JPAUtil.create(payLog);
        return result;
    }
    
    /**
     * 微信退款
     * @param order 订单信息
     * @param reason 退款原因(默认:正常退款)
     * @return
     */
    public static String tradeRefund(BasePayOrder order, String reason){
        // SDK已经封装掉了公共参数,这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
        if(StringUtils.isEmpty(reason)) {
            reason = "正常退款";
        }
        String totalFee = order.getTotalAmount().multiply(new BigDecimal("100")).toString().split("\\.")[0];
        Map<String, String> params = RefundModel.builder()
                .appid(payConfig.getAppId())
                .mch_id(payConfig.getMchId())
                .nonce_str(WxPayKit.generateStr())
                .transaction_id(order.getTradeNo())
                .out_trade_no(order.getOutTradeNo())
                .out_refund_no(WxPayKit.generateStr())
                .total_fee(totalFee)
                .refund_fee(totalFee)
                .build()
                .createSign(payConfig.getAppPrivateKey(), SignType.MD5);

        String xmlResult = WxPayApi.orderRefund(false, params, payConfig.getCertPath(), payConfig.getMchId());
        Map<String, String> result = WxPayKit.xmlToMap(xmlResult);
        for (Map.Entry<String, String> entry : result.entrySet()) {
            System.out.println(entry.getKey() + " = " + entry.getValue());
        }
        return null;
    }

    // 校验异步通知签名
    public static boolean verifyNotify(Map<String, String> params) {
        return WxPayKit.verifyNotify(params, payConfig.getAppPrivateKey(), SignType.HMACSHA256);
    }
    
    // 返回微信AppId
    public static String getAppId() {
        return payConfig.getAppId();
    }
    
    public static BasePayConfig getWxPayConfig() {
        return payConfig;
    }
    
    private static WxPayUtil instance = new WxPayUtil();

    private WxPayUtil() {
    }

    /**
     * 获取实例
     */
    public static WxPayUtil getInstance() {
        return instance;
    }

工具类

public class Util {
    
    /**
     * 获取UUID
     */
    public static String getUUID(){
        return UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();
    }

    /**
     * 下载并解压文件zip
     * @param downUrl zip下载路径
     * @param descDir 解压完成之后输出的文件夹
     * @throws IOException
     */
    public static void downCsv(String downUrl, String descDir)throws IOException {
        URL url = new URL(downUrl);
        try {
            URLConnection conn = url.openConnection();
            InputStream inStream = conn.getInputStream();
            ZipInputStream Zin=new ZipInputStream(inStream, Charset.forName("gbk"));
            BufferedInputStream Bin=new BufferedInputStream(Zin);
            String Parent=descDir; //输出路径(文件夹目录)
            File Fout=null;
            ZipEntry entry;
            try {
                while((entry = Zin.getNextEntry())!=null && !entry.isDirectory()){
                    Fout=new File(Parent,entry.getName());
                    if(!Fout.exists()){
                        (new File(Fout.getParent())).mkdirs();
                    }
                    FileOutputStream out=new FileOutputStream(Fout);
                    BufferedOutputStream Bout=new BufferedOutputStream(out);
                    int b;
                    while((b=Bin.read())!=-1){
                        Bout.write(b);
                    }
                    Bout.close();
                    out.close();
                    System.out.println(Fout+"解压成功");
                }
                Bin.close();
                Zin.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }

    /**
     * 按顺序关闭流
     */
    public static void closeStream(BufferedReader bufferedReader, InputStreamReader inputStreamReader, InputStream inputStream) {
        try {
            if (bufferedReader != null) {
                bufferedReader.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        if (inputStreamReader != null) {
            try {
                inputStreamReader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (inputStream != null) {
            try {
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    
    
    /**
     * 将指定内容转为二维码流
     * @param contents 内容
     * @param width 二维码宽
     * @param height 二维码高
     * @return 返回 base64二维码图片
     */
    public static String creatQrCode(String contents, int width, int height) {
        Hashtable<EncodeHintType, Object> hints = new Hashtable<>();
        String binary = null;
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); //容错级别最高
        hints.put(EncodeHintType.CHARACTER_SET, "utf-8");  //设置字符编码
        hints.put(EncodeHintType.MARGIN, 1);                //二维码空白区域,最小为0也有白边,只是很小,最小是6像素左右
        try {
            BitMatrix bitMatrix = new MultiFormatWriter().encode(contents, BarcodeFormat.QR_CODE, width, height, hints); // 1、读取文件转换为字节数组
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            BufferedImage image = toBufferedImage(bitMatrix);
            //转换成png格式的IO流
            ImageIO.write(image, "png", out);
            byte[] bytes = out.toByteArray();
//            // 2、将字节数组转为二进制
            BASE64Encoder encoder = new BASE64Encoder();
            binary = encoder.encodeBuffer(bytes).trim();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return binary;
    }

    /**
     * image流数据处理
     *
     * @author ianly
     */
    public static BufferedImage toBufferedImage(BitMatrix matrix) {
        int width = matrix.getWidth();
        int height = matrix.getHeight();
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                image.setRGB(x, y, matrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
            }
        }
        return image;
    }
    
    
    public static String readData(HttpServletRequest request) {
        BufferedReader br = null;

        try {
            StringBuilder result = new StringBuilder();

            String line;
            for(br = request.getReader(); (line = br.readLine()) != null; result.append(line)) {
                if (result.length() > 0) {
                    result.append("\n");
                }
            }

            line = result.toString();
            return line;
        } catch (IOException var12) {
            throw new RuntimeException(var12);
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException var11) {
                    var11.printStackTrace();
                }
            }

        }
    }
    
    public static String getRealIp(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if ((ip == null) || (ip.length() == 0) || ("unknown".equalsIgnoreCase(ip))) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if ((ip == null) || (ip.length() == 0) || ("unknown".equalsIgnoreCase(ip))) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if ((ip == null) || (ip.length() == 0) || ("unknown".equalsIgnoreCase(ip))) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,372评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,368评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,415评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,157评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,171评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,125评论 1 297
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,028评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,887评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,310评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,533评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,690评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,411评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,004评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,659评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,812评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,693评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,577评论 2 353