首页 > Java > 全国中小企业融资综合信用服务平台-省级节点数据接口规范-河南省营商环境和社会信用建设中心

全国中小企业融资综合信用服务平台-省级节点数据接口规范-河南省营商环境和社会信用建设中心

开始之前先说一点题外话,几年前曾经看过一个视频,其中一个观点大概就是程序员是一个反传统的群体,其他群体掌握了某个技术,一般都是当做内部商业机密,而程序员则不一样,喜欢开源,尤其 GPL 协议的开源,不仅自己毫无保留的开源,还要求使用他的软件也得开源,也正是这种开源造就了互联网的蓬勃发展。我目前所在公司因为是做金融相关的公司,国家出于某些原因,要求要上报相关的数据到省平台,而省平台的技术采用的是 webservice,和我们目前习惯的 http 接口不太一样,所以前一段时间在写这个的时候走了不少弯路,而网上也没有参考资料,所以决定把相关的核心代码公布出来,供需要的同学参考。需要说明的是:这是我们河南省的系统相关接口,不知道外省是否一致,省平台给的接口文档名是:全国中小企业融资综合信用服务平台省级节点数据接口规范V5.3.pdf,首页写的是:全国中小企业融资综合信用服务平台省级节点数据接口规范,国家公共信用信息中心,河南省营商环境和社会信用建设中心,2024年7月

1. jar 包引入


        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.10</version>
        </dependency>
        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcprov-jdk15on</artifactId>
            <version>1.70</version>
        </dependency>
        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcpkix-jdk15on</artifactId>
            <version>1.70</version>
        </dependency>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-frontend-jaxws</artifactId>
            <version>4.0.5</version>
        </dependency>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-transports-http</artifactId>
            <version>4.0.5</version>
        </dependency>

2. 上报工具类,其中:queryData 方法是用来查询,sendData 方法用来上报数据


package cn.bridgeli.demo;

import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.CharEncoding;
import org.apache.commons.lang3.StringUtils;
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
import org.bouncycastle.util.encoders.Base64;
import org.bouncycastle.util.encoders.Hex;

import javax.xml.namespace.QName;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.security.PublicKey;

@Slf4j
public class XyhnUtil {

    private static String pubKey;
    private static String queryPubKey;

    private static PublicKey reportPublicKey;

//    private static XyhnConfig xyhnConfig = SpringUtils.getBean(XyhnConfig.class);
    private static XyhnConfig xyhnConfig = null;

    /**
     * 授权查询省平台接口
     *
     * @param method 要调取的方法名
     * @param object 查询方法的参数(不包含:publicKey、appKey)
     * @return 省平台解密后的数据
     */
    public static String queryData(String method, JSONObject object) {
        //1、组装报文
        if (StringUtils.isEmpty(queryPubKey)) {
            queryPubKey = convertFileToBase64(xyhnConfig.getQueryPubKeyPath());
        }

        object.put("publicKey", queryPubKey);
        object.put("appKey", xyhnConfig.getQueryAppKey());
        //2、发送报文
        String jsonRes = callInterface("query", method, object.toJSONString());

        //3、解密返回数据
        JSONObject json = JSONObject.parseObject(jsonRes);
        Boolean success = json.getBoolean("success");
        if ("uploadLicense".equals(method)) {
            if (null == success || !success) {
                return jsonRes;
            }
        } else if ("cancelLicense".equals(method)) {
            if (null != success && success) {
                return jsonRes;
            }
        }

        BigInteger d = new BigInteger(xyhnConfig.getQueryPriKey(), 16);
        BCECPrivateKey bcecPrivateKey = GMUtil.getPrivatekeyFromD(d);
        String key0 = json.getString("key");
        String data = json.getString("data");
        String signatureData = json.getString("signatureData");
        byte[] decode = Hex.decode(key0);
        // sm2解密
        byte[] bytes1 = GMUtil.sm2Decrypt(decode, bcecPrivateKey);
        // sm4解密
        String content = GMUtil.sm4Decrypt(new String(bytes1), data);
        log.info("content: " + content);
        // 4、验签
        File file = base64ToFileEx(json.getString("pubKey"));
        PublicKey publicKey = GMUtil.getPublickeyFromX509File(file);
        byte[] signatureData1 = Hex.decode(signatureData);
        boolean verifyRes = GMUtil.verifySm3WithSm2(content.getBytes(), xyhnConfig.getUserId().getBytes(), signatureData1, publicKey);
        log.info("method 验签结果:" + verifyRes);
        if (!verifyRes) {
            return null;
        }
        return content;
    }

    private static PublicKey getPublicKey() {
        //1、组装报文
        if (StringUtils.isEmpty(pubKey)) {
            pubKey = convertFileToBase64(xyhnConfig.getPubKeyPath());
        }
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("key", xyhnConfig.getAppKey());
        JSONObject object = new JSONObject();
        object.put("requestData", jsonObject);
        object.put("publicKey", pubKey);
        //2、发送报文
        String jsonRes = callInterface("report", "getPublicKey", object.toJSONString());

        //3、解密返回数据
        JSONObject json = JSONObject.parseObject(jsonRes);
        BigInteger d = new BigInteger(xyhnConfig.getPriKey(), 16);
        BCECPrivateKey bcecPrivateKey = GMUtil.getPrivatekeyFromD(d);
        String key0 = json.getString("key");
        String data = json.getString("data");
        String signatureData = json.getString("signatureData");
        byte[] decode = Hex.decode(key0);
        // sm2解密
        byte[] bytes1 = GMUtil.sm2Decrypt(decode, bcecPrivateKey);
        // sm4解密
        String returnData = GMUtil.sm4Decrypt(new String(bytes1), data);
        log.info("returnData:" + returnData);
        // 4、验签
        File file = base64ToFileEx(returnData);
        PublicKey publicKey = GMUtil.getPublickeyFromX509File(file);
        byte[] signatureData1 = Hex.decode(signatureData);
        boolean verifyRes = GMUtil.verifySm3WithSm2(returnData.getBytes(), xyhnConfig.getUserId().getBytes(), signatureData1, publicKey);
        log.info("getPublicKey 接口验签结果:" + verifyRes);
        if (!verifyRes) {
            return null;
        }
        return publicKey;
    }

    public static String sendData(String jsonStr, String method) {

        log.info("调用省平台方法名:" + method + ",参数:" + jsonStr);

        try {
            if (StringUtils.isEmpty(pubKey)) { // 解析公钥
                pubKey = convertFileToBase64(xyhnConfig.getPubKeyPath());
            }
            if (reportPublicKey == null) {  //请求接口,获取公钥
                reportPublicKey = getPublicKey();
            }

            // 1、摘要签名 sm2withsm3
            byte[] msg = jsonStr.getBytes(CharEncoding.ISO_8859_1);
            byte[] userIdBytes = xyhnConfig.getUserId().getBytes();
            BigInteger d = new BigInteger(xyhnConfig.getPriKey(), 16);
            BCECPrivateKey bcecPrivateKey = GMUtil.getPrivatekeyFromD(d);
            byte[] sig = GMUtil.signSm3WithSm2(msg, userIdBytes, bcecPrivateKey);
            String signature = Hex.toHexString(sig);

            // 2、sm4加密数据报文
            String key1 = RandomUtil.randomString(16);
            String jsonobj = GMUtil.sm4Encrypt(key1, jsonStr);

            //3、sm2加密16位随机码key
            byte[] datamsg = GMUtil.sm2Encrypt(key1.getBytes(), reportPublicKey);
            String s = Hex.toHexString(datamsg);

            //4、组装并发送报文
            JSONObject jsonObject2 = new JSONObject();
            jsonObject2.put("requestData", jsonobj); // sm4加密的数据集
            jsonObject2.put("key", s); // sm2加密的16位随机码
            jsonObject2.put("signatureData", signature); // 签名
            jsonObject2.put("publicKey", pubKey); // 我的公钥
            jsonObject2.put("appKey", xyhnConfig.getAppKey()); // 数据授权的key

            String setFPRes = callInterface("report", method, jsonObject2.toJSONString());
            return setFPRes;
        } catch (Exception ex) {
            log.error("请求省平台接口异常", ex);
            return null;
        }

    }


    /**
     * 请求接口
     *
     * @param type,report 回传数据,query 查询
     * @param method
     * @param json
     * @return
     */
    private static String callInterface(String type, String method, String json) {
        log.info("调用省平台类型:" + type + ",接口:" + method + ",参数:" + json);
        Client client = null;
        QName name = null;
        JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
        String result = null;
        try {
            if ("report".equals(type)) {
                client = dcf.createClient(xyhnConfig.getWsAddr());
                name = new QName(xyhnConfig.getNamespaceURI(), method);
            } else if ("query".equals(type)) {
                client = dcf.createClient(xyhnConfig.getQueryWsAddr());
                name = new QName(xyhnConfig.getQueryNamespaceURI(), method);
            }

            Object[] objects = client.invoke(name, json);
            result = objects[0].toString();

        } catch (Exception e) {
            log.error("调用省平台接口报错", e);
        } finally {
            if (client != null) {
                try {
                    client.close();
                } catch (Exception e) {
                    log.error("关闭Client资源时发生异常", e);
                }
            }
        }

        log.info("调用省平台类型:" + type + ",接口:" + method + ",返回值:" + result);

        return result;
    }

    private static String convertFileToBase64(String imgPath) {
        byte[] data = null;
        // 读取图片字节数组
        try (InputStream in = new FileInputStream(imgPath);) {
            data = new byte[in.available()];
            in.read(data);
        } catch (IOException e) {
            log.error("IOException", e);
        }
        // 对字节数组进行Base64编码,得到Base64编码的字符串
        String base64Str = java.util.Base64.getEncoder().encodeToString(data);
        return base64Str;
    }

    private static File base64ToFileEx(String base64) {
        if (StringUtils.isBlank(base64)) {
            return null;
        }
        byte[] buff = Base64.decode(base64);
        File file = null;
        FileOutputStream fout = null;
        try {
            file = File.createTempFile("tmp", null);
            fout = new FileOutputStream(file);
            fout.write(buff);
            file.deleteOnExit();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fout != null) {
                try {
                    fout.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return file;
    }

}

3. 用到的工具类


package cn.bridgeli.demo;

import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.gm.GMNamedCurves;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.engines.SM2Engine;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
import org.bouncycastle.jcajce.spec.SM2ParameterSpec;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECParameterSpec;
import org.bouncycastle.jce.spec.ECPrivateKeySpec;
import org.bouncycastle.util.encoders.Hex;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.Signature;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Arrays;

@Slf4j
public class GMUtil {
    private static X9ECParameters x9ECParameters = GMNamedCurves.getByName("sm2p256v1");
    private static ECDomainParameters ecDomainParameters;
    private static ECParameterSpec ecParameterSpec;

    public static byte[] signSm3WithSm2(byte[] msg, byte[] userId, PrivateKey privateKey) {
        return rsAsn1ToPlainByteArray(signSm3WithSm2Asn1Rs(msg, userId, privateKey));
    }

    public static byte[] signSm3WithSm2Asn1Rs(byte[] msg, byte[] userId, PrivateKey privateKey) {
        try {
            SM2ParameterSpec parameterSpec = new SM2ParameterSpec(userId);
            Signature signer = Signature.getInstance("SM3withSM2", "BC");
            signer.setParameter(parameterSpec);
            signer.initSign(privateKey, new SecureRandom());
            signer.update(msg, 0, msg.length);
            byte[] sig = signer.sign();
            return sig;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static boolean verifySm3WithSm2(byte[] msg, byte[] userId, byte[] rs, PublicKey publicKey) {
        return verifySm3WithSm2Asn1Rs(msg, userId, rsPlainByteArrayToAsn1(rs), publicKey);
    }

    public static boolean verifySm3WithSm2Asn1Rs(byte[] msg, byte[] userId, byte[] rs, PublicKey publicKey) {
        try {
            SM2ParameterSpec parameterSpec = new SM2ParameterSpec(userId);
            Signature verifier = Signature.getInstance("SM3withSM2", "BC");
            verifier.setParameter(parameterSpec);
            verifier.initVerify(publicKey);
            verifier.update(msg, 0, msg.length);
            return verifier.verify(rs);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static byte[] changeC1C2C3ToC1C3C2(byte[] c1c2c3) {
        int c1Len = (x9ECParameters.getCurve().getFieldSize() + 7) / 8 * 2 + 1;

        byte[] result = new byte[c1c2c3.length];
        System.arraycopy(c1c2c3, 0, result, 0, c1Len);
        System.arraycopy(c1c2c3, c1c2c3.length - 32, result, c1Len, 32);
        System.arraycopy(c1c2c3, c1Len, result, c1Len + 32, c1c2c3.length - c1Len - 32);
        return result;
    }

    public static byte[] changeC1C3C2ToC1C2C3(byte[] c1c3c2) {
        int c1Len = (x9ECParameters.getCurve().getFieldSize() + 7) / 8 * 2 + 1;

        byte[] result = new byte[c1c3c2.length];
        System.arraycopy(c1c3c2, 0, result, 0, c1Len);
        System.arraycopy(c1c3c2, c1Len + 32, result, c1Len, c1c3c2.length - c1Len - 32);
        System.arraycopy(c1c3c2, c1Len, result, c1c3c2.length - 32, 32);
        return result;
    }

    public static byte[] sm2Decrypt(byte[] data, PrivateKey key) {
        return sm2DecryptOld(changeC1C3C2ToC1C2C3(data), key);
    }

    public static byte[] sm2Encrypt(byte[] data, PublicKey key) {
        return changeC1C2C3ToC1C3C2(sm2EncryptOld(data, key));
    }

    public static byte[] sm2EncryptOld(byte[] data, PublicKey key) {
        BCECPublicKey localECPublicKey = (BCECPublicKey) key;
        ECPublicKeyParameters ecPublicKeyParameters = new ECPublicKeyParameters(localECPublicKey.getQ(), ecDomainParameters);
        SM2Engine sm2Engine = new SM2Engine();
        sm2Engine.init(true, new ParametersWithRandom(ecPublicKeyParameters, new SecureRandom()));

        try {
            return sm2Engine.processBlock(data, 0, data.length);
        } catch (InvalidCipherTextException e) {
            throw new RuntimeException(e);
        }
    }

    public static byte[] sm2DecryptOld(byte[] data, PrivateKey key) {
        BCECPrivateKey localECPrivateKey = (BCECPrivateKey) key;
        ECPrivateKeyParameters ecPrivateKeyParameters = new ECPrivateKeyParameters(localECPrivateKey.getD(), ecDomainParameters);
        SM2Engine sm2Engine = new SM2Engine();
        sm2Engine.init(false, ecPrivateKeyParameters);

        try {
            return sm2Engine.processBlock(data, 0, data.length);
        } catch (InvalidCipherTextException e) {
            throw new RuntimeException(e);
        }
    }

    public static byte[] sm4Encrypt(byte[] keyBytes, byte[] plain) {
        byte[] keyBytes0;
        if (keyBytes.length != 16) {
            keyBytes0 = new byte[16];

            for (int i = 0; i < keyBytes0.length; ++i) {
                if (keyBytes.length > i) {
                    keyBytes0[i] = keyBytes[i];
                }
            }

            keyBytes = keyBytes0;
        }

        if (plain.length % 16 != 0) {
            keyBytes0 = new byte[16 * (plain.length / 16 + 1)];
            System.arraycopy(plain, 0, keyBytes0, 0, plain.length);
            plain = keyBytes0;
        }

        try {
            Key key = new SecretKeySpec(keyBytes, "SM4");
            Cipher out = Cipher.getInstance("SM4/ECB/NoPadding", "BC");
            out.init(1, key);
            return out.doFinal(plain);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static byte[] sm4Decrypt(byte[] keyBytes, byte[] cipher) {
        byte[] keyBytes0;
        if (keyBytes.length != 16) {
            keyBytes0 = new byte[16];

            for (int i = 0; i < keyBytes0.length; ++i) {
                if (keyBytes.length > i) {
                    keyBytes0[i] = keyBytes[i];
                }
            }

            keyBytes = keyBytes0;
        }

        if (cipher.length % 16 != 0) {
            keyBytes0 = new byte[16 * (cipher.length / 16 + 1)];
            System.arraycopy(cipher, 0, keyBytes0, 0, cipher.length);
            cipher = keyBytes0;
        }

        try {
            Key key = new SecretKeySpec(keyBytes, "SM4");
            Cipher in = Cipher.getInstance("SM4/ECB/NoPadding", "BC");
            in.init(2, key);
            byte[] bytes = in.doFinal(cipher);

            for (int i = bytes.length - 1; i >= 0; --i) {
                if (bytes[i] != 0) {
                    byte[] bytes1 = new byte[i + 1];
                    System.arraycopy(bytes, 0, bytes1, 0, i + 1);
                    bytes = bytes1;
                    i = -1;
                }
            }

            return bytes;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static String sm4Encrypt(String key, String plan) {
        byte[] keyBytes = new byte[16];
        byte[] keyBytes0 = key.getBytes(StandardCharsets.UTF_8);

        for (int i = 0; i < keyBytes.length; ++i) {
            if (keyBytes0.length > i) {
                keyBytes[i] = keyBytes0[i];
            }
        }

        byte[] cipher = plan.getBytes(StandardCharsets.UTF_8);

        byte[] bytes = sm4Encrypt(keyBytes, cipher);
        return Hex.toHexString(bytes).toUpperCase();
    }

    public static String sm4Decrypt(String key, String cipher) {
        byte[] keyBytes = new byte[16];
        byte[] keyBytes0 = key.getBytes(StandardCharsets.UTF_8);

        for (int i = 0; i < keyBytes.length; ++i) {
            if (keyBytes0.length > i) {
                keyBytes[i] = keyBytes0[i];
            }
        }

        byte[] cipherbytes = Hex.decode(cipher);
        byte[] bytes = sm4Decrypt(keyBytes, cipherbytes);

        return new String(bytes, StandardCharsets.UTF_8);

    }

    private static byte[] bigIntToFixexLengthBytes(BigInteger rOrS) {
        byte[] rs = rOrS.toByteArray();
        if (rs.length == 32) {
            return rs;
        } else if (rs.length == 33 && rs[0] == 0) {
            return Arrays.copyOfRange(rs, 1, 33);
        } else if (rs.length < 32) {
            byte[] result = new byte[32];
            Arrays.fill(result, (byte) 0);
            System.arraycopy(rs, 0, result, 32 - rs.length, rs.length);
            return result;
        } else {
            throw new RuntimeException("err rs: " + Hex.toHexString(rs));
        }
    }

    private static byte[] rsAsn1ToPlainByteArray(byte[] rsDer) {
        ASN1Sequence seq = ASN1Sequence.getInstance(rsDer);
        byte[] r = bigIntToFixexLengthBytes(ASN1Integer.getInstance(seq.getObjectAt(0)).getValue());
        byte[] s = bigIntToFixexLengthBytes(ASN1Integer.getInstance(seq.getObjectAt(1)).getValue());
        byte[] result = new byte[64];
        System.arraycopy(r, 0, result, 0, r.length);
        System.arraycopy(s, 0, result, 32, s.length);
        return result;
    }

    private static byte[] rsPlainByteArrayToAsn1(byte[] sign) {
        if (sign.length != 64) {
            throw new RuntimeException("err rs. ");
        } else {
            BigInteger r = new BigInteger(1, Arrays.copyOfRange(sign, 0, 32));
            BigInteger s = new BigInteger(1, Arrays.copyOfRange(sign, 32, 64));
            ASN1EncodableVector v = new ASN1EncodableVector();
            v.add(new ASN1Integer(r));
            v.add(new ASN1Integer(s));

            try {
                return (new DERSequence(v)).getEncoded("DER");
            } catch (IOException var5) {
                throw new RuntimeException(var5);
            }
        }
    }

    public static BCECPrivateKey getPrivatekeyFromD(BigInteger d) {
        ECPrivateKeySpec ecPrivateKeySpec = new ECPrivateKeySpec(d, ecParameterSpec);
        return new BCECPrivateKey("EC", ecPrivateKeySpec, BouncyCastleProvider.CONFIGURATION);
    }

    public static PublicKey getPublickeyFromX509File(File file) {
        try {
            CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC");
            FileInputStream in = new FileInputStream(file);
            X509Certificate x509 = (X509Certificate) cf.generateCertificate(in);
            return x509.getPublicKey();
        } catch (Exception var4) {
            throw new RuntimeException(var4);
        }
    }

    static {
        ecDomainParameters = new ECDomainParameters(x9ECParameters.getCurve(), x9ECParameters.getG(), x9ECParameters.getN());
        ecParameterSpec = new ECParameterSpec(x9ECParameters.getCurve(), x9ECParameters.getG(), x9ECParameters.getN());
        if (Security.getProvider("BC") == null) {
            Security.addProvider(new BouncyCastleProvider());
        }
    }
}

4. 相关配置


package cn.bridgeli.demo;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Data
@Component
@ConfigurationProperties(prefix = "xyhn")
//@RefreshScope
public class XyhnConfig {

    private String userId;
    private String platformId;

    private String appKey;
    private String priKey;
    private String wsAddr;
    private String namespaceURI;
    private String pubKeyPath;

    private String queryAppKey;
    private String queryPriKey;
    private String queryWsAddr;
    private String queryNamespaceURI;
    private String queryPubKeyPath;
}

以上是上报和查询数据的核心方法,下面是查询具体数据的封装

5. 查询的接口:


package cn.bridgeli.demo;

public interface XyhnService {
    Response queryDatas(String param, String page, String size);
}

package cn.bridgeli.demo;

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
public abstract class AbstractXyhnService implements XyhnService {

//    private static ICompInfoService compInfoService = SpringUtils.getBean(ICompInfoService.class);

    @Override
    public Response queryDatas(String enterpriseName, String page, String size) {

        CompInfo compInfoParam = new CompInfo();
//        compInfoParam.setEnterpriseName(enterpriseName);
//        List<CompInfo> compInfos = compInfoService.selectCompInfoList(compInfoParam);
//        CompInfo compInfo = null;
//        if (CollectionUtils.isEmpty(compInfos)) {
//            compInfo = new CompInfo();
//            compInfo.setEnterpriseName(enterpriseName);
//        } else {
//            compInfo = compInfos.get(0);
//        }

        List<QueryParam> list = buildQueryParam(compInfoParam);

        QueryParam isDeleteParam = new QueryParam();
        isDeleteParam.setField_value("0");
        isDeleteParam.setField_name("$$_ISDELETE");
        isDeleteParam.setField_type("String");
        isDeleteParam.setField_symbol("=");
        list.add(isDeleteParam);

        QueryParam stateParam = new QueryParam();
        stateParam.setField_value("0");
        stateParam.setField_name("$$_STATE");
        stateParam.setField_type("String");
        stateParam.setField_symbol("=");
        list.add(stateParam);

        if (StringUtils.isBlank(size) || StringUtils.isBlank(page)) {
            size = "20";
            page = "1";
        }

        JSONObject jsonObject = new JSONObject();
        buildTableIdParam(jsonObject);

        jsonObject.put("query", list);
        jsonObject.put("page", page);
        jsonObject.put("size", size);

        buildSortParam(jsonObject);

        String data = XyhnUtil.queryData("queryPageDataByTableId", jsonObject);

        return parseXml(data);
    }

    protected abstract List<QueryParam> buildQueryParam(CompInfo compInfo);

    protected abstract void buildTableIdParam(JSONObject jsonObject);

    protected abstract void buildSortParam(JSONObject jsonObject);

    public static Response parseXml(String xmlContent) {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        Document doc = null;
        try {
            DocumentBuilder builder = factory.newDocumentBuilder();
            doc = builder.parse(new InputSource(new StringReader(xmlContent)));
        } catch (ParserConfigurationException e) {
            log.error("ParserConfigurationException", e);
        } catch (IOException e) {
            log.error("IOException", e);
        } catch (SAXException e) {
            log.error("SAXException", e);
        }

        if (null == doc) {
            return null;
        }

        Response response = new Response();

        Element root = doc.getDocumentElement();
        Element datas = (Element) root.getElementsByTagName("datas").item(0);

        // Extract items
        NodeList rowList = datas.getElementsByTagName("row");
        if (rowList.getLength() <= 0) {
            return response;
        }

        List<Map<String, String>> items = new ArrayList<>();
        for (int i = 0; i < rowList.getLength(); i++) {
            Element row = (Element) rowList.item(i);
            NodeList itemList = row.getElementsByTagName("item");
            if (itemList.getLength() == 0) {
                continue;
            }
            Map<String, String> itemMap = new HashMap<>();
            for (int j = 0; j < itemList.getLength(); j++) {
                Element item = (Element) itemList.item(j);
                String key = item.getAttribute("field");
                String value = item.getTextContent();
                itemMap.put(key, value);
            }
            items.add(itemMap);

        }
        response.setData(items);

        // Extract attributes from the 'datas' tag
        NamedNodeMap attrs = datas.getAttributes();
        response.setStartIndex(Integer.parseInt(attrs.getNamedItem("startIndex").getNodeValue()));
        response.setTotalPage(Integer.parseInt(attrs.getNamedItem("totalPage").getNodeValue()));
        response.setTotalSize(Integer.parseInt(attrs.getNamedItem("totalSize").getNodeValue()));
        response.setTime(Integer.parseInt(attrs.getNamedItem("time").getNodeValue()));
        response.setSize(Integer.parseInt(attrs.getNamedItem("size").getNodeValue()));

        log.info("解析成对象之后: " + JSONObject.toJSONString(response));

        return response;
    }

}

查询的具体实现主要分三种:

① 普通查询,即公开公示的接口:


package cn.bridgeli.demo;

import com.alibaba.fastjson.JSONObject;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
public class GsAoOpaDetailServiceImpl extends AbstractXyhnService {
    @Override
    protected List<QueryParam> buildQueryParam(CompInfo compInfo) {
        QueryParam queryParam = new QueryParam();
        queryParam.setField_value(compInfo.getEnterpriseName());
        queryParam.setField_type("String");
        queryParam.setField_symbol("=");
        queryParam.setField_name("ENTNAME");
        return Stream.of(queryParam).collect(Collectors.toList());
    }

    @Override
    protected void buildTableIdParam(JSONObject jsonObject) {
        jsonObject.put("tableId", "");
    }

    @Override
    protected void buildSortParam(JSONObject jsonObject) {
//        jsonObject.put("sort", Stream.of("$$_MDATE").collect(Collectors.toList()));
    }
}

② 普通授权接口


package cn.bridgeli.demo;

import com.alibaba.fastjson.JSONObject;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
public class ZxqySbbxfjnServiceImpl extends AbstractXyhnService {
    @Resource
    private XYHNConfig xyhnConfig;

    @Override
    protected List<QueryParam> buildQueryParam(CompInfo compInfo) {

        if (!"0".equals(compInfo.getCancelAuthState())) {
            throw new ServiceException("接口未授权,请先授权");
        }
        String licenseId = compInfo.getLicenseId();
        if (StringUtils.isBlank(licenseId)) {
            throw new ServiceException("接口未授权,无法调用");
        }

        QueryParam queryParam = new QueryParam();
        queryParam.setField_value(compInfo.getEnterpriseName());
        queryParam.setField_type("String");
        queryParam.setField_symbol("=");
        queryParam.setField_name("enterpriseName");

        QueryParam licenseIdParam = new QueryParam();
        licenseIdParam.setField_value(licenseId);
        licenseIdParam.setField_name("licenseId");
        licenseIdParam.setField_type("String");
        licenseIdParam.setField_symbol("=");


        QueryParam uniscIdParam = new QueryParam();
        uniscIdParam.setField_value(compInfo.getUniscId());
        uniscIdParam.setField_name("uniscId");
        uniscIdParam.setField_type("String");
        uniscIdParam.setField_symbol("=");


        QueryParam platformIdParam = new QueryParam();
        platformIdParam.setField_value(xyhnConfig.getPlatformId());
        platformIdParam.setField_name("platformId");
        platformIdParam.setField_type("String");
        platformIdParam.setField_symbol("=");


        QueryParam searchOrgCodeParam = new QueryParam();
//        searchOrgCodeParam.setField_value(compInfo.getAuthorizedOrgsCode());
        searchOrgCodeParam.setField_name("searchOrgCode");
        searchOrgCodeParam.setField_type("String");
        searchOrgCodeParam.setField_symbol("=");

        return Stream.of(queryParam, licenseIdParam, uniscIdParam, platformIdParam, searchOrgCodeParam).collect(Collectors.toList());
    }

    @Override
    protected void buildTableIdParam(JSONObject jsonObject) {
        jsonObject.put("tableId", "");
    }

    @Override
    protected void buildSortParam(JSONObject jsonObject) {

    }
}

③ 省授权接口


package cn.bridgeli.demo;

import com.alibaba.fastjson.JSONObject;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
public class SrstCbdwsbjfxxServiceImpl extends AbstractXyhnService {

    @Resource
    private XYHNConfig xyhnConfig;

    // searchSubject 和 searchSubjectCode,对应 getAuth 接口的 searchSubject 和 searchSubjectCode
    @Override
    protected List<QueryParam> buildQueryParam(CompInfo compInfo) {

        String authId = compInfo.getAuthId();
        if (StringUtils.isBlank(authId)) {
            throw new ServiceException("请先获取省授权");
        }
        Date validDate = compInfo.getValidDate();

        QueryParam searchSubjectParam = new QueryParam();
        searchSubjectParam.setField_value(compInfo.getEnterpriseName());
        searchSubjectParam.setField_type("String");
        searchSubjectParam.setField_symbol("=");
        searchSubjectParam.setField_name("aab004");

        QueryParam searchSubjectCodeParam = new QueryParam();
        searchSubjectCodeParam.setField_value(compInfo.getUniscId());
        searchSubjectCodeParam.setField_type("String");
        searchSubjectCodeParam.setField_symbol("=");
        searchSubjectCodeParam.setField_name("aab039");

        QueryParam authKeyParam = new QueryParam();
        authKeyParam.setField_value(xyhnConfig.getQueryAppKey());
        authKeyParam.setField_name("authKey");
        authKeyParam.setField_type("String");
        authKeyParam.setField_symbol("=");


        QueryParam authIDParam = new QueryParam();
        authIDParam.setField_value(authId);
        authIDParam.setField_name("authID");
        authIDParam.setField_type("String");
        authIDParam.setField_symbol("=");

        return Stream.of(searchSubjectParam, searchSubjectCodeParam, authKeyParam, authIDParam).collect(Collectors.toList());
    }

    @Override
    protected void buildTableIdParam(JSONObject jsonObject) {
        jsonObject.put("tableId", "");
    }

    @Override
    protected void buildSortParam(JSONObject jsonObject) {

    }
}

6. 查询参数的封装:


package cn.bridgeli.demo;

import lombok.Data;

@Data
public class QueryParam {
    private String field_name;
    private String field_type;
    private String field_value;
    private String field_symbol;
    private String field_grantmapping;
}

7. 返回值的封装


package cn.bridgeli.demo;

import lombok.Data;

import java.util.List;
import java.util.Map;

@Data
public class Response {

    private Integer startIndex;
    private Integer totalPage;
    private Integer totalSize;
    private Integer time;
    private Integer size;
    private List<Map<String, String>> data;
}

8. 接口类型


package cn.bridgeli.demo;

import lombok.Getter;

@Getter
public enum FaGaiWeiInterfaceEnum {

    gsQyjbxxServiceImpl("社会公开", "工商企业基本信息(带行业代码)"),
    zxqyQysfqsServiceImpl("授权查询", "中小企业融资-企业是否欠税"),
    zrtBdcqdjxxFdcqServiceImpl("授权查询", "不动产_不动产权登记信息_房地产权信息-省授权"),
    mztHydjxxServiceImpl("社会公开", "婚姻登记信息-省授权"),
    ;

    FaGaiWeiInterfaceEnum(String openType, String description) {
        this.openType = openType;
        this.description = description;
    }

    private final String openType;
    private final String description;

}

最后也必须要说明的是,这段代码是我随手从项目中摘出来的,并不完全,也会存在很多问题,但思路是没错的,代码也存在很大的优化空间.

全文完,如果本文对您有所帮助,请花 1 秒钟帮忙点击一下广告,谢谢。

作 者: BridgeLi,https://www.bridgeli.cn
原文链接:http://www.bridgeli.cn/archives/764
版权声明:非特殊声明均为本站原创作品,转载时请注明作者和原文链接。
分类: Java 标签:
  1. 本文目前尚无任何评论.

请输入正确的验证码