IRS 接口调用

特别说明:

快速调用示例

    public static void main(String[] args) {

        String accessKey = "你的 accessKey";
        String secretKey = "你的 secretKey ";
        String urlStr = "https://ibcdsg.zj.gov.cn:8443/restapi/prod/IC33000020240523000016/proxy/eccbc87e4b5ce2fe28308fd9f2a7baf3/c51ce410c124a10e0db5e4b97fc2af39/addrdata/associate/api/search";

        UrlBuilder builder = UrlBuilder.of(urlStr)
                .addQuery("query", "杭州中泰中心小学")
                .addQuery("adcode", "330000")
                .addQuery("ack", "6ba46de613594b4b88e93613e36a3fd8");

        long timeMillis = System.currentTimeMillis();
        Map<String, String> headers = HmacAuthUtil.generateHeader(builder.build(), HttpMethod.GET.name(), accessKey, secretKey);
        HttpResponse<String> response = Unirest.get(builder.build())
                .headers(headers)
                .asString();

        System.out.println(response.getBody());
        System.out.println(timeMillis);
        System.out.println(Md5Utils.md5(accessKey + secretKey + timeMillis));
    }

业务中的示例

1、添加Maven依赖

<!-- https://mvnrepository.com/artifact/com.konghq/unirest-java -->
<dependency>
    <groupId>com.konghq</groupId>
    <artifactId>unirest-java</artifactId>
    <version>3.14.5</version>
</dependency>

2、公共工具类

  • HmacAuthUtil
import javafx.util.Pair;
import lombok.extern.slf4j.Slf4j;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URL;
import java.net.URLEncoder;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 仅适用于IRS请求信息加密
 */
@Slf4j
public class HmacAuthUtil {

    public static void main(String[] args) {
        String url="http://59.202.53.51:9080/restapi/prod/IC33000020220124000009/ip";
        String ak =  "test11";
        String sk = "test333";
        String method="GET";
        Map<String, String> header = HmacAuthUtil.generateHeader(url, method, ak, sk);

        Iterator<String> its = header.keySet().iterator();
        while(its.hasNext()){
            String next = its.next();
            System.out.println(next+":"+header.get(next));
        }
    }

    /**
     * 构造请求 header
     * @param urlStr 请求url,全路径格式,比如:https://bcdsg.zj.gov.cn/api/p/v1/user.get
     * @param requestMethod 请求方法,大写格式,如:GET, POST
     * @param accessKey 应用的 AK
     * @param secretKey 应用的 SK
     * @return
     */
    public static Map<String, String> generateHeader(String urlStr, String requestMethod, String accessKey, String secretKey) {
        log.info("params,urlStr={},requestMethod={},accessKey={},secretKey={}",urlStr,requestMethod,accessKey,secretKey);
        Map<String, String> header = new HashMap<>();
        try {
            DateFormat dateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
            dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
            String date = dateFormat.format(new Date());
            URL url = new URL(urlStr);
            URI uri = new URI(url.getProtocol(), url.getHost(), url.getPath(), url.getQuery(), null);

            String canonicalQueryString = getCanonicalQueryString(uri.getQuery());

            String message = requestMethod.toUpperCase() + "\n" + uri.getPath() + "\n" + canonicalQueryString + "\n"  + accessKey + "\n" + date + "\n";

            Mac hasher = Mac.getInstance("HmacSHA256");
            hasher.init(new SecretKeySpec(secretKey.getBytes(), "HmacSHA256"));

            byte[] hash = hasher.doFinal(message.getBytes());

            // to lowercase hexits
            DatatypeConverter.printHexBinary(hash);

            // to base64
            String sign = DatatypeConverter.printBase64Binary(hash);
            header.put("X-BG-HMAC-SIGNATURE", sign);
            header.put("X-BG-HMAC-ALGORITHM", "hmac-sha256");
            header.put("X-BG-HMAC-ACCESS-KEY", accessKey);
            header.put("X-BG-DATE-TIME", date);
        } catch (Exception e) {
            log.error("generate error",e);
            throw new RuntimeException("generate header error");
        }
        log.info("header info,{}",header);
        return header;
    }

    private static String getCanonicalQueryString(String query) {
        if (query == null || query.trim().length() == 0) {
            return "";
        }
        List<Pair<String, String>> queryParamList = new ArrayList<>();
        String[] params = query.split("&");
        for (String param : params) {
            int eqIndex = param.indexOf("=");
            String key = param.substring(0, eqIndex);
            String value = param.substring(eqIndex+1);
            Pair<String, String> pair = new Pair<String, String>(key,value);
            queryParamList.add(pair);
        }

        List<Pair<String, String>> sortedParamList = queryParamList.stream().sorted(Comparator.comparing(param -> param.getKey() + "=" + Optional.ofNullable(param.getValue()).orElse(""))).collect(Collectors.toList());
        List<Pair<String, String>> encodeParamList = new ArrayList<>();
        sortedParamList.stream().forEach(param -> {
            try {
                String key = URLEncoder.encode(param.getKey(), "utf-8");
                String value = URLEncoder.encode(Optional.ofNullable(param.getValue()).orElse(""), "utf-8")
                        .replaceAll("\\%2B","%20")
                        .replaceAll("\\+","%20")
                        .replaceAll("\\%21","!")
                        .replaceAll("\\%27","'")
                        .replaceAll("\\%28","(")
                        .replaceAll("\\%29",")")
                        .replaceAll("\\%7E","~")
                        .replaceAll("\\%25","%")
                        ;
                encodeParamList.add(new Pair<>(key, value));
            } catch (UnsupportedEncodingException e) {
                throw new RuntimeException("encoding error");
            }
        });
        StringBuilder queryParamString = new StringBuilder(64);
        for (Pair<String, String> encodeParam : encodeParamList) {
            queryParamString.append(encodeParam.getKey()).append("=").append(Optional.ofNullable(encodeParam.getValue()).orElse(""));
            queryParamString.append("&");
        }

        return queryParamString.substring(0, queryParamString.length() - 1);
    }
}
  • Md5Utils
import lombok.SneakyThrows;

import java.security.MessageDigest;

/**
 * 仅适用于IRS请求信息加密
 */
public class Md5Utils {

    /**
     * Md 5 string.
     *
     * @param src     the src
     * @param charset the charset
     * @return the string
     */
    @SneakyThrows
    private static String md5(final String src, final String charset) {
        MessageDigest md5;
        StringBuilder hexValue = new StringBuilder(32);
        md5 = MessageDigest.getInstance("MD5");
        byte[] byteArray;
        byteArray = src.getBytes(charset);
        byte[] md5Bytes = md5.digest(byteArray);
        for (byte md5Byte : md5Bytes) {
            int val = ((int) md5Byte) & 0xff;
            if (val < 16) {
                hexValue.append("0");
            }
            hexValue.append(Integer.toHexString(val));
        }
        return hexValue.toString();
    }

    /**
     * Md 5 string.
     *
     * @param src the src
     * @return the string
     */
    public static String md5(final String src) {
        return md5(src, "UTF-8");
    }

}

IRS 组件,IRSComponentJobHandler 示例

import cn.hutool.core.net.url.UrlBuilder;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.tianyin.evaluation.admin.bmp.service.ISjZxxxXxjbsjlbService;
import com.tianyin.evaluation.admin.entity.bmp.SjZxxxXxjbsjlbEntity;
import com.tianyin.evaluation.job.util.HmacAuthUtil;
import com.tianyin.evaluation.job.util.Md5Utils;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import com.xxl.job.spring.boot.annotation.XxlJobCron;
import kong.unirest.HttpMethod;
import kong.unirest.HttpResponse;
import kong.unirest.Unirest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * IRS 组件调用
 * 特别说明:
 * 1、在组件超市中目前存在两种方式调用,组件详情页中展示的调用地址为:“https://interface.zjzwfw.gov.cn/gateway/component/routing/agent.htm” 时参考《调用方式一》进行对接。
 * 2、组件超市页面展示的调用地址类似:“https://bcdsg.zj.gov.cn:8443/restapi/prod/*”地址时,采用《调用方式二》进行对接。
 */
@Component
public class IRSComponentJobHandler {

    private final static String GATEWAY = "https://interface.zjzwfw.gov.cn/gateway/component/routing/agent.htm";

    @Autowired
    private ISjZxxxXxjbsjlbService sjZxxxXxjbsjlbService;
    /**
     * IRS 配置
     */
    @Value("${datasync.irs.geo.secret-key:}")
    private String secretKey;
    @Value("${datasync.irs.geo.access-key:}")
    private String accessKey;
    @Value("${datasync.irs.geo.adcode:330100}")
    private String adcode;
    @Value("${datasync.irs.geo.call-type:2}")
    private int callType;

    /**
     * 1、空间地址服务组件
     */
    @XxlJob("addrJobHandler")
    @XxlJobCron(cron = "0 0 2 * * ?", desc = "空间地址服务组件", author = "wandl", selfStarting = true)
    public ReturnT<String> addrJobHandler() throws Exception {

        // 政务外网地址: https://bcdsg.zj.gov.cn:8443/restapi/prod/IC33000020240523000016/proxy/eccbc87e4b5ce2fe28308fd9f2a7baf3/c51ce410c124a10e0db5e4b97fc2af39/addrdata/associate/api/search
        // 互联网地址: https://ibcdsg.zj.gov.cn:8443/restapi/prod/IC33000020240523000016/proxy/eccbc87e4b5ce2fe28308fd9f2a7baf3/c51ce410c124a10e0db5e4b97fc2af39/addrdata/associate/api/search

        List<SjZxxxXxjbsjlbEntity> schoolList = sjZxxxXxjbsjlbService.list(new LambdaQueryWrapper<SjZxxxXxjbsjlbEntity>()
                .select(SjZxxxXxjbsjlbEntity::getXxbsm, SjZxxxXxjbsjlbEntity::getXxdm, SjZxxxXxjbsjlbEntity::getXxmc, SjZxxxXxjbsjlbEntity::getXxbxlxm)
                .eq(SjZxxxXxjbsjlbEntity::getIsDelete, "0")
                .isNotNull(SjZxxxXxjbsjlbEntity::getXxbsm));
        if (CollectionUtils.isEmpty(schoolList)) {
            XxlJobHelper.log("业务中台学校列表为空,无需执行IRS组件调用任务.");
            return ReturnT.SUCCESS;
        }
        for (SjZxxxXxjbsjlbEntity schoolEntity : schoolList) {
            /*
             * zjgxfwxt-interface-code    是    string    接口请求唯一标识
             * zjgxfwxt-access-key    是    string    应用访问授权码(AK)
             * zjgxfwxt-sign    是    string    认证签名,签名规则:MD5(AK+SK+时间毫秒值),其签名值小写,MD5工具类详细信息详见附件(如何获取AK/SK,参考常见问题)
             * zjgxfwxt-time    是    string    时间毫秒值(示例:1632643914516)
             */
            long timeMillis = System.currentTimeMillis();

            if(callType == 1){
                HttpResponse<String> response = Unirest.get(GATEWAY)
                        // 请求头必须包含zjgxfwxt-interface-code、zjgxfwxt-time、zjgxfwxt-access-key、zjgxfwxt-sign
                        .header("zjgxfwxt-interface-code", "Z33000020240523000006")
                        .header("zjgxfwxt-access-key", accessKey)
                        .header("zjgxfwxt-sign", Md5Utils.md5(accessKey + secretKey + timeMillis))
                        .header("zjgxfwxt-time", String.valueOf(timeMillis))
                        .queryString("query", schoolEntity.getXxmc())
                        .queryString("adcode", adcode)
                        .queryString("ack", "6ba46de613594b4b88e93613e36a3fd8")
                        .asString();
                XxlJobHelper.log("学校标识码: {},空间地址服务组件调用返回结果:{}", schoolEntity.getXxbsm(), response.getBody());
            } else if(callType == 2){
                String urlStr = "https://ibcdsg.zj.gov.cn:8443/restapi/prod/IC33000020240523000016/proxy/eccbc87e4b5ce2fe28308fd9f2a7baf3/c51ce410c124a10e0db5e4b97fc2af39/addrdata/associate/api/search";
                UrlBuilder builder = UrlBuilder.of(urlStr)
                        .addQuery("query", schoolEntity.getXxmc())
                        .addQuery("adcode", adcode)
                        .addQuery("ack", "6ba46de613594b4b88e93613e36a3fd8");
                Map<String, String> headers = HmacAuthUtil.generateHeader(builder.build(), HttpMethod.GET.name(), accessKey, secretKey);
                HttpResponse<String> response = Unirest.get(builder.build())
                        .headers(headers)
                        .asString();
                XxlJobHelper.log("学校标识码: {},空间地址服务组件调用返回结果:{}", schoolEntity.getXxbsm(), response.getBody());
            }
            TimeUnit.SECONDS.sleep(2);
        }
        return ReturnT.SUCCESS;
    }

}
作者:杭州天音  创建时间:2025-05-15 18:09
最后编辑:杭州天音  更新时间:2025-08-20 19:36