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

org.redkalex.pay.EhkingPayService 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 javax.annotation.Resource;
import org.redkale.convert.json.JsonConvert;
import org.redkale.util.*;
import static org.redkalex.pay.PayRetCodes.*;
import org.redkale.service.Local;

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

    private static final Map header = new HashMap<>();

    static {
        header.put("Content-Type", "application/vnd.ehking-v1.0+json");
    }

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

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

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

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

    @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 = EhkingPayElement.create(logger, properties, home);
            } catch (Exception e) {
                logger.log(Level.SEVERE, "init ehkingpay conf error", e);
            }
        }
    }

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

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

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

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

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

    @Override
    public PayPreResponse prepay(PayPreRequest request) {
        request.checkVaild();
        final PayPreResponse result = new PayPreResponse();
        try {
            final EhkingPayElement element = elements.get(request.getAppid());
            if (element == null) return result.retcode(RETPAY_CONF_ERROR);
            result.setAppid(element.appid);
            LinkedHashMap map = new LinkedHashMap<>();

            final Map pd = new LinkedHashMap<>();
            pd.put("name", request.getPaytitle());
            pd.put("quantity", "1");
            pd.put("amount", "" + request.getPaymoney());
            pd.put("receiver", request.getAttach("receiver", ""));

            map.put("merchantId", element.merchno);
            map.put("orderAmount", "" + request.getPaymoney());
            map.put("orderCurrency", "CNY");
            map.put("requestId", request.getPayno());
            String notifyurl = (request.notifyurl != null && !request.notifyurl.isEmpty()) ? request.notifyurl : element.notifyurl;
            map.put("notifyUrl", notifyurl);
            map.put("callbackUrl", request.getAttach("gotourl", notifyurl));
            map.put("remark", request.getPayno());
            map.put("paymentModeCode", request.getAttach("bankcode", ""));
            map.put("forUse", request.getAttach("foruse", ""));

            map.put("productDetails", new Object[]{pd});
            map.put("payer", new LinkedHashMap<>());
            map.put("bankCard", new LinkedHashMap<>());

            map.put("hmac", createSign(element, map));

            result.responsetext = Utility.postHttpContent(element.createurl, header, convert.convertTo(map));
            Map resultmap = convert.convertFrom(JsonConvert.TYPE_MAP_STRING_STRING, result.responsetext.replace("\"violations\":{", "\"violations\":'{").replace("}}", "}}'"));
            result.setResult(resultmap);
            final Map rsmap = new LinkedHashMap<>();
            rsmap.put("merchantId", resultmap.getOrDefault("merchantId", ""));
            rsmap.put("requestId", resultmap.getOrDefault("requestId", ""));
            rsmap.put("status", resultmap.getOrDefault("status", ""));
            rsmap.put("redirectUrl", resultmap.getOrDefault("redirectUrl", ""));
            rsmap.put("hmac", resultmap.getOrDefault("hmac", ""));
            if (!checkSign(element, rsmap)) return result.retcode(RETPAY_FALSIFY_ERROR);

            if (!"SUCCESS".equalsIgnoreCase(resultmap.get("status")) && !"REDIRECT".equalsIgnoreCase(resultmap.get("status"))) {
                return result.retcode(RETPAY_PAY_ERROR);
            }

            final Map rmap = new TreeMap<>();
            rmap.put("redirect", resultmap.getOrDefault("redirectUrl", ""));
            rmap.put("requestid", resultmap.getOrDefault("requestId", ""));
            result.setThirdpayno(rmap.get("requestid"));
            result.setResult(rmap);
        } catch (Exception e) {
            result.setRetcode(RETPAY_PAY_ERROR);
            logger.log(Level.WARNING, "prepay_pay_error req=" + request + ", resp=" + result.responsetext, e);
        }
        return result;
    }

    @Override
    public PayNotifyResponse notify(PayNotifyRequest request) {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public PayCreatResponse create(PayCreatRequest request) {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public PayQueryResponse query(PayRequest request) {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public PayResponse close(PayCloseRequest request) {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public PayRefundResponse refund(PayRefundRequest request) {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public PayRefundResponse queryRefund(PayRequest request) {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    protected String createSign(PayElement element, String aValue) {
        byte value[] = aValue.getBytes(UTF8);
        MessageDigest md;
        try {
            md = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException e) {
            return null;
        }
        md.update(((EhkingPayElement) element).inpad);
        md.update(value);
        byte dg[] = md.digest();
        md.reset();
        md.update(((EhkingPayElement) element).outpad);
        md.update(dg, 0, 16);
        dg = md.digest();
        return Utility.binToHexString(dg);
    }

    @Override
    protected String createSign(PayElement element, Map map0) {
        Map map = (Map) map0;
        final String hmac = (String) map.remove("hmac");
        final StringBuilder sb = new StringBuilder();
        for (Map.Entry en : map.entrySet()) {
            if ("productDetails".equals(en.getKey())) {
                final Map pd = (Map) ((Object[]) en.getValue())[0];
                pd.forEach((x, y) -> sb.append(y));
            } else if (en.getValue() instanceof String) {
                sb.append(en.getValue());
            }
        }
        String rs = createSign(element, sb.toString());
        if (hmac != null) map.put("hmac", hmac);
        return rs;
    }

    @Override
    protected boolean checkSign(PayElement element, Map map0) {
        Map map = (Map) map0;
        return ((String) map.getOrDefault("hmac", "")).equalsIgnoreCase(createSign(element, map));
    }

    public static class EhkingPayElement extends PayElement {

        //"pay.ehking.merchno" //商户ID 
        public String merchno = ""; //

        //"pay.ehking.appid"
        public String appid = "";  //虚拟APPID, 为空则取merchno

        //"pay.ehking.merchkey" //商户Key
        public String merchkey = ""; //

        //"pay.ehking.notifyurl" //回调url
        public String notifyurl = "";

        //"pay.ehking.createurl" //请求付款url
        public String createurl = "https://api.ehking.com/onlinePay/order";

        //"pay.ehking.queryurl" //请求查询url
        public String queryurl = "https://api.ehking.com/onlinePay/query";

        //"pay.ehking.refundurl" //退款url
        public String refundurl = "https://xxxx";

        //"pay.ehking.closeurl" //请求关闭url
        public String closeurl = "https://xxxx";

        protected byte[] inpad;

        protected byte[] outpad;

        @Override
        public boolean initElement(Logger logger, File home) {
            byte k_ipad[] = new byte[64];

            byte k_opad[] = new byte[64];

            byte keyb[] = this.merchkey.getBytes(UTF8);

            Arrays.fill(k_ipad, keyb.length, 64, (byte) 54);
            Arrays.fill(k_opad, keyb.length, 64, (byte) 92);
            for (int i = 0; i < keyb.length; i++) {
                k_ipad[i] = (byte) (keyb[i] ^ 0x36);
                k_opad[i] = (byte) (keyb[i] ^ 0x5c);
            }
            this.inpad = k_ipad;
            this.outpad = k_opad;
            return true;
        }

        public static Map create(Logger logger, Properties properties, File home) {
            String def_merchno = properties.getProperty("pay.ehking.merchno", "").trim();
            String def_appid = properties.getProperty("pay.ehking.appid", def_merchno).trim();
            String def_merchkey = properties.getProperty("pay.ehking.merchkey", "").trim();
            String def_notifyurl = properties.getProperty("pay.ehking.notifyurl", "").trim();

            String def_createurl = properties.getProperty("pay.ehking.createurl", "https://api.ehking.com/onlinePay/order").trim();
            String def_queryurl = properties.getProperty("pay.ehking.queryurl", "https://api.ehking.com/onlinePay/query").trim();
            String def_refundurl = properties.getProperty("pay.ehking.refundurl", "https://xxxx").trim();
            String def_closeurl = properties.getProperty("pay.ehking.closeurl", "https://xxxx").trim();

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

                String merchno = properties.getProperty(prefix + ".merchno", def_merchno).trim();
                String appid = properties.getProperty(prefix + ".appid", def_appid).trim();
                String merchkey = properties.getProperty(prefix + ".merchkey", def_merchkey).trim();
                String notifyurl = properties.getProperty(prefix + ".notifyurl", def_notifyurl).trim();
                String createurl = properties.getProperty(prefix + ".createurl", def_createurl).trim();
                String queryurl = properties.getProperty(prefix + ".queryurl", def_queryurl).trim();
                String refundurl = properties.getProperty(prefix + ".refundurl", def_refundurl).trim();
                String closeurl = properties.getProperty(prefix + ".closeurl", def_closeurl).trim();

                if (merchno.isEmpty() || notifyurl.isEmpty()) {
                    logger.log(Level.WARNING, properties + "; has illegal ehkingpay conf by prefix" + prefix);
                    return;
                }
                EhkingPayElement element = new EhkingPayElement();
                element.merchno = merchno;
                element.appid = appid;
                element.merchkey = merchkey;
                element.notifyurl = notifyurl;
                element.createurl = createurl;
                element.queryurl = queryurl;
                element.refundurl = refundurl;
                element.closeurl = closeurl;
                if (element.initElement(logger, null)) {
                    map.put(appid, element);
                    if (def_appid.equals(appid)) map.put("", element);
                }
            });
            //if (logger.isLoggable(Level.FINEST)) logger.finest("" + map);
            return map;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy