e签宝工具类

263 阅读15分钟

本工具类包含,企业认证完整流程,人脸识别,文件合同签署等


/**
 * @program: dsr-cloud-master
 * @description: e签宝工具类
 * @author: 尉一民
 * @create: 2024-01-21 01:12
 **/

public class EqbUtils {

    private static final Logger logger = LoggerFactory.getLogger(EqbUtils.class);
    /**
     * 沙盒模式使用URL
     */
//    // e签宝接口调用域名(模拟环境)
//    public static final String ESIGN_HOST = "https://smlopenapi.esign.cn";

//     e签宝接口调用域名(正式环境)
    public static final String ESIGN_HOST = "https://openapi.esign.cn";

    // 账号的appid
    public static final String APPID = "";
    // 账号的secret
    public static final String SECRET = "";

  /**
     * 运营商3要素比对
     *
     * @param name     名称
     * @param idno     身份证号
     * @param mobileNo 手机号
     * @return String
     */
    public static String verifyPerson3keys(String name, String idno, String mobileNo) {
        int code = 0;
        String msg = "";
        String flowId = "";
        JSONObject jspell = new JSONObject();
        jspell.put("idNo", idno);
        jspell.put("name", name);
        jspell.put("mobileNo", mobileNo);
        String res = "";
        logger.info("============纯API方式【发起运营商3要素实名认证】==========");
        res = HttpHelper.sendPost(EqbConfig.startPer3keys_telecom(), TokenHelper.getToken(), jspell.toString());
        JSONObject jparse = JsonUtils.parseObject(res, JSONObject.class);
        code = jparse.getInt("code");
        msg = jparse.getStr("message");
        if (code != 0) {
            logger.error("个人信息比对成功失败具体信息: " + msg);
            throw new ServiceException(new ErrorCode(400, msg));
        }
        JSONObject data = jparse.getJSONObject("data");
        flowId = data.getStr("flowId");
        logger.info("实名流程Id: " + flowId);
        return flowId;
    }

    /**
     * 个人信息比对
     *
     * @param name 个人姓名
     * @param idno 身份证件号
     * @return String
     * @author: 尉一民
     */
    public static Boolean verifyPerson2keys(String name, String idno) {
        logger.info("个人2要素信息比对name:{},idno:{}", name, idno);
        int code = 0;
        String msg = "";
        JSONObject jspell = new JSONObject();
        jspell.put("idNo", idno);
        jspell.put("name", name);
        // 获取个人2要素信息比对请求url
        String url = EqbConfig.verifyPer2keys();
        String token = TokenHelper.getToken();
        String res = HttpHelper.sendPost(url, token, jspell.toString());
        JSONObject jparse = JsonUtils.parseObject(res, JSONObject.class);
        code = jparse.getInt("code");
        msg = jparse.getStr("message");
        if (code != 0) {
            logger.error("个人信息比对成功失败具体信息: " + msg);
            return Boolean.FALSE;
        }
        return Boolean.TRUE;
    }

    /**
     * 企业2要素信息比对
     *
     * @param name    企业名称
     * @param orgCode 企业证件号,支持15位工商注册号或统一社会信用代码
     * @return 信息比对业务Id
     * @author: 尉一民
     */
    public static Boolean verifyEnterprise2keys(String name, String orgCode) {
        logger.info("企业2要素信息比对name:{},orgCode:{}", name, orgCode);
        int code = 0;
        String msg = "";
        String verifyId = "";
        JSONObject jspell = new JSONObject();
        jspell.put("orgCode", orgCode);
        jspell.put("name", name);
        // 获取企业2要素信息比对请求url
        String url = EqbConfig.verifyEnterprise2keys();
        String token = TokenHelper.getToken();
        String res = HttpHelper.sendPost(url, token, jspell.toString());
        JSONObject jparse = JsonUtils.parseObject(res, JSONObject.class);
        code = jparse.getInt("code");
        msg = jparse.getStr("message");
        if (code != 0) {
            logger.error("企业信息比对成功失败具体信息: " + msg);
            return Boolean.FALSE;
        }
        return Boolean.TRUE;
    }

    /**
     * 企业4要素信息比对
     *
     * @param name           企业名称
     * @param orgCode        企业统一社会信用代码或工商注册号
     * @param legalRepName   企业法定代表人姓名
     * @param legalRepCertNo 企业法定代表人身份证号
     * @return
     */
    public static Boolean verifyEnterprise4keys(String name, String orgCode, String legalRepName, String legalRepCertNo) {
        logger.info("企业2要素信息比对name:{},orgCode:{},legalRepName:{},legalRepCertNo:{}", name, orgCode, legalRepName, legalRepCertNo);
        int code = 0;
        String msg = "";
        JSONObject jspell = new JSONObject();
        jspell.put("orgCode", orgCode);
        jspell.put("name", name);
        jspell.put("legalRepName", legalRepName);
        jspell.put("legalRepCertNo", legalRepCertNo);
        String url = EqbConfig.verifyEnterprise4keys();
        String res = "";
        logger.info("============企业4要素信息比对==========");
        res = HttpHelper.sendPost(url, TokenHelper.getToken(), jspell.toString());
        JSONObject jparse = JsonUtils.parseObject(res, JSONObject.class);
        code = jparse.getInt("code");
        msg = jparse.getStr("message");
        if (code != 0) {
            logger.error("企业信息比对成功失败具体信息: " + msg);
            return Boolean.FALSE;
        }
        return Boolean.TRUE;
    }

    /**
     * 企业/个人文件签署
     *
     * @param filePath    文件目录地址
     * @param notifyUrl   回调地址
     * @param redirectUrl 官方重定向调用地址(带body)
     * @param fileSignBo  文件签署校验类
     * @return String 签署流程id
     * @throws EsignDemoException
     * @author: 尉一民
     */
    public static String fileSign(String filePath, String notifyUrl, String redirectUrl, FileSignBo fileSignBo) throws EsignDemoException {
        Gson gson = new Gson();
        EsignHttpResponse getUploadUrl = EqbFileUtils.getUploadUrl(filePath);
        JsonObject getUploadUrlJsonObject = gson.fromJson(getUploadUrl.getBody(), JsonObject.class);
        JsonObject data = getUploadUrlJsonObject.getAsJsonObject("data");
        // 文件id后续发起签署使用
        String fileId = data.get("fileId").getAsString();
        String fileUploadUrl = data.get("fileUploadUrl").getAsString();
        fileSignBo.setFileId(fileId);
        logger.info("获取文件id以及文件上传地址成功,文件id:{},上传链接:{}", fileId, fileUploadUrl);
        // 文件上传
        EsignHttpResponse uploadFileResponse = EqbFileUtils.uploadFile(fileUploadUrl, filePath);
        JsonObject uploadFileResponseJsonObject = gson.fromJson(uploadFileResponse.getBody(), JsonObject.class);
        int errCode = uploadFileResponseJsonObject.get("errCode").getAsInt();
        logger.info("文件上传成功,状态码:{}", errCode);
        // 文件上传成功后文件会有一个异步处理过程,建议轮询文件状态,正常后发起签署
        // 查询文件上传状态
        int i = 0;
        while (i < 3) {
            EsignHttpResponse fileStatus = EqbFileUtils.getFileStatus(fileId);
            JSONObject fileStatusJsonObject = JsonUtils.parseObject(fileStatus.getBody(), JSONObject.class);
            String status = fileStatusJsonObject.getJSONObject("data").getStr("fileStatus");
            logger.info(String.format("查询文件状态执行第%s次", i + 1));
            if ("2".equalsIgnoreCase(status) || "5".equalsIgnoreCase(status)) {// 查询状态为2或者5代表文件准备完成
                System.out.println("文件准备完成");
                break;
            }
            System.out.println("文件未准备完成,等待两秒重新查询");
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            i++;
        }
        // 创建签署流程
        return createByFile(notifyUrl, redirectUrl, fileSignBo);
    }

    /**
     * 发起签署
     *
     * @return String
     * @throws EsignDemoException
     * @author: 尉一民
     */
    public static String createByFile(String notifyUrl, String redirectUrl, FileSignBo fileSignBo) throws EsignDemoException {
        logger.info("发起签署参数Json:{}", JsonUtils.toJsonString(fileSignBo));
        String apiaddr = "/v3/sign-flow/create-by-file";
        // 请求参数body体,json格式。get或者delete请求时jsonString传空json:"{}"或者null
        FileSign fileSign = new FileSign();
        // 设置待签署文件信息
        Docs build = Docs.build(fileSignBo.getFileId(), fileSignBo.getFileName());
        ArrayList<Docs> docsList = Lists.newArrayList();
        docsList.add(build);
        fileSign.setDocs(docsList);

        // 签署流程配置项
        SignFlowConfig signFlowConfig = SignFlowConfig.build(fileSignBo.getSignFlowTitle(), notifyUrl, redirectUrl);
        fileSign.setSignFlowConfig(signFlowConfig);

        // 签署方信息
        List<Signers> signersList = Lists.newArrayList();
        signersList.add(Signers.build(fileSignBo));
        fileSign.setSigners(signersList);

        String jsonParm = JSONUtil.toJsonStr(fileSign);
        // 请求方法
        EsignRequestType requestType = EsignRequestType.POST;
        // 生成请求签名鉴权方式的Header
        Map<String, String> header = EsignHttpHelper.signAndBuildSignAndJsonHeader(APPID, SECRET, jsonParm, requestType.name(), apiaddr, true);
        // 发起接口请求
        EsignHttpResponse esignHttpResponse = EsignHttpHelper.doCommHttp(ESIGN_HOST, apiaddr, requestType, jsonParm, header, true);
        JSONObject entries = JsonUtils.parseObject(esignHttpResponse.getBody(), JSONObject.class);
        // 签署流程ID
        return entries.getJSONObject("data").getStr("signFlowId");
    }

    /**
     * 人脸识别
     *
     * @param name         姓名
     * @param idNo         身份证号
     * @param faceauthMode 人脸识别默认方式"ESIGN
     * @param callbackUrl  重定向地址
     * @return String
     * @throws Exception
     * @author: 尉一民
     */
    public static FaceIdentityRespVO faceIdentity(String name, String idNo, String faceauthMode, String callbackUrl) {
        logger.info("人脸识别参数name:{},idno:{}", name, idNo);
        int code = 0;
        String msg = "";
        FaceIdentity faceIdentity = new FaceIdentity();
        faceIdentity.setIdNo(idNo);
        faceIdentity.setName(name);
        faceIdentity.setFaceauthMode("ESIGN");
        // 获取人脸识别链接地址
        String res = HttpHelper.sendPost(EqbConfig.startFaceVerify(), TokenHelper.getToken(), JsonUtils.toJsonString(faceIdentity));
        JSONObject jparse = JsonUtils.parseObject(res, JSONObject.class);
        code = jparse.getInt("code");
        msg = jparse.getStr("message");
        JSONObject data = jparse.getJSONObject("data");
        FaceIdentityRespVO faceIdentityRespVO = new FaceIdentityRespVO();
//        originalUrl = jparse.getStr("originalUrl"); 长链接
        if (code != 0) {
            logger.error("人脸识别成功失败具体信息: " + msg);
            throw new ServiceException(new ErrorCode(400, msg));
        }
        faceIdentityRespVO.setFlowId(data.getStr("flowId"));
        faceIdentityRespVO.setFaceIdentityUrl(data.getStr("authUrl"));
        return faceIdentityRespVO;
    }

    /**
     * 人脸识别状态
     *
     * @param flowId 人脸识别流程ID
     * @return
     */
    public static Boolean type(String flowId) {
        int code = 0;
        // 获取人脸识别链接地址
        String res = HttpHelper.sendGet2(EqbConfig.queryPersonalFaceVerify(flowId), TokenHelper.getToken());
        JSONObject jparse = JsonUtils.parseObject(res, JSONObject.class);
        JSONObject data = jparse.getJSONObject("data");
        code = jparse.getInt("code");
        if (code != 0) {
            return Boolean.FALSE;
        }
        if (!data.getStr("status").equals("SUCCESS")) {
            throw new ServiceException(new ErrorCode(400, data.getStr("message")));
        }
        return Boolean.TRUE;
    }


    /**
     * 身份证OCR识别
     *
     * @param infoImg   身份证信息面图片BASE64字符串。
     * @param emblemImg 身份证国徽面图片BASE64字符串
     * @param name      姓名
     * @param idNo      身份证号
     * @return verifyId 业务Id为null失败
     * @author: 尉一民
     */
    public static JSONObject idCard(String infoImg, String emblemImg, String name, String idNo) {
        int code = 0;
        String msg = "";
        JSONObject jspell = new JSONObject();
        jspell.put("infoImg", FileUtils.getBase64(infoImg));
        jspell.put("emblemImg", FileUtils.getBase64(emblemImg));
        logger.info("============身份证Ocr识别==========");
        String token = TokenHelper.getToken();
        String res = HttpHelper.sendPost(EqbConfig.idcard(), token, jspell.toString());
        JSONObject jparse = JsonUtils.parseObject(res, JSONObject.class);
        code = jparse.getInt("code");
        msg = jparse.getStr("message");
        if (code != 0) {
            logger.error("身份证Ocr识别成功失败具体信息: " + msg);
            throw new ServiceException(new ErrorCode(400, msg));
        }
        JSONObject data = jparse.getJSONObject("data");
        if (data.getStr("name").equals(name) && data.getStr("idNo").equals(idNo)) {

        } else {
            throw new ServiceException(SIGN_ID_CARD_TYPE);
        }
        return data;
    }

    /**
     * 营业执照OCR识别
     *
     * @param img    营业执照信息面图片BASE64字符串。
     * @param name   公司名称
     * @param certNo 社会信用号码
     * @return verifyId 业务Id为null失败
     * @author: 尉一民
     */
    public static LicenseVO license(String img, String name, String certNo) {
        int code = 0;
        String msg = "";
        JSONObject jspell = new JSONObject();
        jspell.put("img", FileUtils.getBase64(img));
        logger.info("============营业执照Ocr识别==========");
        String token = TokenHelper.getToken();
        String res = HttpHelper.sendPost(EqbConfig.license(), token, jspell.toString());
        JSONObject jparse = JsonUtils.parseObject(res, JSONObject.class);
        code = jparse.getInt("code");
        msg = jparse.getStr("message");
        if (code != 0) {
            logger.error("营业执照Ocr识别成功失败具体信息: " + msg);
            throw new ServiceException(new ErrorCode(400, msg));
        }
        JSONObject data = jparse.getJSONObject("data");
        if (data.getStr("name").equals(name) && data.getStr("certNo").equals(certNo)) {

        } else {
            throw new ServiceException(SIGN_LICENSE_TYPE);
        }
        String validTerm = data.getStr("validTerm");
        String scope = data.getStr("scope");
        String address = data.getStr("address");
        validTerm = validTerm.replace("年", ".");
        validTerm = validTerm.replace("月", ".");
        validTerm = validTerm.replace("日", ".");
        validTerm = validTerm.replace("至", "-");
        LicenseVO licenseVO = new LicenseVO();
        licenseVO.setScope(scope);
        licenseVO.setValidTerm(validTerm);
        licenseVO.setAddress(address);
        return licenseVO;
    }


    /**
     * 短信验证码校验
     *
     * @param flowId    流程ID
     * @param phoneCode 验证码
     * @return String
     * @throws Exception
     * @author: 尉一民
     */
    public static Boolean pinPer3keysTelecom(String flowId, String phoneCode) {
        logger.info("短信验证码校验参数flowId:{},phoneCode:{}", flowId, phoneCode);
        int code = 0;
        String msg = "";
        JSONObject jspell = new JSONObject();
        jspell.put("authcode", phoneCode);
        // 短信验证码校验
        String res = HttpHelper.sendPut(EqbConfig.putPinPer3keys_telecom(flowId), TokenHelper.getToken(), jspell.toString());
        JSONObject jparse = JsonUtils.parseObject(res, JSONObject.class);
        code = jparse.getInt("code");
        msg = jparse.getStr("message");
        if (code != 0) {
            logger.error("短信验证码校验成功失败具体信息: " + msg);
            throw new ServiceException(new ErrorCode(400, msg));
        }
        return Boolean.TRUE;
    }


    /**
     * 再次发送短信验证码
     *
     * @param flowId 流程ID
     * @return String
     * @throws Exception
     * @author: 尉一民
     */
    public static Boolean againPinPer3keysTelecom(String flowId) {
        logger.info("再次发送短信验证码参数flowId:{}", flowId);
        int code = 0;
        String msg = "";
        // 再次发送短信验证码
        String res = HttpHelper.sendPost(EqbConfig.againPutPinPer3keys_telecom(flowId), TokenHelper.getToken(), null);
        JSONObject jparse = JsonUtils.parseObject(res, JSONObject.class);
        code = jparse.getInt("code");
        msg = jparse.getStr("message");
        if (code != 0) {
            logger.error("短信验证码校验成功失败具体信息: " + msg);
            throw new ServiceException(new ErrorCode(400, msg));
        }
        return Boolean.TRUE;
    }
    public static String getFileDownloadUrl(String filePath) throws EsignDemoException {
        Gson gson = new Gson();
        EsignHttpResponse getUploadUrl = EqbFileUtils.getUploadUrl(filePath);
        JsonObject getUploadUrlJsonObject = gson.fromJson(getUploadUrl.getBody(), JsonObject.class);
        JsonObject data = getUploadUrlJsonObject.getAsJsonObject("data");
        // 文件id后续发起签署使用
        String fileId = data.get("fileId").getAsString();
        String fileUploadUrl = data.get("fileUploadUrl").getAsString();
        logger.info("获取文件id以及文件上传地址成功,文件id:{},上传链接:{}", fileId, fileUploadUrl);
        // 文件上传
        EsignHttpResponse uploadFileResponse = EqbFileUtils.uploadFile(fileUploadUrl, filePath);
        JsonObject uploadFileResponseJsonObject = gson.fromJson(uploadFileResponse.getBody(), JsonObject.class);
        int errCode = uploadFileResponseJsonObject.get("errCode").getAsInt();
        logger.info("文件上传成功,状态码:{}", errCode);
        int i = 0;
        String fileDownloadUrl = null;
        while (i < 3) {
            EsignHttpResponse fileStatus = EqbFileUtils.getFileStatus(fileId);
            JSONObject fileStatusJsonObject = JsonUtils.parseObject(fileStatus.getBody(), JSONObject.class);
            String status = fileStatusJsonObject.getJSONObject("data").getStr("fileStatus");
            logger.info(String.format("查询文件状态执行第%s次", i + 1));
            if ("2".equalsIgnoreCase(status) || "5".equalsIgnoreCase(status)) {// 查询状态为2或者5代表文件准备完成
                System.out.println("文件准备完成");
                fileDownloadUrl = fileStatusJsonObject.getJSONObject("data").getStr("fileDownloadUrl");
                break;
            }
            System.out.println("文件未准备完成,等待两秒重新查询");
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            i++;
        }
        return fileDownloadUrl;
    }

    public static String signPrivacyPolicy(String filePath,
                                           String notifyUrl,
                                           String redirectUrl,
                                           FileSignBo fileSignBo,
                                           FileSignBo fileSignBoPsn,
                                           List<SignFieldPosition> signFieldPositionList,
                                           Integer type) throws EsignDemoException {
        // 合同签署
        Gson gson = new Gson();
        EsignHttpResponse getUploadUrl = EqbFileUtils.getUploadUrl(filePath);
        JsonObject getUploadUrlJsonObject = gson.fromJson(getUploadUrl.getBody(), JsonObject.class);
        JsonObject data = getUploadUrlJsonObject.getAsJsonObject("data");
        // 文件id后续发起签署使用
        String fileId = data.get("fileId").getAsString();
        String fileUploadUrl = data.get("fileUploadUrl").getAsString();
        fileSignBo.setFileId(fileId);
        logger.info("获取文件id以及文件上传地址成功,文件id:{},上传链接:{}", fileId, fileUploadUrl);
        // 文件上传
        EsignHttpResponse uploadFileResponse = EqbFileUtils.uploadFile(fileUploadUrl, filePath);
        JsonObject uploadFileResponseJsonObject = gson.fromJson(uploadFileResponse.getBody(), JsonObject.class);
        int errCode = uploadFileResponseJsonObject.get("errCode").getAsInt();
        logger.info("文件上传成功,状态码:{}", errCode);
        // 文件上传成功后文件会有一个异步处理过程,建议轮询文件状态,正常后发起签署
        // 查询文件上传状态
        int i = 0;
        while (i < 3) {
            EsignHttpResponse fileStatus = EqbFileUtils.getFileStatus(fileId);
            JSONObject fileStatusJsonObject = JsonUtils.parseObject(fileStatus.getBody(), JSONObject.class);
            String status = fileStatusJsonObject.getJSONObject("data").getStr("fileStatus");
            logger.info(String.format("查询文件状态执行第%s次", i + 1));
            if ("2".equalsIgnoreCase(status) || "5".equalsIgnoreCase(status)) {// 查询状态为2或者5代表文件准备完成
                System.out.println("文件准备完成");
                break;
            }
            System.out.println("文件未准备完成,等待两秒重新查询");
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            i++;
        }
        logger.info("发起签署参数Json:{}", JsonUtils.toJsonString(fileSignBo));
        String apiaddr = "/v3/sign-flow/create-by-file";
        // 请求参数body体,json格式。get或者delete请求时jsonString传空json:"{}"或者null
        FileSign fileSign = new FileSign();
        // 设置待签署文件信息
        Docs build = Docs.build(fileId, fileSignBo.getFileName());
        ArrayList<Docs> docsList = Lists.newArrayList();
        docsList.add(build);
        fileSign.setDocs(docsList);
        // 签署流程配置项
        SignFlowConfig signFlowConfig = SignFlowConfig.build(fileSignBo.getSignFlowTitle(), notifyUrl, redirectUrl);
        fileSign.setSignFlowConfig(signFlowConfig);
        // 签署方信息
        List<Signers> signersList = Lists.newArrayList();
        fileSignBoPsn.setFileId(fileId);
        //企业类型(1 - 个人工商户,2 - 企业)
        if (type == 1) {

            for (int j = 0; j < signFieldPositionList.size(); j++) {
                SignFieldPosition signFieldPosition = signFieldPositionList.get(j);
                if (j != 3 && j != 5) {
                    //个人工商户 法人签署位置
                    signersList.add(Signers.build(fileSignBoPsn, 1, signFieldPosition));
                } else {
                    signersList.add(Signers.build(fileSignBo, 1, signFieldPosition));
                }
            }
        } else if (type == 2) {

            for (int j = 0; j < signFieldPositionList.size(); j++) {
                SignFieldPosition signFieldPosition = signFieldPositionList.get(j);
                if (j == signFieldPositionList.size() - 1 || j == 0 || j == signFieldPositionList.size() - 3) {
                    //企业 法人签署位置
                    signersList.add(Signers.build(fileSignBoPsn, 1, signFieldPosition));
                } else {
                    signersList.add(Signers.build(fileSignBo, 1, signFieldPosition));
                }
            }
        }

        fileSign.setSigners(signersList);
        String jsonParm = JSONUtil.toJsonStr(fileSign);
        // 请求方法
        EsignRequestType requestType = EsignRequestType.POST;
        // 生成请求签名鉴权方式的Header
        Map<String, String> header = EsignHttpHelper.signAndBuildSignAndJsonHeader(APPID, SECRET, jsonParm, requestType.name(), apiaddr, true);
        // 发起接口请求
        EsignHttpResponse esignHttpResponse = EsignHttpHelper.doCommHttp(ESIGN_HOST, apiaddr, requestType, jsonParm, header, true);
        JSONObject entries = JsonUtils.parseObject(esignHttpResponse.getBody(), JSONObject.class);
        String str = entries.getJSONObject("data").getStr("signFlowId");
        return str;
    }

    /**
     * 根据位置签署
     *
     * @param filePath
     * @param notifyUrl
     * @param redirectUrl
     * @param fileSignBo
     * @param keyPosition
     * @return
     * @throws Exception
     */
    public static String fileSignWithPosition(String filePath,
                                              String notifyUrl,
                                              String redirectUrl,
                                              FileSignBo fileSignBo,
                                              String keyPosition) throws Exception {
        // 合同签署
        Gson gson = new Gson();
        EsignHttpResponse getUploadUrl = EqbFileUtils.getUploadUrl(filePath);
        JsonObject getUploadUrlJsonObject = gson.fromJson(getUploadUrl.getBody(), JsonObject.class);
        JsonObject data = getUploadUrlJsonObject.getAsJsonObject("data");
        // 文件id后续发起签署使用
        String fileId = data.get("fileId").getAsString();
        String fileUploadUrl = data.get("fileUploadUrl").getAsString();
        fileSignBo.setFileId(fileId);
        logger.info("获取文件id以及文件上传地址成功,文件id:{},上传链接:{}", fileId, fileUploadUrl);
        // 文件上传
        EsignHttpResponse uploadFileResponse = EqbFileUtils.uploadFile(fileUploadUrl, filePath);
        JsonObject uploadFileResponseJsonObject = gson.fromJson(uploadFileResponse.getBody(), JsonObject.class);
        int errCode = uploadFileResponseJsonObject.get("errCode").getAsInt();
        logger.info("文件上传成功,状态码:{}", errCode);
        // 文件上传成功后文件会有一个异步处理过程,建议轮询文件状态,正常后发起签署
        // 查询文件上传状态
        int i = 0;
        while (i < 3) {
            EsignHttpResponse fileStatus = EqbFileUtils.getFileStatus(fileId);
            JSONObject fileStatusJsonObject = JsonUtils.parseObject(fileStatus.getBody(), JSONObject.class);
            String status = fileStatusJsonObject.getJSONObject("data").getStr("fileStatus");
            logger.info(String.format("查询文件状态执行第%s次", i + 1));
            if ("2".equalsIgnoreCase(status) || "5".equalsIgnoreCase(status)) {// 查询状态为2或者5代表文件准备完成
                System.out.println("文件准备完成");
                break;
            }
            System.out.println("文件未准备完成,等待两秒重新查询");
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            i++;
        }
        logger.info("发起签署参数Json:{}", JsonUtils.toJsonString(fileSignBo));
        String apiaddr = "/v3/sign-flow/create-by-file";
        // 请求参数body体,json格式。get或者delete请求时jsonString传空json:"{}"或者null
        FileSign fileSign = new FileSign();
        // 设置待签署文件信息
        Docs build = Docs.build(fileSignBo.getFileId(), fileSignBo.getFileName());
        ArrayList<Docs> docsList = Lists.newArrayList();
        docsList.add(build);
        fileSign.setDocs(docsList);

        // 签署流程配置项
        SignFlowConfig signFlowConfig = SignFlowConfig.build(fileSignBo.getSignFlowTitle(), notifyUrl, redirectUrl);
        fileSign.setSignFlowConfig(signFlowConfig);
        List<SignFieldPosition> signFieldPositionList = new ArrayList<>();
        // 文件id后续发起签署使用
        String positions = keywordPositions(fileId, keyPosition);
        ObjectMapper objectMapper = new ObjectMapper();
        List<KeywordPositions> keywordPositions = objectMapper.readValue(positions, new TypeReference<List<KeywordPositions>>() {
        });
        for (KeywordPositions keywordPosition : keywordPositions) {

            System.out.println("Keyword: " + keywordPosition.getKeyword());
            System.out.println("Search Result: " + keywordPosition.getSearchResult());

            for (Positions position : keywordPosition.getPositions()) {
                System.out.println("PageNum: " + position.getPageNum());
                for (Coordinate coordinate : position.getCoordinates()) {
                    System.out.println("PositionX: " + coordinate.getPositionX() + ", PositionY: " + coordinate.getPositionY());
                    Float xPosition = coordinate.getPositionX() + 100;
                    SignFieldPosition signFieldPosition = SignFieldPosition.build(String.valueOf(position.getPageNum()), xPosition, coordinate.getPositionY());
                    signFieldPositionList.add(signFieldPosition);
                }
            }
        }

        // 签署方信息
        List<Signers> signersList = Lists.newArrayList();
        for (SignFieldPosition signFieldPosition : signFieldPositionList) {
            signersList.add(Signers.build(fileSignBo, 1, signFieldPosition));
        }
        signersList.add(Signers.build(fileSignBo, 2, SignFieldPosition.build("3", SignPositionEnum.POSITION_X.getPosition(), SignPositionEnum.POSITION_Y.getPosition())));
        fileSign.setSigners(signersList);

        String jsonParm = JSONUtil.toJsonStr(fileSign);
        // 请求方法
        EsignRequestType requestType = EsignRequestType.POST;
        // 生成请求签名鉴权方式的Header
        Map<String, String> header = EsignHttpHelper.signAndBuildSignAndJsonHeader(APPID, SECRET, jsonParm, requestType.name(), apiaddr, true);
        // 发起接口请求
        EsignHttpResponse esignHttpResponse = EsignHttpHelper.doCommHttp(ESIGN_HOST, apiaddr, requestType, jsonParm, header, true);
        JSONObject entries = JsonUtils.parseObject(esignHttpResponse.getBody(), JSONObject.class);
        return entries.getJSONObject("data").getStr("signFlowId");
    }

    /**
     * 我方静默签
     *
     * @param orgId
     * @param assignedSealId
     * @param filePath
     * @param notifyUrl
     * @param redirectUrl
     * @param fileSignBo
     * @param keyPosition
     * @return
     * @throws Exception
     */
    public static String fileSignWithAssignedSealId(String orgId,
                                                    String assignedSealId,
                                                    String filePath,
                                                    String notifyUrl,
                                                    String redirectUrl,
                                                    FileSignBo fileSignBo,
                                                    String keyPosition) throws Exception {
        // 合同签署
        Gson gson = new Gson();
        EsignHttpResponse getUploadUrl = EqbFileUtils.getUploadUrl(filePath);
        JsonObject getUploadUrlJsonObject = gson.fromJson(getUploadUrl.getBody(), JsonObject.class);
        JsonObject data = getUploadUrlJsonObject.getAsJsonObject("data");
        // 文件id后续发起签署使用
        String fileId = data.get("fileId").getAsString();
        String fileUploadUrl = data.get("fileUploadUrl").getAsString();
        fileSignBo.setFileId(fileId);
        logger.info("获取文件id以及文件上传地址成功,文件id:{},上传链接:{}", fileId, fileUploadUrl);
        // 文件上传
        EsignHttpResponse uploadFileResponse = EqbFileUtils.uploadFile(fileUploadUrl, filePath);
        JsonObject uploadFileResponseJsonObject = gson.fromJson(uploadFileResponse.getBody(), JsonObject.class);
        int errCode = uploadFileResponseJsonObject.get("errCode").getAsInt();
        logger.info("文件上传成功,状态码:{}", errCode);
        // 文件上传成功后文件会有一个异步处理过程,建议轮询文件状态,正常后发起签署
        // 查询文件上传状态
        int i = 0;
        while (i < 3) {
            EsignHttpResponse fileStatus = EqbFileUtils.getFileStatus(fileId);
            JSONObject fileStatusJsonObject = JsonUtils.parseObject(fileStatus.getBody(), JSONObject.class);
            String status = fileStatusJsonObject.getJSONObject("data").getStr("fileStatus");
            logger.info(String.format("查询文件状态执行第%s次", i + 1));
            if ("2".equalsIgnoreCase(status) || "5".equalsIgnoreCase(status)) {// 查询状态为2或者5代表文件准备完成
                System.out.println("文件准备完成");
                break;
            }
            System.out.println("文件未准备完成,等待两秒重新查询");
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            i++;
        }
        logger.info("发起签署参数Json:{}", JsonUtils.toJsonString(fileSignBo));
        String apiaddr = "/v3/sign-flow/create-by-file";
        // 请求参数body体,json格式。get或者delete请求时jsonString传空json:"{}"或者null
        FileSign fileSign = new FileSign();
        // 设置待签署文件信息
        Docs build = Docs.build(fileSignBo.getFileId(), fileSignBo.getFileName());
        ArrayList<Docs> docsList = Lists.newArrayList();
        docsList.add(build);
        fileSign.setDocs(docsList);

        // 签署流程配置项
        SignFlowConfig signFlowConfig = SignFlowConfig.build(fileSignBo.getSignFlowTitle(), notifyUrl, redirectUrl);
        fileSign.setSignFlowConfig(signFlowConfig);
        List<SignFieldPosition> signFieldPositionList = new ArrayList<>();
        // 文件id后续发起签署使用
        String s = keywordPositions(fileId, keyPosition);
        ObjectMapper objectMapper = new ObjectMapper();
        List<KeywordPositions> keywordPositions = objectMapper.readValue(s, new TypeReference<List<KeywordPositions>>() {
        });
        for (KeywordPositions keywordPosition : keywordPositions) {

            System.out.println("Keyword: " + keywordPosition.getKeyword());
            System.out.println("Search Result: " + keywordPosition.getSearchResult());

            for (Positions position : keywordPosition.getPositions()) {
                System.out.println("PageNum: " + position.getPageNum());
                for (Coordinate coordinate : position.getCoordinates()) {
                    System.out.println("PositionX: " + coordinate.getPositionX() + ", PositionY: " + coordinate.getPositionY());
                    SignFieldPosition signFieldPosition = SignFieldPosition.build(String.valueOf(position.getPageNum()), coordinate.getPositionX() + 100, coordinate.getPositionY());
                    signFieldPositionList.add(signFieldPosition);
                }
            }
        }

        // 签署方信息
        List<Signers> signersList = Lists.newArrayList();
        for (SignFieldPosition signFieldPosition : signFieldPositionList) {
            signersList.add(Signers.build(orgId, assignedSealId, fileSignBo, 1, signFieldPosition));
        }
        fileSign.setSigners(signersList);
        String jsonParm = JSONUtil.toJsonStr(fileSign);
        // 请求方法
        EsignRequestType requestType = EsignRequestType.POST;
        // 生成请求签名鉴权方式的Header
        Map<String, String> header = EsignHttpHelper.signAndBuildSignAndJsonHeader(APPID, SECRET, jsonParm, requestType.name(), apiaddr, true);
        // 发起接口请求
        EsignHttpResponse esignHttpResponse = EsignHttpHelper.doCommHttp(ESIGN_HOST, apiaddr, requestType, jsonParm, header, true);
        JSONObject entries = JsonUtils.parseObject(esignHttpResponse.getBody(), JSONObject.class);
        return entries.getJSONObject("data").getStr("signFlowId");
    }

    public static String silentlySignPrivacyPolicy(String orgId,
                                                   String assignedSealId,
                                                   String filePath,
                                                   String notifyUrl,
                                                   String redirectUrl,
                                                   FileSignBo fileSignBo,
                                                   List<SignFieldPosition> signFieldPositionList) throws Exception {
        // 合同签署
        Gson gson = new Gson();
        EsignHttpResponse getUploadUrl = EqbFileUtils.getUploadUrl(filePath);
        JsonObject getUploadUrlJsonObject = gson.fromJson(getUploadUrl.getBody(), JsonObject.class);
        JsonObject data = getUploadUrlJsonObject.getAsJsonObject("data");
        // 文件id后续发起签署使用
        String fileId = data.get("fileId").getAsString();
        String fileUploadUrl = data.get("fileUploadUrl").getAsString();
        fileSignBo.setFileId(fileId);
        logger.info("获取文件id以及文件上传地址成功,文件id:{},上传链接:{}", fileId, fileUploadUrl);
        // 文件上传
        EsignHttpResponse uploadFileResponse = EqbFileUtils.uploadFile(fileUploadUrl, filePath);
        JsonObject uploadFileResponseJsonObject = gson.fromJson(uploadFileResponse.getBody(), JsonObject.class);
        int errCode = uploadFileResponseJsonObject.get("errCode").getAsInt();
        logger.info("文件上传成功,状态码:{}", errCode);
        // 文件上传成功后文件会有一个异步处理过程,建议轮询文件状态,正常后发起签署
        // 查询文件上传状态
        int i = 0;
        while (i < 3) {
            EsignHttpResponse fileStatus = EqbFileUtils.getFileStatus(fileId);
            JSONObject fileStatusJsonObject = JsonUtils.parseObject(fileStatus.getBody(), JSONObject.class);
            String status = fileStatusJsonObject.getJSONObject("data").getStr("fileStatus");
            logger.info(String.format("查询文件状态执行第%s次", i + 1));
            if ("2".equalsIgnoreCase(status) || "5".equalsIgnoreCase(status)) {// 查询状态为2或者5代表文件准备完成
                System.out.println("文件准备完成");
                break;
            }
            System.out.println("文件未准备完成,等待两秒重新查询");
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            i++;
        }
        logger.info("发起签署参数Json:{}", JsonUtils.toJsonString(fileSignBo));
        String apiaddr = "/v3/sign-flow/create-by-file";
        // 请求参数body体,json格式。get或者delete请求时jsonString传空json:"{}"或者null
        FileSign fileSign = new FileSign();
        // 设置待签署文件信息
        Docs build = Docs.build(fileSignBo.getFileId(), fileSignBo.getFileName());
        ArrayList<Docs> docsList = Lists.newArrayList();
        docsList.add(build);
        fileSign.setDocs(docsList);

        // 签署流程配置项
        SignFlowConfig signFlowConfig = SignFlowConfig.build(fileSignBo.getSignFlowTitle(), notifyUrl, redirectUrl);
        fileSign.setSignFlowConfig(signFlowConfig);
        // 签署方信息
        List<Signers> signersList = Lists.newArrayList();
        for (SignFieldPosition signFieldPosition : signFieldPositionList) {
            signersList.add(Signers.build(orgId, assignedSealId, fileSignBo, 1, signFieldPosition));
        }
        fileSign.setSigners(signersList);
        String jsonParm = JSONUtil.toJsonStr(fileSign);
        // 请求方法
        EsignRequestType requestType = EsignRequestType.POST;
        // 生成请求签名鉴权方式的Header
        Map<String, String> header = EsignHttpHelper.signAndBuildSignAndJsonHeader(APPID, SECRET, jsonParm, requestType.name(), apiaddr, true);
        // 发起接口请求
        EsignHttpResponse esignHttpResponse = EsignHttpHelper.doCommHttp(ESIGN_HOST, apiaddr, requestType, jsonParm, header, true);
        JSONObject entries = JsonUtils.parseObject(esignHttpResponse.getBody(), JSONObject.class);
        return entries.getJSONObject("data").getStr("signFlowId");
    }

    public static String silentlySignPrivacyPolicy(String assignedSealId,
                                                   String filePath,
                                                   String notifyUrl,
                                                   String redirectUrl,
                                                   FileSignBo fileSignBo,
                                                   List<SignFieldPosition> signFieldPositionList) throws Exception {
        // 合同签署
        Gson gson = new Gson();
        EsignHttpResponse getUploadUrl = EqbFileUtils.getUploadUrl(filePath);
        JsonObject getUploadUrlJsonObject = gson.fromJson(getUploadUrl.getBody(), JsonObject.class);
        JsonObject data = getUploadUrlJsonObject.getAsJsonObject("data");
        // 文件id后续发起签署使用
        String fileId = data.get("fileId").getAsString();
        String fileUploadUrl = data.get("fileUploadUrl").getAsString();
        fileSignBo.setFileId(fileId);
        logger.info("获取文件id以及文件上传地址成功,文件id:{},上传链接:{}", fileId, fileUploadUrl);
        // 文件上传
        EsignHttpResponse uploadFileResponse = EqbFileUtils.uploadFile(fileUploadUrl, filePath);
        JsonObject uploadFileResponseJsonObject = gson.fromJson(uploadFileResponse.getBody(), JsonObject.class);
        int errCode = uploadFileResponseJsonObject.get("errCode").getAsInt();
        logger.info("文件上传成功,状态码:{}", errCode);
        // 文件上传成功后文件会有一个异步处理过程,建议轮询文件状态,正常后发起签署
        // 查询文件上传状态
        int i = 0;
        while (i < 3) {
            EsignHttpResponse fileStatus = EqbFileUtils.getFileStatus(fileId);
            JSONObject fileStatusJsonObject = JsonUtils.parseObject(fileStatus.getBody(), JSONObject.class);
            String status = fileStatusJsonObject.getJSONObject("data").getStr("fileStatus");
            logger.info(String.format("查询文件状态执行第%s次", i + 1));
            if ("2".equalsIgnoreCase(status) || "5".equalsIgnoreCase(status)) {// 查询状态为2或者5代表文件准备完成
                System.out.println("文件准备完成");
                break;
            }
            System.out.println("文件未准备完成,等待两秒重新查询");
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            i++;
        }
        logger.info("发起签署参数Json:{}", JsonUtils.toJsonString(fileSignBo));
        String apiaddr = "/v3/sign-flow/create-by-file";
        // 请求参数body体,json格式。get或者delete请求时jsonString传空json:"{}"或者null
        FileSign fileSign = new FileSign();
        // 设置待签署文件信息
        Docs build = Docs.build(fileSignBo.getFileId(), fileSignBo.getFileName());
        ArrayList<Docs> docsList = Lists.newArrayList();
        docsList.add(build);
        fileSign.setDocs(docsList);

        // 签署流程配置项
        SignFlowConfig signFlowConfig = SignFlowConfig.build(fileSignBo.getSignFlowTitle(), notifyUrl, redirectUrl);
        fileSign.setSignFlowConfig(signFlowConfig);
        // 签署方信息
        List<Signers> signersList = Lists.newArrayList();
        for (SignFieldPosition signFieldPosition : signFieldPositionList) {
            signersList.add(Signers.build(assignedSealId, fileSignBo, 1, signFieldPosition));
        }
        fileSign.setSigners(signersList);
        String jsonParm = JSONUtil.toJsonStr(fileSign);
        // 请求方法
        EsignRequestType requestType = EsignRequestType.POST;
        // 生成请求签名鉴权方式的Header
        Map<String, String> header = EsignHttpHelper.signAndBuildSignAndJsonHeader(APPID, SECRET, jsonParm, requestType.name(), apiaddr, true);
        // 发起接口请求
        EsignHttpResponse esignHttpResponse = EsignHttpHelper.doCommHttp(ESIGN_HOST, apiaddr, requestType, jsonParm, header, true);
        JSONObject entries = JsonUtils.parseObject(esignHttpResponse.getBody(), JSONObject.class);
        return entries.getJSONObject("data").getStr("signFlowId");
    }

    /**
     * 根据关键字获取签章位置信息
     *
     * @param fileId      文件id
     * @param keyPosition 关键字
     * @return 位置信息
     * @throws EsignDemoException
     */
    public static String keywordPositions(String fileId, String keyPosition) throws EsignDemoException {
        // 获取请求url
        String apiaddr = "/v3/files/" + fileId + "/keyword-positions";
        // 请求方法
        EsignRequestType requestType = EsignRequestType.POST;
        // 生成请求签名鉴权方式的Header
        Map<String, String> header = EsignHttpHelper.signAndBuildSignAndJsonHeader(APPID, SECRET, keyPosition, requestType.name(), apiaddr, true);
        ///发起接口请求
        EsignHttpResponse esignHttpResponse = EsignHttpHelper.doCommHttp(ESIGN_HOST, apiaddr, requestType, keyPosition, header, true);
        JSONObject entries = JsonUtils.parseObject(esignHttpResponse.getBody(), JSONObject.class);
        return entries.getJSONObject("data").getStr("keywordPositions");
    }

    /**
     * 开启签署流程
     *
     * @param signFlowId 签署流程ID
     * @return
     * @author: 尉一民
     */
    public static Boolean signFlowStart(String signFlowId) throws EsignDemoException {
        String apiaddr = "/v3/sign-flow/" + signFlowId + "/start";
        // 请求参数body体,json格式。get或者delete请求时jsonString传空json:"{}"或者null
        String jsonParm = null;
        // 请求方法
        EsignRequestType requestType = EsignRequestType.POST;
        // 生成签名鉴权方式的的header
        Map<String, String> header = EsignHttpHelper.signAndBuildSignAndJsonHeader(APPID, SECRET, jsonParm, requestType.name(), apiaddr, true);
        // 发起接口请求
        EsignHttpResponse signFlowStart = EsignHttpHelper.doCommHttp(ESIGN_HOST, apiaddr, requestType, jsonParm, header, true);
        JSONObject jsonObject = JsonUtils.parseObject(signFlowStart.getBody(), JSONObject.class);
        int code = jsonObject.getInt("code");
        String msg = jsonObject.getStr("message");
        if (code != 0) {
            logger.error("开启签署流程成功失败具体信息: " + msg);
            return Boolean.FALSE;
        }
        return Boolean.TRUE;
    }

    /**
     * 下载已签署文件及附属材料
     *
     * @return String
     * @throws EsignDemoException
     * @author: 尉一民
     */
    public static String fileDownloadUrl(String signFlowId) throws EsignDemoException {
        String downloadUrl = "";
        String apiaddr = "/v3/sign-flow/" + signFlowId + "/file-download-url";
        // 请求参数body体,json格式。get或者delete请求时jsonString传空json:"{}"或者null
        String jsonParm = null;
        // 请求方法
        EsignRequestType requestType = EsignRequestType.GET;
        // 生成签名鉴权方式的的header
        Map<String, String> header = EsignHttpHelper.signAndBuildSignAndJsonHeader(APPID, SECRET, jsonParm, requestType.name(), apiaddr, true);
        // 发起接口请求
        EsignHttpResponse esignHttpResponse = EsignHttpHelper.doCommHttp(ESIGN_HOST, apiaddr, requestType, jsonParm, header, true);
        JSONObject jsonObject = JsonUtils.parseObject(esignHttpResponse.getBody(), JSONObject.class);
        int code = jsonObject.getInt("code");
        String msg = jsonObject.getStr("message");
        if (code != 0) {
            logger.error("下载已签署文件及附属材料成功失败具体信息: " + msg);
            return downloadUrl;
        }
        JSONObject data = jsonObject.getJSONObject("data");
        JSONArray files = data.getJSONArray("files");
        for (int i = 0; i < files.size(); i++) {
            downloadUrl = files.getJSONObject(i).getStr("downloadUrl");
        }
        return downloadUrl;
    }
}