All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.redkalex.pay.WeiXinPayService Maven / Gradle / Ivy

There is a newer version: 2.7.7
Show newest version
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package org.redkalex.pay;

import java.io.*;
import java.security.*;
import java.util.*;
import java.util.logging.*;
import java.util.regex.*;
import javax.annotation.Resource;
import javax.net.ssl.*;
import org.redkale.convert.json.JsonConvert;
import org.redkale.service.*;
import org.redkale.util.*;
import static org.redkalex.pay.PayRetCodes.*;
import static org.redkalex.pay.Pays.*;

/**
 *
 * 详情见: https://redkale.org
 *
 * @author zhangjx
 */
@Local
@AutoLoad(false)
public class WeiXinPayService extends AbstractPayService {

    protected static final String format = "%1$tY%1$tm%1$td%1$tH%1$tM%1$tS"; //yyyyMMddHHmmss

    protected static final Pattern PAYXML = Pattern.compile("<([^/>]+)>(.+)"); // "<([^/>]+)>"

    //配置集合
    protected Map elements = new HashMap<>();

    @Resource(name = "property.pay.weixin.conf") //支付配置文件路径
    protected String conf = "config.properties";

    @Resource(name = "APP_HOME")
    protected File home;

    @Resource
    protected JsonConvert convert;

    @Override
    public void init(AnyValue conf) {
        if (this.convert == null) this.convert = JsonConvert.root();
        if (this.conf != null && !this.conf.isEmpty()) { //存在微信支付配置
            try {
                File file = (this.conf.indexOf('/') == 0 || this.conf.indexOf(':') > 0) ? new File(this.conf) : new File(home, "conf/" + this.conf);
                InputStream in = (file.isFile() && file.canRead()) ? new FileInputStream(file) : getClass().getResourceAsStream("/META-INF/" + this.conf);
                if (in == null) return;
                Properties properties = new Properties();
                properties.load(in);
                in.close();
                this.elements = WeixinPayElement.create(logger, properties, home);
            } catch (Exception e) {
                logger.log(Level.SEVERE, "init weixinpay conf error", e);
            }
        }
    }

    public void setPayElements(Map elements) {
        this.elements = elements;
    }

    public void putPayElements(Map elements) {
        this.elements.putAll(elements);
    }

    public WeixinPayElement getPayElement(String appid) {
        return this.elements.get(appid);
    }

    public void setPayElement(String appid, WeixinPayElement element) {
        this.elements.put(appid, element);
    }

    public boolean existsPayElement(String appid) {
        return this.elements != null && this.elements.containsKey(appid);
    }

    /**
     * 手机支付或者微信公众号支付时调用
     *
     * @param request PayPreRequest
     *
     * @return PayPreResponse
     */
    @Override
    public PayPreResponse prepay(final PayPreRequest request) {
        request.checkVaild();
        final PayPreResponse result = new PayPreResponse();
        try {
            final WeixinPayElement element = elements.get(request.getAppid());
            if (element == null) return result.retcode(RETPAY_CONF_ERROR);
            result.setAppid(element.appid);
            final TreeMap map = new TreeMap<>();
            if (request.getMap() != null) map.putAll(request.getMap());
            map.put("appid", element.appid);
            map.put("mch_id", element.merchno);
            map.put("nonce_str", Long.toHexString(System.currentTimeMillis()) + Long.toHexString(System.nanoTime()));
            map.put("body", request.getPaybody());
            //map.put("attach", "" + payid);
            map.put("out_trade_no", request.getPayno());
            map.put("total_fee", "" + request.getPaymoney());
            map.put("spbill_create_ip", request.getClientAddr());
            map.put("time_expire", String.format(format, System.currentTimeMillis() + request.getTimeoutms() * 60 * 1000));
            map.put("notify_url", ((request.notifyurl != null && !request.notifyurl.isEmpty()) ? request.notifyurl : element.notifyurl));
            map.put("trade_type", request.getPayway() == PAYWAY_WEB ? "JSAPI" : "APP");
            //trade_type=JSAPI,openid参数必传,用户在商户appid下的唯一标识
            if (request.getPayway() == PAYWAY_WEB && !map.containsKey("openid")) return result.retcode(RETPAY_OPENID_ERROR);
            map.put("sign", createSign(element, map));

            final String responseText = Utility.postHttpContent("https://api.mch.weixin.qq.com/pay/unifiedorder", formatMapToXML(map));
            result.setResponsetext(responseText);

            Map resultmap = formatXMLToMap(responseText);
            if (!"SUCCESS".equals(resultmap.get("return_code"))) return result.retcode(RETPAY_PAY_ERROR);
            if (!checkSign(element, resultmap)) return result.retcode(RETPAY_FALSIFY_ERROR);
            /**
             * "appId" : "wx2421b1c4370ec43b", //公众号名称,由商户传入 "timeStamp":" 1395712654", //时间戳,自1970年以来的秒数 "nonceStr" : "e61463f8efa94090b1f366cccfbbb444", //随机串 "package" :
             * "prepay_id=u802345jgfjsdfgsdg888", "signType" : "MD5", //微信签名方式: "paySign" : "70EA570631E4BB79628FBCA90534C63FF7FADD89" //微信签名
             */
            final String timestamp = Long.toString(System.currentTimeMillis() / 1000);
            final String noncestr = Long.toHexString(System.currentTimeMillis()) + Long.toHexString(System.nanoTime());
            final Map retmap = new TreeMap<>();
            if (request.getPayway() == PAYWAY_WEB) {
                retmap.put("appId", element.appid);
                retmap.put("timeStamp", timestamp);
                retmap.put("nonceStr", noncestr);
                retmap.put("package", "prepay_id=" + resultmap.get("prepay_id"));
                retmap.put("signType", "MD5");
                retmap.put("paySign", createSign(element, retmap));
            } else {
                retmap.put("appid", element.appid);
                retmap.put("partnerid", element.merchno);
                retmap.put("prepayid", resultmap.get("prepay_id"));
                retmap.put("timestamp", timestamp);
                retmap.put("noncestr", noncestr);
                retmap.put("package", "Sign=WXPay"); //固定值            
                retmap.put("sign", createSign(element, retmap));
            }
            result.setResult(retmap);

        } catch (Exception e) {
            result.setRetcode(RETPAY_PAY_ERROR);
            logger.log(Level.WARNING, "prepay_pay_error req=" + request + ", resp=" + result.responsetext, e);
        }
        return result;
    }

    /**
     * <xml>
     * <appid><![CDATA[wx2421b1c4370ec43b]]></appid>
     * <attach><![CDATA[支付测试]]></attach>
     * <bank_type><![CDATA[CFT]]></bank_type>
     * <fee_type><![CDATA[CNY]]></fee_type>
     * <is_subscribe><![CDATA[Y]]></is_subscribe>
     * <mch_id><![CDATA[10000100]]></mch_id>
     * <nonce_str><![CDATA[5d2b6c2a8db53831f7eda20af46e531c]]></nonce_str>
     * <openid><![CDATA[oUpF8uMEb4qRXf22hE3X68TekukE]]></openid>
     * <out_trade_no><![CDATA[1409811653]]></out_trade_no>
     * <result_code><![CDATA[SUCCESS]]></result_code>
     * <return_code><![CDATA[SUCCESS]]></return_code>
     * <sign><![CDATA[B552ED6B279343CB493C5DD0D78AB241]]></sign>
     * <sub_mch_id><![CDATA[10000100]]></sub_mch_id>
     * <time_end><![CDATA[20140903131540]]></time_end>
     * <total_fee>1</total_fee>
     * <trade_type><![CDATA[JSAPI]]></trade_type>
     * <transaction_id><![CDATA[1004400740201409030005092168]]></transaction_id>
     * </xml>
     *
     * @param request PayNotifyRequest
     *
     * @return PayNotifyResponse
     */
    @Override
    public PayNotifyResponse notify(PayNotifyRequest request) {
        request.checkVaild();
        final PayNotifyResponse result = new PayNotifyResponse();
        result.setPaytype(request.getPaytype());
        final String rstext = "";
        Map map = formatXMLToMap(request.getText());
        String appid = request.getAppid();
        if (appid == null || appid.isEmpty()) appid = map.getOrDefault("appid", "");
        final WeixinPayElement element = elements.get(appid);
        if (element == null) return result.retcode(RETPAY_CONF_ERROR);
        result.setPayno(map.getOrDefault("out_trade_no", ""));
        result.setThirdpayno(map.getOrDefault("transaction_id", ""));
        if ("NOTPAY".equals(map.get("return_code"))) return result.retcode(RETPAY_PAY_WAITING).result(rstext);
        if (!"SUCCESS".equals(map.get("return_code"))) return result.retcode(RETPAY_PAY_FAILED).result(rstext);
        if (!(map instanceof SortedMap)) map = new TreeMap<>(map);
        if (!checkSign(element, map)) return result.retcode(RETPAY_FALSIFY_ERROR).result(rstext);
        String state = map.get("trade_state");
        if (state == null && "SUCCESS".equals(map.get("result_code")) && Long.parseLong(map.get("total_fee")) > 0) {
            state = "SUCCESS";
        }
        if (!"SUCCESS".equals(state)) return result.retcode(RETPAY_PAY_FAILED).result(rstext);
        return result.result(rstext);
    }

    /**
     * 网页支付
     *
     * @param request PayCreatRequest
     *
     * @return PayCreatResponse
     */
    @Override
    public PayCreatResponse create(final PayCreatRequest request) {
        request.checkVaild();
        final PayCreatResponse result = new PayCreatResponse();
        try {
            final WeixinPayElement element = elements.get(request.getAppid());
            if (element == null) return result.retcode(RETPAY_CONF_ERROR);
            final TreeMap map = new TreeMap<>();
            if (request.getMap() != null) map.putAll(request.getMap());
            map.put("appid", element.appid);
            map.put("mch_id", element.merchno);
            map.put("nonce_str", Long.toHexString(System.currentTimeMillis()) + Long.toHexString(System.nanoTime()));
            map.put("body", request.getPaybody());
            //map.put("attach", "" + payid);
            map.put("out_trade_no", request.getPayno());
            map.put("total_fee", "" + request.getPaymoney());
            map.put("spbill_create_ip", request.getClientAddr());
            map.put("time_expire", String.format(format, System.currentTimeMillis() + request.getPaytimeout() * 1000));
            map.put("notify_url", element.notifyurl);
            map.put("sign", createSign(element, map));

            final String responseText = Utility.postHttpContent("https://api.mch.weixin.qq.com/pay/unifiedorder", formatMapToXML(map));
            result.setResponsetext(responseText);

            Map resultmap = formatXMLToMap(responseText);
            if (!"SUCCESS".equals(resultmap.get("return_code"))) return result.retcode(RETPAY_PAY_ERROR);
            if (!checkSign(element, resultmap)) return result.retcode(RETPAY_FALSIFY_ERROR);
            /**
             * "appId" : "wx2421b1c4370ec43b", //公众号名称,由商户传入 "timeStamp":" 1395712654", //时间戳,自1970年以来的秒数 "nonceStr" : "e61463f8efa94090b1f366cccfbbb444", //随机串 "package" :
             * "prepay_id=u802345jgfjsdfgsdg888", "signType" : "MD5", //微信签名方式: "paySign" : "70EA570631E4BB79628FBCA90534C63FF7FADD89" //微信签名
             */
            final Map rmap = new TreeMap<>();
            result.setResult(rmap);
            rmap.put("appId", element.appid);
            rmap.put("timeStamp", Long.toString(System.currentTimeMillis() / 1000));
            rmap.put("nonceStr", Long.toHexString(System.currentTimeMillis()) + Long.toHexString(System.nanoTime()));
            rmap.put("package", "prepay_id=" + resultmap.get("prepay_id"));
            rmap.put("signType", "MD5");
            rmap.put("paySign", createSign(element, rmap));
        } catch (Exception e) {
            result.setRetcode(RETPAY_PAY_ERROR);
            logger.log(Level.WARNING, "create_pay_error req=" + request + ", resp=" + result.responsetext, e);
        }
        return result;
    }

    /**
     * 回调支付接口返回的结果
     * < p >
     * < xml >
     * < appid >< ![CDATA[wx4ad12c89818dd981]] >< /appid >
     * < attach >< ![CDATA[10000070334]] >< /attach >
     * < bank_type >< ![CDATA[ICBC_DEBIT]] >< /bank_type >
     * < cash_fee >< ![CDATA[10]] >< /cash_fee >
     * < fee_type >< ![CDATA[CNY]] >< /fee_type >
     * < is_subscribe >< ![CDATA[Y]] >< /is_subscribe >
     * < mch_id >< ![CDATA[1241384602]] >< /mch_id >
     * < nonce_str >< ![CDATA[14d69ac6d6525f27dc9bcbebc]] >< /nonce_str >
     * < openid >< ![CDATA[ojEVbsyDUzGqlgX3eDgmAMaUDucA]] >< /openid >
     * < out_trade_no >< ![CDATA[1000072334]] >< /out_trade_no >
     * < result_code >< ![CDATA[SUCCESS]] >< /result_code >
     * < return_code >< ![CDATA[SUCCESS]] >< /return_code >
     * < sign >< ![CDATA[60D95E25EA9C4F54BD1020952303C4E2]] >< /sign >
     * < time_end >< ![CDATA[20150519085546]] >< /time_end >
     * < total_fee >10< /total_fee >
     * < trade_type >< ![CDATA[JSAPI]] >< /trade_type >
     * < transaction_id >< ![CDATA[1009630061201505190139511926]] >< /transaction_id >
     * < /xml >
     *
     * @param request PayRequest
     *
     * @return PayQueryResponse
     */
    @Override
    public PayQueryResponse query(final PayRequest request) {
        request.checkVaild();
        final PayQueryResponse result = new PayQueryResponse();
        try {
            final WeixinPayElement element = elements.get(request.getAppid());
            if (element == null) return result.retcode(RETPAY_CONF_ERROR);
            final Map map = new TreeMap<>();
            map.put("appid", element.appid);
            map.put("mch_id", element.merchno);
            map.put("out_trade_no", request.getPayno());
            map.put("nonce_str", Long.toHexString(System.currentTimeMillis()) + Long.toHexString(System.nanoTime()));
            map.put("sign", createSign(element, map));

            final String responseText = Utility.postHttpContent("https://api.mch.weixin.qq.com/pay/orderquery", formatMapToXML(map));
            result.setResponsetext(responseText);

            final Map resultmap = formatXMLToMap(responseText);
            result.setResult(resultmap);

            String state = resultmap.getOrDefault("trade_state", "");
            if (state.isEmpty() && "SUCCESS".equals(resultmap.get("result_code")) && Long.parseLong(resultmap.get("total_fee")) > 0) {
                state = "SUCCESS";
            }
            if (!checkSign(element, resultmap)) return result.retcode(RETPAY_FALSIFY_ERROR);
            if (state.isEmpty()) logger.warning("weixin.pay.query = " + resultmap);

            //trade_state 支付状态: SUCCESS—支付成功 REFUND—转入退款 NOTPAY—未支付 CLOSED—已关闭 REVOKED—已撤销(刷卡支付) USERPAYING--用户支付中 PAYERROR--支付失败(其他原因,如银行返回失败)
            short paystatus = PAYSTATUS_PAYNO;
            switch (state) {
                case "SUCCESS": paystatus = PAYSTATUS_PAYOK;
                    break;
                case "NOTPAY": paystatus = PAYSTATUS_UNPAY;
                    break;
                case "CLOSED": paystatus = PAYSTATUS_CLOSED;
                    break;
                case "REVOKED": paystatus = PAYSTATUS_CANCELED;
                    break;
                case "USERPAYING": paystatus = PAYSTATUS_PAYING;
                    break;
                case "PAYERROR": paystatus = PAYSTATUS_PAYNO;
                    break;
            }
            result.setPaystatus(paystatus);
            result.setThirdpayno(resultmap.getOrDefault("transaction_id", ""));
            result.setPayedmoney(Long.parseLong(resultmap.getOrDefault("total_fee", "0")));
        } catch (Exception e) {
            result.setRetcode(RETPAY_PAY_ERROR);
            logger.log(Level.WARNING, "query_pay_error req=" + request + ", resp=" + result.responsetext, e);
        }
        return result;
    }

    @Override
    public PayResponse close(final PayCloseRequest request) {
        request.checkVaild();
        final PayResponse result = new PayResponse();
        try {
            final WeixinPayElement element = elements.get(request.getAppid());
            if (element == null) return result.retcode(RETPAY_CONF_ERROR);
            Map map = new TreeMap<>();
            map.put("appid", element.appid);
            map.put("mch_id", element.merchno);
            map.put("nonce_str", Long.toHexString(System.currentTimeMillis()) + Long.toHexString(System.nanoTime()));
            map.put("out_trade_no", request.getPayno());
            map.put("sign", createSign(element, map));

            final String responseText = Utility.postHttpContent("https://api.mch.weixin.qq.com/pay/closeorder", formatMapToXML(map));
            result.setResponsetext(responseText);

            Map resultmap = formatXMLToMap(responseText);
            if (!"SUCCESS".equals(resultmap.get("return_code"))) return result.retcode(RETPAY_PAY_ERROR);
            if (!checkSign(element, resultmap)) return result.retcode(RETPAY_FALSIFY_ERROR);
            result.setResult(resultmap);

        } catch (Exception e) {
            result.setRetcode(RETPAY_PAY_ERROR);
            logger.log(Level.WARNING, "close_pay_error req=" + request + ", resp=" + result.responsetext, e);
        }
        return result;
    }

    //https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_4
    @Override
    public PayRefundResponse refund(PayRefundRequest request) {
        request.checkVaild();
        final PayRefundResponse result = new PayRefundResponse();
        try {
            final WeixinPayElement element = elements.get(request.getAppid());
            if (element == null) return result.retcode(RETPAY_CONF_ERROR);
            final TreeMap map = new TreeMap<>();
            map.put("appid", element.appid);
            map.put("mch_id", element.merchno);
            map.put("nonce_str", Long.toHexString(System.currentTimeMillis()) + Long.toHexString(System.nanoTime()));
            map.put("out_trade_no", request.getPayno());
            map.put("total_fee", "" + request.getPaymoney());
            map.put("out_refund_no", request.getRefundno());
            map.put("refund_fee", "" + request.getRefundmoney());
            map.put("op_user_id", element.merchno);
            map.put("sign", createSign(element, map));

            final String responseText = Utility.postHttpContent(element.paySSLContext, "https://api.mch.weixin.qq.com/secapi/pay/refund", formatMapToXML(map));
            result.setResponsetext(responseText);

            Map resultmap = formatXMLToMap(responseText);
            if (!"SUCCESS".equals(resultmap.get("return_code"))) return result.retcode(RETPAY_REFUND_ERROR);
            if (!checkSign(element, resultmap)) return result.retcode(RETPAY_FALSIFY_ERROR);
            result.setRefundedmoney(Long.parseLong(resultmap.get("refund_fee")));
        } catch (Exception e) {
            result.setRetcode(RETPAY_REFUND_ERROR);
            logger.log(Level.WARNING, "refund_pay_error req=" + request + ", resp=" + result.responsetext, e);
        }
        return result;
    }

    @Override
    public PayRefundResponse queryRefund(PayRequest request) {
        request.checkVaild();
        final PayRefundResponse result = new PayRefundResponse();
        try {
            final WeixinPayElement element = elements.get(request.getAppid());
            if (element == null) return result.retcode(RETPAY_CONF_ERROR);
            final Map map = new TreeMap<>();
            map.put("appid", element.appid);
            map.put("mch_id", element.merchno);
            map.put("out_trade_no", request.getPayno());
            map.put("nonce_str", Long.toHexString(System.currentTimeMillis()) + Long.toHexString(System.nanoTime()));
            map.put("sign", createSign(element, map));

            final String responseText = Utility.postHttpContent("https://api.mch.weixin.qq.com/pay/refundquery", formatMapToXML(map));
            result.setResponsetext(responseText);

            final Map resultmap = formatXMLToMap(responseText);
            result.setResult(resultmap);

            if (!"SUCCESS".equals(resultmap.get("return_code"))) return result.retcode(RETPAY_PAY_ERROR);
            if (!checkSign(element, resultmap)) return result.retcode(RETPAY_FALSIFY_ERROR);
            //trade_state SUCCESS—退款成功 FAIL—退款失败 PROCESSING—退款处理中 NOTSURE—未确定,需要商户原退款单号重新发起 
            //CHANGE—转入代发,退款到银行发现用户的卡作废或者冻结了,导致原路退款银行卡失败,资金回流到商户的现金帐号,需要商户人工干预,通过线下或者财付通转账的方式进行退款。

            result.setResult(resultmap);
            result.setRefundedmoney(Long.parseLong(resultmap.get("refund_fee_$n")));
        } catch (Exception e) {
            result.setRetcode(RETPAY_PAY_ERROR);
            logger.log(Level.WARNING, "query_pay_error req=" + request + ", resp=" + result.responsetext, e);
        }
        return result;
    }

    @Override
    protected String createSign(final PayElement element, Map map) throws Exception { //计算签名
        final StringBuilder sb = new StringBuilder();
        map.forEach((x, y) -> {
            if (!((String) y).isEmpty()) sb.append(x).append('=').append(y).append('&');
        });
        sb.append("key=").append(((WeixinPayElement) element).signkey);
        return Utility.binToHexString(MessageDigest.getInstance("MD5").digest(sb.toString().getBytes())).toUpperCase();
    }

    @Override
    protected boolean checkSign(final PayElement element, Map map) {  //验证签名
        if (!(map instanceof SortedMap)) map = new TreeMap<>(map);
        String sign = (String) map.remove("sign");
        final StringBuilder sb = new StringBuilder();
        map.forEach((x, y) -> {
            if (!((String) y).isEmpty()) sb.append(x).append('=').append(y).append('&');
        });
        sb.append("key=").append(((WeixinPayElement) element).signkey);
        try {
            return sign.equals(Utility.binToHexString(MessageDigest.getInstance("MD5").digest(sb.toString().getBytes())).toUpperCase());
        } catch (Exception e) {
            return false;
        }
    }

    protected static String formatMapToXML(final Map map) {
        final StringBuilder sb = new StringBuilder();
        sb.append("");
        map.forEach((x, y) -> sb.append('<').append(x).append('>').append(y.replace("<", "<").replace(">", ">").replace("&", "&")).append("'));
        sb.append("");
        return sb.toString();
    }

    public static Map formatXMLToMap(final String xml) {
        Map map = new TreeMap<>();
        Matcher m = PAYXML.matcher(xml.substring(xml.indexOf('>') + 1));
        while (m.find()) {
            String val = m.group(2);
            if (val.startsWith(" create(Logger logger, Properties properties, File home) {
            String def_appid = properties.getProperty("pay.weixin.appid", "").trim();
            String def_merchno = properties.getProperty("pay.weixin.merchno", "").trim();
            String def_submerchno = properties.getProperty("pay.weixin.submerchno", "").trim();
            String def_notifyurl = properties.getProperty("pay.weixin.notifyurl", "").trim();
            String def_signkey = properties.getProperty("pay.weixin.signkey", "").trim();
            String def_certpwd = properties.getProperty("pay.weixin.certpwd", "").trim();
            String def_certpath = properties.getProperty("pay.weixin.certpath", "").trim();
            String def_certbase64 = properties.getProperty("pay.weixin.certbase64", "").trim();

            final Map map = new HashMap<>();
            properties.keySet().stream().filter(x -> x.toString().startsWith("pay.weixin.") && x.toString().endsWith(".appid")).forEach(appid_key -> {
                final String prefix = appid_key.toString().substring(0, appid_key.toString().length() - ".appid".length());

                String appid = properties.getProperty(prefix + ".appid", def_appid).trim();
                String merchno = properties.getProperty(prefix + ".merchno", def_merchno).trim();
                String submerchno = properties.getProperty(prefix + ".submerchno", def_submerchno).trim();
                String notifyurl = properties.getProperty(prefix + ".notifyurl", def_notifyurl).trim();
                String signkey = properties.getProperty(prefix + ".signkey", def_signkey).trim();
                String certpwd = properties.getProperty(prefix + ".certpwd", def_certpwd).trim();
                String certpath = properties.getProperty(prefix + ".certpath", def_certpath).trim();
                String certbase64 = properties.getProperty(prefix + ".certbase64", def_certbase64).trim();

                if (appid.isEmpty() || merchno.isEmpty() || notifyurl.isEmpty() || signkey.isEmpty() || (certpath.isEmpty() && certbase64.isEmpty())) {
                    logger.log(Level.WARNING, properties + "; has illegal weixinpay conf by prefix" + prefix);
                    return;
                }
                WeixinPayElement element = new WeixinPayElement();
                element.appid = appid;
                element.merchno = merchno;
                element.submerchno = submerchno;
                element.notifyurl = notifyurl;
                element.signkey = signkey;
                element.certpwd = certpwd;
                element.certpath = certpath;
                element.certbase64 = certbase64;
                if (element.initElement(logger, home)) {
                    map.put(appid, element);
                    if (def_appid.equals(appid)) map.put("", element);
                }
            });
            return map;
        }

        @Override
        public boolean initElement(Logger logger, File home) {
            try {
                InputStream in;
                if (this.certbase64 != null && !this.certbase64.isEmpty()) {
                    in = new ByteArrayInputStream(Base64.getDecoder().decode(this.certbase64));
                } else {
                    File file = (certpath.indexOf('/') == 0 || certpath.indexOf(':') > 0) ? new File(this.certpath) : new File(home, "conf/" + this.certpath);
                    in = file.isFile() ? new FileInputStream(file) : getClass().getResourceAsStream("/META-INF/" + this.certpath);
                }
                if (in == null) return false;
                //需要更新%JDK_HOME%\jre\lib\security下的policy
                //http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html 
                setPaySSLContext(in);
                return true;
            } catch (Exception e) {
                logger.log(Level.SEVERE, "init weixinpay sslcontext error", e);
                return false;
            }
        }

        public void setPaySSLContext(InputStream in) throws Exception {
            final KeyStore keyStore = KeyStore.getInstance("PKCS12");
            keyStore.load(in, this.certpwd.toCharArray());
            in.close();
            KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
            keyManagerFactory.init(keyStore, certpwd.toCharArray());
            SSLContext ctx = SSLContext.getInstance("TLSv1");
            ctx.init(keyManagerFactory.getKeyManagers(), null, null);
            this.paySSLContext = ctx;
        }

        @Override
        public String toString() {
            return JsonConvert.root().convertTo(this);
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy