Jenkins CLI二次开发工具类

使用Jenkins CLI进行二次开发

使用背景

复制代码
公司自研CI/DI平台,借助Jenkins+SonarQube进行代码质量管理。

对接版本

复制代码
Jenkins版本为:Version 2.428
SonarQube版本为:Community EditionVersion 10.2.1 (build 78527)

技术选型

复制代码
Java对接Jenkins有第三方组件,比如jenkins-rest、jenkins-client,但是考虑到第三方组件会引入其他jar包,而且会存在漏洞问题。
到时候升级组件时可能会和项目框架本身使用的第三方jar起冲突。因此,使用jenkins-cli来实现自己的需求。

注意:这里不是单纯的使用java -jar jenkins-cli.jar -http xxxx来实现接口调用,
而且提取并修改jenkins-cli.jar中的源码来达到自身需求开发的目的。
比如创建View时,使用jenkins-cli.jar时需要传入xml内容(标准输入流),
所以我们进行了改造,可以支持传入byte数组的形式,使用体验更符合大众。

jenkins-cli.jar的源码修改

java 复制代码
package com.infosec.autobuild.util;

import com.cdancy.jenkins.rest.JenkinsClient;
import com.cdancy.jenkins.rest.domain.job.BuildInfo;
import com.cdancy.jenkins.rest.domain.queue.QueueItem;
import com.infosec.autobuild.dto.*;
import com.infosec.autobuild.dto.jenkins.BuildInfoDto;
import com.infosec.autobuild.dto.jenkins.CredentialDto;
import com.infosec.autobuild.dto.jenkins.JobDto;
import com.infosec.autobuild.dto.jenkins.ViewDto;
import com.infosec.autobuild.hudson.cli.CLI;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.AuthCache;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.impl.client.BasicAuthCache;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * Jenkins cli工具类
 */
@Slf4j
public class JenkinsUtil {

    private static final String PROTOCOL_HTTP = "-http";
    private static final String PROTOCOL_WEB_SOCKET = "-webSocket";
    /**
     * 结束符:\r\n
     */
    private static final String END_SYMBOL = "\\r\\n";
    /**
     * 换行符:\n
     */
    private static final String LINE_BREAK_SYMBOL = "\\n";

    /**
     * Jenkins 凭证相关操作(暂不包括domain相关操作)
     */
    public static class Credentials {
        /**
         * system::system::jenkins等同于SystemCredentialsProvider::SystemContextResolver::jenkins
         * Provider可以通过java -jar jenkins-cli.jar -auth admin:admin -s http://xxx:8080/ -http list-credentials-providers获取
         * Resolver可以通过java -jar jenkins-cli.jar -auth admin:admin -s http://xxx:8080/ -http list-credentials-context-resolvers获取
         */
        private static final String SYSTEM_STORE_ID = "system::system::jenkins";
        /**
         * 默认全局domain
         */
        private static final String GLOBAL_DOMAIN = "(global)";

        private static final String CREDENTIAL_NOT_FOUND = "No such credential";

        enum Operation {
            /**
             * 查询Jenkins Credentials集合:list-credentials
             */
            LIST_CREDENTIALS("list-credentials", "查询Jenkins Credentials集合"),
            /**
             * 查询Jenkins Credentials集合,返回xml:list-credentials-as-xml
             */
            LIST_CREDENTIALS_AS_XML("list-credentials-as-xml", "查询Jenkins Credentials集合,返回xml"),
            /**
             * 创建Jenkins Credentials:create-credentials-by-xml
             */
            CREATE_CREDENTIALS("create-credentials-by-xml", "创建Jenkins Credentials"),
            /**
             * 更新Jenkins Credentials:create-credentials-by-xml
             */
            UPDATE_CREDENTIALS("update-credentials-by-xml", "更新Jenkins Credentials"),
            /**
             * 删除Jenkins Credentials:delete-credentials
             */
            DELETE_CREDENTIALS("delete-credentials", "删除Jenkins Credentials"),
            /**
             * 查询Jenkins Credentials:get-credentials-as-xml
             */
            GET_CREDENTIALS("get-credentials-as-xml", "查询Jenkins Credentials"),

            ;
            @Setter
            @Getter
            private String op;
            @Setter
            @Getter
            private String desc;

            Operation(String op, String desc) {
                this.setOp(op);
                this.setDesc(desc);
            }
        }

        /**
         * 创建Jenkins 凭证(凭证id为空时,默认使用36位UUID)
         *
         * @param host          Jenkins地址,比如:http://10.100.57.156:8080
         * @param auth          Jenkins登录用户名:密码,比如:admin:admin
         * @param credentialDto 凭证对象
         * @return ResultDto
         */
        public static ResultDto createCredential(String host, String auth, CredentialDto credentialDto) {
            if (!StringUtils.hasText(credentialDto.getId())) {
                credentialDto.setId(UUID.randomUUID().toString());
            }
            String xml = CredentialDto.parseDto2Xml(credentialDto);
            CLI cli = doWork(host, auth, new String[]{Operation.CREATE_CREDENTIALS.op, SYSTEM_STORE_ID, ""}, PROTOCOL_HTTP, xml);
            int code = cli.code;
            String msg = cli.msg;
            return ResultDto.SUCCESS.equals(String.valueOf(code)) ?
                    ResultDto.buildSuccessDto() : ResultDto.buildErrorDto().msg(msg);
        }

        /**
         * 删除Jenkins 凭证
         *
         * @param host         Jenkins地址,比如:http://10.100.57.156:8080
         * @param auth         Jenkins登录用户名:密码,比如:admin:admin
         * @param credentialId 凭证id
         * @return ResultDto
         */
        public static ResultDto deleteCredential(String host, String auth, String credentialId) {
            CLI cli = doWork(host, auth,
                    new String[]{Operation.DELETE_CREDENTIALS.op, SYSTEM_STORE_ID, "", credentialId},
                    PROTOCOL_HTTP, null);
            int code = cli.code;
            String msg = cli.msg;
            if (StringUtils.hasText(msg) && msg.contains(CREDENTIAL_NOT_FOUND)) {
                return ResultDto.buildSuccessDto();
            }
            return ResultDto.SUCCESS.equals(String.valueOf(code)) ?
                    ResultDto.buildSuccessDto() : ResultDto.buildErrorDto().msg(msg);
        }

        /**
         * 更新Jenkins 凭证(凭证id无法修改)
         *
         * @param host          Jenkins地址,比如:http://10.100.57.156:8080
         * @param auth          Jenkins登录用户名:密码,比如:admin:admin
         * @param credentialDto 凭证对象
         * @return ResultDto
         */
        public static ResultDto updateCredential(String host, String auth, CredentialDto credentialDto) {
            if (!StringUtils.hasText(credentialDto.getId())) {
                return ResultDto.buildErrorDto().msg("凭证id不能为空");
            }
            String xml = CredentialDto.parseDto2Xml(credentialDto);
            CLI cli = doWork(host, auth, new String[]{Operation.UPDATE_CREDENTIALS.op, SYSTEM_STORE_ID,
                    GLOBAL_DOMAIN, credentialDto.getId()}, PROTOCOL_HTTP, xml);
            int code = cli.code;
            String msg = cli.msg;
            if (StringUtils.hasText(msg) && msg.contains(CREDENTIAL_NOT_FOUND)) {
                msg = "根据凭证id未找到对应记录";
                return ResultDto.buildErrorDto().msg(msg);
            }
            return ResultDto.SUCCESS.equals(String.valueOf(code)) ?
                    ResultDto.buildSuccessDto() : ResultDto.buildErrorDto().msg(msg);
        }

        /**
         * 查询Jenkins 凭证
         *
         * @param host         Jenkins地址,比如:http://10.100.57.156:8080
         * @param auth         Jenkins登录用户名:密码,比如:admin:admin
         * @param credentialId 凭证id
         * @return ResultDto
         */
        public static ResultDto<CredentialDto> getCredential(String host, String auth, String credentialId) {
            CLI cli = doWork(host, auth,
                    new String[]{Operation.GET_CREDENTIALS.op, SYSTEM_STORE_ID, "", credentialId},
                    PROTOCOL_HTTP, null);
            int code = cli.code;
            String msg = cli.msg;
            if (StringUtils.hasText(msg) && msg.contains(CREDENTIAL_NOT_FOUND)) {
                msg = "根据凭证id未找到对应记录";
                return ResultDto.buildErrorDto().msg(msg);
            }
            boolean ifSuccess = ResultDto.SUCCESS.equals(String.valueOf(code));
            CredentialDto credentialDto = new CredentialDto();
            if (ifSuccess) {
                if (StringUtils.hasText(msg)) {
                    CredentialDto.parseXmlStr2Dto(credentialDto, msg, null);
                }
            }
            return ifSuccess ? ResultDto.buildSuccess(credentialDto) : ResultDto.buildError(credentialDto).msg(msg);
        }

        /**
         * 查询Jenkins上的凭证列表
         *
         * @param host Jenkins地址,比如:http://10.100.57.156:8080
         * @param auth Jenkins登录用户名:密码,比如:admin:admin
         * @return ResultDto
         */
        public static ResultDto<List<CredentialDto>> listCredentials(String host, String auth) {
            CLI cli = doWork(host, auth, new String[]{Operation.LIST_CREDENTIALS_AS_XML.op, SYSTEM_STORE_ID},
                    PROTOCOL_HTTP, null);
            int code = cli.code;
            String msg = cli.msg;
            List<CredentialDto> credentialDtoList = new ArrayList<>(10);
            boolean ifSuccess = ResultDto.SUCCESS.equals(String.valueOf(code));
            if (ifSuccess) {
                CredentialDto.parseXmlStr2List(credentialDtoList, msg);
            }
            return ifSuccess ? ResultDto.buildSuccess(credentialDtoList) : ResultDto.buildError(credentialDtoList).msg(msg);
        }

        /**
         * 查询Jenkins上的凭证列表
         *
         * @param ip       Jenkins服务IP
         * @param port     Jenkins服务端口
         * @param username Jenkins服务登录用户名
         * @param password Jenkins服务登录密码
         * @return ResultDto
         */
        public static ResultDto listCredentials(String ip, String port, String username, String password) {
            String host = "http://" + ip + ":" + port;
            String auth = username + ":" + password;
            return listCredentials(host, auth);
        }
    }

    /**
     * Jenkins Job相关操作(即Item)
     */
    public static class Jobs {

        private static String JOB_BUILD_DETAIL_URL = "@host/job/@jobName/@buildId/api/json";

        private static String QUEUE_LIST_URL = "@host/job/@jobName/@buildId/api/json";

        enum Operation {
            /**
             * 创建Jenkins Job
             */
            CREATE("create-job", "创建Jenkins Job"),
            /**
             * 复制Jenkins Job
             */
            COPY("copy-job", "复制Jenkins Job"),
            /**
             * 更新Jenkins Job
             */
            UPDATE("update-job", "更新Jenkins Job"),
            /**
             * 删除Jenkins Job
             */
            DELETE("delete-job", "删除Jenkins Job"),
            /**
             * 构建Jenkins Job
             */
            BUILD("build", "构建Jenkins Job"),
            /**
             * Jenkins Job构建日志输出
             */
            CONSOLE("console", "Jenkins Job构建日志输出"),
            /**
             * 查询Jenkins Job集合
             */
            LIST("list-jobs", "查询Jenkins Job集合"),
            /**
             * 查询Jenkins Job
             */
            GET("get-job", "查询Jenkins Job"),
            /**
             * 将Jenkins Job添加到视图中
             */
            ADD_TO_VIEW("add-job-to-view", "将Jenkins Job添加到视图中"),
            /**
             * 将Jenkins Job从视图中移除
             */
            REMOVE_FROM_VIEW("remove-job-from-view", "将Jenkins Job从视图中移除"),
            /**
             * 启用Jenkins Job
             */
            ENABLE("enable-job", "启用Jenkins Job"),
            /**
             * 禁用Jenkins Job
             */
            DISABLE("disable-job", "禁用Jenkins Job"),
            /**
             * 重新加载Jenkins Job
             */
            RELOAD("reload-job", "重新加载Jenkins Job"),
            /**
             * 停止构建Jenkins Jobs
             */
            STOP_BUILDS("stop-builds", "停止构建Jenkins Job");

            @Setter
            @Getter
            private String op;
            @Setter
            @Getter
            private String desc;

            Operation(String op, String desc) {
                this.setOp(op);
                this.setDesc(desc);
            }
        }

        /**
         * 查询Jenkins上的Job列表
         *
         * @param host     Jenkins地址,比如:http://10.100.57.156:8080
         * @param auth     Jenkins登录用户名:密码,比如:admin:admin
         * @param viewName Jenkins视图名称,为空时,查询全部Jobs
         * @return ResultDto
         */
        public static ResultDto listJobs(String host, String auth, String viewName) {
            String[] baseArgs = new String[]{Operation.LIST.op};
            String[] finalArgs = StringUtils.hasText(viewName) ? Stream.concat(Arrays.stream(baseArgs),
                    Arrays.stream(new String[]{viewName})).toArray(String[]::new) : baseArgs;
            CLI cli = doWork(host, auth, finalArgs, PROTOCOL_HTTP, null);
            int code = cli.code;
            String msg = cli.msg;
            List<JobDto> jobDtoList = new ArrayList<>(10);
            boolean ifSuccess = ResultDto.SUCCESS.equals(String.valueOf(code));
            boolean listAllJobs = StringUtils.hasText(viewName) ? true : false;
            if (ifSuccess) {
                if (StringUtils.hasText(msg)) {
                    String[] arr = msg.split(END_SYMBOL);
                    for (String tmp : arr) {
                        JobDto jobDto = new JobDto();
                        jobDto.setJobName(tmp);
                        jobDto.setViewName(listAllJobs ? viewName : "");
                        jobDtoList.add(jobDto);
                    }
                }
            }
            return ifSuccess ? ResultDto.buildSuccess(jobDtoList) : ResultDto.buildError(jobDtoList).msg(msg);
        }

        /**
         * 查询Jenkins上的凭证列表
         *
         * @param ip       Jenkins服务IP
         * @param port     Jenkins服务端口
         * @param username Jenkins服务登录用户名
         * @param password Jenkins服务登录密码
         * @param viewName Jenkins视图名称,为空时,查询全部Jobs
         * @return ResultDto
         */
        public static ResultDto listJobs(String ip, String port, String username, String password, String viewName) {
            String host = "http://" + ip + ":" + port;
            String auth = username + ":" + password;
            return listJobs(host, auth, viewName);
        }

        public static ResultDto addJob2View(String host, String auth, String viewName, String[] jobNames) {
            String[] baseArgs = new String[]{Operation.ADD_TO_VIEW.op};
            String[] finalArgs = Stream.of(baseArgs, new String[]{viewName}, jobNames).flatMap(Arrays::stream)
                    .toArray(String[]::new);
            CLI cli = doWork(host, auth, finalArgs, PROTOCOL_HTTP, null);
            int code = cli.code;
            String msg = cli.msg;
            List<JobDto> jobDtoList = new ArrayList<>(10);
            return ResultDto.SUCCESS.equals(String.valueOf(code)) ?
                    ResultDto.buildSuccess(jobDtoList) : ResultDto.buildError(jobDtoList).msg(msg);
        }

        public static ResultDto addJob2View(String ip, String port, String username, String password,
                                            String viewName, String[] jobNames) {
            String host = "http://" + ip + ":" + port;
            String auth = username + ":" + password;
            return addJob2View(host, auth, viewName, jobNames);
        }

        public static ResultDto removeJobFromView(String host, String auth, String viewName, String[] jobNames) {
            String[] baseArgs = new String[]{Operation.REMOVE_FROM_VIEW.op};
            String[] finalArgs = Stream.of(baseArgs, new String[]{viewName}, jobNames).flatMap(Arrays::stream)
                    .toArray(String[]::new);
            CLI cli = doWork(host, auth, finalArgs, PROTOCOL_HTTP, null);
            int code = cli.code;
            String msg = cli.msg;
            List<JobDto> jobDtoList = new ArrayList<>(10);
            return ResultDto.SUCCESS.equals(String.valueOf(code)) ?
                    ResultDto.buildSuccess(jobDtoList) : ResultDto.buildError(jobDtoList).msg(msg);
        }

        /**
         * 创建Job
         *
         * @param host Jenkins地址,比如:http://10.100.57.156:8080
         * @param auth Jenkins登录用户名:密码,比如:admin:admin
         * @param job  Jenkins Job
         * @return {@link ResultDto}
         */
        public static ResultDto createJob(String host, String auth, JobDto job) {
            List<JobDto.SvnInfoDto> svnInfoDtoList = job.getSvnInfoList();
            List<JobDto.GitInfoDto> gitInfoDtoList = job.getGitInfoList();
            boolean scmCheck = CollectionUtils.isEmpty(svnInfoDtoList) && CollectionUtils.isEmpty(gitInfoDtoList);
            if (scmCheck) {
                return ResultDto.buildErrorDto().msg("源码管理地址信息不能为空");
            }
            String xml = "<?xml version='1.1' encoding='UTF-8'?>\n" +
                    "<project>\n" +
                    "    <actions/>\n" +
                    "    <description>" + job.getDescription() + "</description>\n" +
                    "    <keepDependencies>false</keepDependencies>\n" +
                    "    <properties/>\n";
            if (!CollectionUtils.isEmpty(svnInfoDtoList)) {
                xml += buildSvn(job);
            }
            if (!CollectionUtils.isEmpty(gitInfoDtoList)) {
                xml += buildGit(job);
            }
            xml += "        </locations>\n" +
                    "        <excludedRegions></excludedRegions>\n" +
                    "        <includedRegions></includedRegions>\n" +
                    "        <excludedUsers></excludedUsers>\n" +
                    "        <excludedRevprop></excludedRevprop>\n" +
                    "        <excludedCommitMessages></excludedCommitMessages>\n" +
                    "        <workspaceUpdater class=\"hudson.scm.subversion.UpdateUpdater\"/>\n" +
                    "        <ignoreDirPropChanges>false</ignoreDirPropChanges>\n" +
                    "        <filterChangelog>false</filterChangelog>\n" +
                    "        <quietOperation>true</quietOperation>\n" +
                    "    </scm>\n" +
                    "    <canRoam>true</canRoam>\n" +
                    "    <disabled>" + job.getDisabled() + "</disabled>\n" +
                    "    <blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>\n" +
                    "    <blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>\n" +
                    "    <triggers/>\n" +
                    "    <concurrentBuild>false</concurrentBuild>\n";
            xml += buildBuilders(job);
            xml += "    <publishers/>\n" +
                    "    <buildWrappers/>\n" +
                    "</project>";
            CLI cli = doWork(host, auth, new String[]{Operation.CREATE.op, job.getJobName()}, PROTOCOL_HTTP, xml);
            int code = cli.code;
            String msg = cli.msg;
            return ResultDto.SUCCESS.equals(String.valueOf(code)) ?
                    ResultDto.buildSuccessDto() : ResultDto.buildErrorDto().msg(msg);
        }

        /**
         * 更新Job
         *
         * @param host Jenkins地址,比如:http://10.100.57.156:8080
         * @param auth Jenkins登录用户名:密码,比如:admin:admin
         * @param job  Jenkins Job
         * @return {@link ResultDto}
         */
        public static ResultDto updateJob(String host, String auth, JobDto job) {
            //TODO:待补充完善
            return null;
        }

        /**
         * 删除单个或多个Job
         *
         * @param host     Jenkins地址,比如:http://10.100.57.156:8080
         * @param auth     Jenkins登录用户名:密码,比如:admin:admin
         * @param jobNames Jenkins Job名称集
         * @return {@link ResultDto}
         */
        public static ResultDto deleteJob(String host, String auth, String[] jobNames) {
            String[] finalArgs = Stream.of(new String[]{Operation.DELETE.op}, jobNames)
                    .flatMap(Arrays::stream).toArray(String[]::new);
            return operation(host, auth, finalArgs);
        }

        /**
         * 复制Job
         *
         * @param host        Jenkins地址,比如:http://10.100.57.156:8080
         * @param auth        Jenkins登录用户名:密码,比如:admin:admin
         * @param srcJobName  需要被复制的Jenkins Job名称
         * @param destJobName 新Jenkins Job名称
         * @return {@link ResultDto}
         */
        public static ResultDto copyJob(String host, String auth, String srcJobName, String destJobName) {
            String[] finalArgs = new String[]{Operation.COPY.op, srcJobName, destJobName};
            return operation(host, auth, finalArgs);
        }

        /**
         * 查询单个Job
         *
         * @param host    Jenkins地址,比如:http://10.100.57.156:8080
         * @param auth    Jenkins登录用户名:密码,比如:admin:admin
         * @param jobName Jenkins Job名称
         * @return {@link ResultDto}
         */
        public static ResultDto<JobDto> getJob(String host, String auth, String jobName) {
            String[] finalArgs = new String[]{Operation.GET.op, jobName};
            ResultDto resultDto = operation(host, auth, finalArgs);
            JobDto jobDto = new JobDto();
            jobDto.setJobName(jobName);
            //解析xml,获取名称、描述等信息
            String msg = ObjectUtils.isEmpty(resultDto.getData()) ? "" : resultDto.getData().toString();
            if (StringUtils.hasText(msg)) {
                jobDto.parseXmlStr2Dto(msg);
            }
            return resultDto.data(jobDto);
        }

        /**
         * 构建单个Job
         *
         * @param host    Jenkins地址,比如:http://10.100.57.156:8080
         * @param auth    Jenkins登录用户名:密码,比如:admin:admin
         * @param jobName Jenkins Job名称
         * @return {@link ResultDto}
         */
        public static ResultDto buildJob(String host, String auth, String jobName) {
            return operation(host, auth, new String[]{Operation.BUILD.op, jobName});
        }

        /**
         * 输出单个Job的构建日志信息
         *
         * @param host    Jenkins地址,比如:http://10.100.57.156:8080
         * @param auth    Jenkins登录用户名:密码,比如:admin:admin
         * @param jobName Jenkins Job名称
         * @param buildId 构建id,为空时,查询最后一次构建的信息
         * @return {@link ResultDto}
         */
        public static ResultDto console(String host, String auth, String jobName, Integer buildId) {
            String[] baseArgs = new String[]{Operation.CONSOLE.op, jobName};
            String[] finalArgs = ObjectUtils.isEmpty(buildId) ? baseArgs : Stream.of(baseArgs, new String[]{buildId.toString()})
                    .flatMap(Arrays::stream).toArray(String[]::new);
            return operation(host, auth, finalArgs);
        }

        /**
         * 禁用Job
         *
         * @param host    Jenkins地址,比如:http://10.100.57.156:8080
         * @param auth    Jenkins登录用户名:密码,比如:admin:admin
         * @param jobName Jenkins Job名称
         * @return {@link ResultDto}
         */
        public static ResultDto disableJob(String host, String auth, String jobName) {
            return operation(host, auth, new String[]{Operation.DISABLE.op, jobName});
        }

        /**
         * 启用Job
         *
         * @param host    Jenkins地址,比如:http://10.100.57.156:8080
         * @param auth    Jenkins登录用户名:密码,比如:admin:admin
         * @param jobName Jenkins Job名称
         * @return {@link ResultDto}
         */
        public static ResultDto enableJob(String host, String auth, String jobName) {
            return operation(host, auth, new String[]{Operation.ENABLE.op, jobName});
        }

        /**
         * 重新加载Job
         *
         * @param host    Jenkins地址,比如:http://10.100.57.156:8080
         * @param auth    Jenkins登录用户名:密码,比如:admin:admin
         * @param jobName Jenkins Job名称
         * @return {@link ResultDto}
         */
        public static ResultDto reloadJob(String host, String auth, String jobName) {
            return operation(host, auth, new String[]{Operation.RELOAD.op, jobName});
        }

        /**
         * 停止构建Job
         *
         * @param host     Jenkins地址,比如:http://10.100.57.156:8080
         * @param auth     Jenkins登录用户名:密码,比如:admin:admin
         * @param jobNames Jenkins Job名称集合
         * @return {@link ResultDto}
         */
        public static ResultDto stopBuildJob(String host, String auth, String[] jobNames) {
            String[] finalArgs = Stream.of(new String[]{Operation.STOP_BUILDS.op}, jobNames)
                    .flatMap(Arrays::stream).toArray(String[]::new);
            return operation(host, auth, finalArgs);
        }

        /**
         * 获取Jenkins Job的构建信息
         *
         * @param host     Jenkins地址,比如:http://10.100.57.156:8080
         * @param username Jenkins登录用户名
         * @param password Jenkins登录用户密码
         * @param jobName  Jenkins Job名称
         * @param buildId  Jenkins Job构建id
         * @return {@link ResultDto}
         */
        public static ResultDto<BuildInfoDto> getJobBuildInfoDetail(String host, String username, String password,
                                                                    String jobName, Integer buildId) {
            if (ObjectUtils.isEmpty(buildId)) {
                return ResultDto.buildErrorDto().msg("buildId can not empty.");
            }
            JenkinsClient client = JenkinsClient.builder().endPoint(host).credentials(username + ":" + password).build();
            List<QueueItem> list = client.api().queueApi().queue();
            for (QueueItem item : list) {
                System.out.println(item.why() + "   " + item.task().name());
            }
            System.out.println(JsonUtil.toJSONString(client.api().systemApi().systemInfo()));
            BuildInfo data = client.api().jobsApi().buildInfo(null, jobName, buildId);
            System.out.println(data.building());

            String url = JOB_BUILD_DETAIL_URL.replace("@host", host).replace("@jobName", jobName)
                    .replace("@buildId", buildId.toString());
            return doGet(url, username, password, BuildInfoDto.class);
        }

        /**
         * 获取Jenkins Job的构建信息
         *
         * @param host     Jenkins地址,比如:http://10.100.57.156:8080
         * @param username Jenkins登录用户名
         * @param password Jenkins登录用户密码
         * @param jobName  Jenkins Job名称
         * @param buildId  Jenkins Job构建id
         * @return {@link ResultDto}
         */
        public static boolean getJobBuildStatus(String host, String username, String password,
                                                String jobName, Integer buildId) {
            if (ObjectUtils.isEmpty(buildId)) {
                throw new IllegalArgumentException("buildId can not empty.");
            }
            String url = JOB_BUILD_DETAIL_URL.replace("@host", host).replace("@jobName", jobName)
                    .replace("@buildId", buildId.toString());
            BuildInfoDto infoDto = getJobBuildInfoDetail(url, username, password, jobName, buildId).getData();
            return infoDto.getBuilding();
        }

        /**
         * 操作单个Job(查询、启用、禁用、删除)
         *
         * @param host Jenkins地址,比如:http://10.100.57.156:8080
         * @param auth Jenkins登录用户名:密码,比如:admin:admin
         * @param args Jenkins CLI参数
         * @return {@link ResultDto}
         */
        private static ResultDto operation(String host, String auth, String[] args) {
            CLI cli = doWork(host, auth, args, PROTOCOL_HTTP, null);
            int code = cli.code;
            String msg = cli.msg;
            return ResultDto.SUCCESS.equals(String.valueOf(code)) ?
                    ResultDto.buildSuccess(msg) : ResultDto.buildError(msg).msg(msg);
        }

        /**
         * 组织Job的git xml章节内容
         *
         * @param job JobDto
         * @return {@link String}
         */
        private static String buildGit(JobDto job) {
            //TODO:待补充组装git相关xml配置
            String xml = "";
            return xml;
        }

        /**
         * 组织Job的svn xml章节内容
         *
         * @param job JobDto
         * @return {@link String}
         */
        private static String buildSvn(JobDto job) {
            List<JobDto.SvnInfoDto> svnInfoDtoList = job.getSvnInfoList();
            String xml = "    <scm class=\"hudson.scm.SubversionSCM\" >\n" +
                    "        <locations>\n";
            StringBuilder sb = new StringBuilder();
            for (JobDto.SvnInfoDto svnInfoDto : svnInfoDtoList) {
                sb.append("            <hudson.scm.SubversionSCM_-ModuleLocation>\n")
                        .append("                <remote>" + svnInfoDto.getRemote() + "</remote>\n")
                        .append("                <credentialsId>" + svnInfoDto.getCredentialsId() + "</credentialsId>\n")
                        .append("                <local>" + svnInfoDto.getLocal() + "</local>\n")
                        .append("                <depthOption>" + svnInfoDto.getDepthOption() + "</depthOption>\n")
                        .append("                <ignoreExternalsOption>" + svnInfoDto.getIgnoreExternalsOption() + "</ignoreExternalsOption>\n")
                        .append("                <cancelProcessOnExternalsFail>" + svnInfoDto.getCancelProcessOnExternalsFail() + "</cancelProcessOnExternalsFail>\n")
                        .append("            </hudson.scm.SubversionSCM_-ModuleLocation>\n");
            }
            xml += sb.toString();
            return xml;
        }

        /**
         * 组织Job的builders xml章节内容
         *
         * @param job JobDto
         * @return {@link String}
         */
        private static String buildBuilders(JobDto job) {
            String xml = "";
            List<String> shellList = job.getBuildCmdList();
            List<JobDto.SonarRunnerBuilderDto> sonarRunnerBuilderDtoList = job.getSonarRunnerBuilderDtoList();
            boolean checkBuilders = CollectionUtils.isEmpty(shellList) && CollectionUtils.isEmpty(sonarRunnerBuilderDtoList);
            if (checkBuilders) {
                xml += "<builders/>";
            } else {
                xml += "    <builders>\n";
                if (!CollectionUtils.isEmpty(shellList)) {
                    String shells = shellList.stream().collect(Collectors.joining("\n"));
                    xml += "        <hudson.tasks.Shell>\n" +
                            "            <command>" + shells +
                            "            </command>\n" +
                            "            <configuredLocalRules/>\n" +
                            "        </hudson.tasks.Shell>\n";
                }
                if (!CollectionUtils.isEmpty(sonarRunnerBuilderDtoList)) {
                    JobDto.ProjectInfo projectInfo = job.getProjectInfo();
                    String keyInfo = projectInfo.getProjectName() + "_" + job.getJobName() + "_" + projectInfo.getBuildVersion();
                    StringBuilder sb = new StringBuilder();
                    for (JobDto.SonarRunnerBuilderDto sonar : sonarRunnerBuilderDtoList) {
                        sb.append("        <hudson.plugins.sonar.SonarRunnerBuilder>\n")
                                .append("            <project></project>\n")
                                .append("            <properties>sonar.projectKey=" + keyInfo + "\n")
                                .append("sonar.projectName=" + keyInfo + "\n")
                                .append("sonar.projectVersion=" + projectInfo.getBuildVersion() + "\n")
                                .append("sonar.language=" + sonar.getSonarScannerLanguage() + "\n")
                                .append("sonar.sourceEncoding=UTF-8\n")
                                .append("sonar.java.binaries=target/classes\n")
                                .append("sonar.sources=.\n")
                                .append("sonar.login=" + job.getSonarLogin() + "\n")
                                .append("sonar.password=" + job.getSonarPassword() + "\n")
                                .append("sonar.scm.disabled=" + sonar.getSonarScmDisabled())
                                .append("            </properties>\n")
                                .append("            <javaOpts>" + sonar.getJavaOpts() + "</javaOpts>\n")
                                .append("            <additionalArguments>" + sonar.getAdditionalArguments() + "</additionalArguments>\n")
                                .append("            <jdk>" + sonar.getJdk() + "</jdk>\n")
                                .append("            <task>" + sonar.getTask() + "</task>\n")
                                .append("        </hudson.plugins.sonar.SonarRunnerBuilder>\n");
                    }
                    xml += sb.toString();
                }
                xml += "    </builders>\n";
            }
            return xml;
        }

    }


    public static class Views {

        public enum Operation {
            /**
             * 创建Jenkins视图
             */
            CREATE("create-view", "创建Jenkins视图"),
            /**
             * 更新Jenkins视图
             */
            UPDATE("update-view", "更新Jenkins视图"),
            /**
             * 删除Jenkins视图
             */
            DELETE("delete-view", "删除Jenkins视图"),
            /**
             * 查询Jenkins视图
             */
            GET("get-view", "查询Jenkins视图");

            @Setter
            @Getter
            private String op;
            @Setter
            @Getter
            private String desc;

            Operation(String op, String desc) {
                this.setOp(op);
                this.setDesc(desc);
            }
        }

        /**
         * 创建View
         *
         * @param host    Jenkins地址,比如:http://10.100.57.156:8080
         * @param auth    Jenkins登录用户名:密码,比如:admin:admin
         * @param viewDto ViewDto
         * @return {@link ResultDto}
         */
        public static ResultDto createView(String host, String auth, ViewDto viewDto) {
            return operation(host, auth, viewDto, Operation.CREATE);
        }

        /**
         * 更新View
         *
         * @param host    Jenkins地址,比如:http://10.100.57.156:8080
         * @param auth    Jenkins登录用户名:密码,比如:admin:admin
         * @param viewDto ViewDto
         * @return {@link ResultDto}
         */
        public static ResultDto updateView(String host, String auth, ViewDto viewDto) {
            return operation(host, auth, viewDto, Operation.UPDATE);
        }

        /**
         * 删除View
         *
         * @param host    Jenkins地址,比如:http://10.100.57.156:8080
         * @param auth    Jenkins登录用户名:密码,比如:admin:admin
         * @param viewDto ViewDto
         * @return {@link ResultDto}
         */
        public static ResultDto deleteView(String host, String auth, ViewDto viewDto) {
            return operation(host, auth, viewDto, Operation.DELETE);
        }

        /**
         * 重命名View
         *
         * @param host        Jenkins地址,比如:http://10.100.57.156:8080
         * @param auth        Jenkins登录用户名:密码,比如:admin:admin
         * @param oldViewName Jenkins旧视图名称
         * @param newViewName Jenkins新视图名称
         * @return ResultDto
         */
        public static ResultDto rename(String host, String auth, String oldViewName, String newViewName) {
            return copyOrRenameView(host, auth, oldViewName, newViewName, true);
        }

        /**
         * 拷贝View
         *
         * @param host        Jenkins地址,比如:http://10.100.57.156:8080
         * @param auth        Jenkins登录用户名:密码,比如:admin:admin
         * @param oldViewName Jenkins旧视图名称
         * @param newViewName Jenkins新视图名称
         * @return ResultDto
         */
        public static ResultDto copyView(String host, String auth, String oldViewName, String newViewName) {
            return copyOrRenameView(host, auth, oldViewName, newViewName, false);
        }

        /**
         * 根据视图名称查询视图信息
         *
         * @param host             Jenkins地址,比如:http://10.100.57.156:8080
         * @param auth             Jenkins登录用户名:密码,比如:admin:admin
         * @param viewName         Jenkins视图名称
         * @param returnJobDetails 是否返回Job详细信息,默认不返回。
         * @return {@link ResultDto}
         */
        public static ResultDto<ViewDto> getView(String host, String auth, String viewName, Boolean returnJobDetails) {
            if (!StringUtils.hasText(viewName)) {
                return ResultDto.buildErrorDto().msg("视图名称不能为空");
            }
            CLI cli = doWork(host, auth, new String[]{Operation.GET.op, viewName}, PROTOCOL_HTTP, null);
            int code = cli.code;
            String msg = cli.msg;
            boolean ifSuccess = ResultDto.SUCCESS.equals(String.valueOf(code));
            ViewDto viewDto = new ViewDto();
            viewDto.setViewName(viewName);
            //解析xml,获取view名称、描述、关联的job等信息
            if (StringUtils.hasText(msg)) {
                viewDto.parseXmlStr2Dto(msg);
            }
            if (ObjectUtils.isEmpty(returnJobDetails)) {
                returnJobDetails = false;
            }
            if (returnJobDetails) {
                List<JobDto> jobDtoList = viewDto.getJobList();
                for (JobDto jobDto : jobDtoList) {
                    String jobName = jobDto.getJobName();
                    JobDto dto = Jobs.getJob(host, auth, jobName).getData();
                    BeanUtils.copyProperties(dto, jobDto);
                }
            }
            return ifSuccess ? ResultDto.buildSuccess(viewDto) : ResultDto.buildError(viewDto).msg(msg);
        }

        /**
         * 拷贝或重命名View
         *
         * @param host        Jenkins地址,比如:http://10.100.57.156:8080
         * @param auth        Jenkins登录用户名:密码,比如:admin:admin
         * @param oldViewName Jenkins旧视图名称
         * @param newViewName Jenkins新视图名称
         * @return ResultDto
         */
        private static ResultDto copyOrRenameView(String host, String auth, String oldViewName, String newViewName, boolean rename) {
            //1、先查询目标View
            ResultDto<ViewDto> oldViewInfoResult = getView(host, auth, oldViewName, true);
            if (!oldViewInfoResult.ifSuccess()) {
                return oldViewInfoResult;
            }
            ViewDto newViewInfo = new ViewDto();
            ViewDto oldViewInfo = oldViewInfoResult.getData();
            BeanUtils.copyProperties(oldViewInfo, newViewInfo);
            newViewInfo.setViewName(newViewName);
            //2、拷贝目标View内容,并重命名
            ResultDto createResult = operation(host, auth, newViewInfo, Operation.CREATE);
            if (!createResult.ifSuccess()) {
                return createResult;
            }
            List<JobDto> jobDtoList = oldViewInfo.getJobList();
            if (CollectionUtils.isEmpty(jobDtoList)) {
                return createResult;
            }
            String[] jobNames = new String[jobDtoList.size()];
            for (int i = 0; i < jobDtoList.size(); i++) {
                jobNames[i] = jobDtoList.get(i).getJobName();
            }
            ResultDto addJob2ViewResult = Jobs.addJob2View(host, auth, newViewName, jobNames);
            if (!addJob2ViewResult.ifSuccess()) {
                return addJob2ViewResult;
            }
            if (rename) {
                //3、再删除旧View
                return operation(host, auth, oldViewInfo, Operation.DELETE);
            } else {
                return ResultDto.buildSuccessDto();
            }
        }

        /**
         * @param host    Jenkins地址,比如:http://10.100.57.156:8080
         * @param auth    Jenkins登录用户名:密码,比如:admin:admin
         * @param viewDto ViewDto
         * @param op      操作:create-view、update-view、delete-view
         * @return {@link ResultDto}
         */
        private static ResultDto operation(String host, String auth, ViewDto viewDto, Operation op) {
            String operation = op.op;
            String xml = "<?xml version=\"1.1\" encoding=\"UTF-8\"?>\n" +
                    "<hudson.model.ListView>\n" +
                    "    <name>" + viewDto.getViewName() + "</name>\n" +
                    "    <description>" + viewDto.getDescription() + "</description>\n" +
                    "    <filterExecutors>" + viewDto.isFilterExecutors() + "</filterExecutors>\n" +
                    "    <filterQueue>" + viewDto.isFilterQueue() + "</filterQueue>\n" +
                    "    <properties class=\"hudson.model.View$PropertyList\"/>\n" +
                    "    <jobNames>\n" +
                    "        <comparator class=\"java.lang.String$CaseInsensitiveComparator\"/>\n" +
                    "    </jobNames>\n" +
                    "    <jobFilters>\n" +
                    "    </jobFilters>\n" +
                    "    <columns>\n" +
                    "        <hudson.views.StatusColumn/>\n" +
                    "        <hudson.views.WeatherColumn/>\n" +
                    "        <hudson.views.JobColumn/>\n" +
                    "        <hudson.views.LastSuccessColumn/>\n" +
                    "        <hudson.views.LastFailureColumn/>\n" +
                    "        <hudson.views.LastStableColumn/>\n" +
                    "        <hudson.views.LastDurationColumn/>\n" +
                    "        <hudson.views.BuildButtonColumn/>\n" +
                    "        <jenkins.branch.DescriptionColumn />\n" +
                    "    </columns>\n";
            if (StringUtils.hasText(viewDto.getIncludeRegex())) {
                xml += "    <includeRegex>" + viewDto.getIncludeRegex() + "</includeRegex>\n";
            }
            xml += "    <recurse>" + viewDto.isRecurse() + "</recurse>\n" +
                    "</hudson.model.ListView>";
            boolean isUpdateOrDelete = Operation.DELETE.equals(op) || Operation.UPDATE.equals(op);
            String[] finalArgs = isUpdateOrDelete ?
                    new String[]{operation, viewDto.getViewName()} : new String[]{operation};
            CLI cli = doWork(host, auth, finalArgs, PROTOCOL_HTTP, xml);
            int code = cli.code;
            String msg = cli.msg;
            return ResultDto.SUCCESS.equals(String.valueOf(code)) ?
                    ResultDto.buildSuccessDto() : ResultDto.buildErrorDto().msg(msg);
        }
    }

    public static class JenkinsSystem {

        public enum Operation {
            /**
             * 获取Jenkins支持的命令
             */
            HELP("help", "获取Jenkins支持的命令"),
            /**
             * 获取Jenkins版本信息
             */
            VERSION("version", "获取Jenkins版本信息"),
            /**
             * 更新Jenkins全局配置信息
             */
            RELOAD_CONFIGURATION("reload-configuration", "更新Jenkins全局配置信息"),
            /**
             * 重启Jenkins服务
             */
            RESTART("restart", "重启Jenkins服务"),
            /**
             * 安全重启Jenkins服务(Safe Restart Jenkins. Don't start any builds.)
             */
            SAFE_RESTART("safe-restart", "重启Jenkins服务"),
            /**
             * 停止Jenkins服务
             */
            SHUTDOWN("shutdown", "停止Jenkins服务"),
            /**
             * 安全停止Jenkins服务(Puts Jenkins into the quiet mode, wait for existing builds to be completed,
             * and then shut down Jenkins.)
             */
            SAFE_SHUTDOWN("safe-shutdown", "安全停止Jenkins服务"),
            /**
             * 清除Jenkins中的构建队列(Clears the build queue.)
             */
            CLEAR_QUEUE("clear-queue", "清除Jenkins中的构建队列"),
            ;

            @Setter
            @Getter
            private String op;
            @Setter
            @Getter
            private String desc;

            Operation(String op, String desc) {
                this.setOp(op);
                this.setDesc(desc);
            }
        }

        /**
         * 获取Jenkins支持的命令
         *
         * @param host Jenkins地址,比如:http://10.100.57.156:8080
         * @param auth Jenkins登录用户名:密码,比如:admin:admin
         * @return ResultDto
         */
        public static ResultDto help(String host, String auth) {
            return operation(host, auth, Operation.HELP);
        }

        /**
         * 获取Jenkins版本信息
         *
         * @param host Jenkins地址,比如:http://10.100.57.156:8080
         * @param auth Jenkins登录用户名:密码,比如:admin:admin
         * @return ResultDto
         */
        public static ResultDto getVersion(String host, String auth) {
            return operation(host, auth, Operation.VERSION);
        }

        /**
         * 重启Jenkins服务
         *
         * @param host Jenkins地址,比如:http://10.100.57.156:8080
         * @param auth Jenkins登录用户名:密码,比如:admin:admin
         * @return ResultDto
         */
        public static ResultDto restart(String host, String auth) {
            return operation(host, auth, Operation.RESTART);
        }

        /**
         * 安全重启Jenkins服务(Safe Restart Jenkins. Don't start any builds.)
         *
         * @param host Jenkins地址,比如:http://10.100.57.156:8080
         * @param auth Jenkins登录用户名:密码,比如:admin:admin
         * @return ResultDto
         */
        public static ResultDto safeRestart(String host, String auth) {
            return operation(host, auth, Operation.SAFE_RESTART);
        }

        /**
         * 停止Jenkins服务
         *
         * @param host Jenkins地址,比如:http://10.100.57.156:8080
         * @param auth Jenkins登录用户名:密码,比如:admin:admin
         * @return ResultDto
         */
        public static ResultDto shutdown(String host, String auth) {
            return operation(host, auth, Operation.SHUTDOWN);
        }

        /**
         * 安全停止Jenkins服务(Puts Jenkins into the quiet mode, wait for existing builds to be completed,
         * and then shut down Jenkins.)
         *
         * @param host Jenkins地址,比如:http://10.100.57.156:8080
         * @param auth Jenkins登录用户名:密码,比如:admin:admin
         * @return ResultDto
         */
        public static ResultDto safeShutdown(String host, String auth) {
            return operation(host, auth, Operation.SAFE_SHUTDOWN);
        }

        /**
         * 清除Jenkins中的构建队列(Clears the build queue.)
         *
         * @param host Jenkins地址,比如:http://10.100.57.156:8080
         * @param auth Jenkins登录用户名:密码,比如:admin:admin
         * @return ResultDto
         */
        public static ResultDto clearQueue(String host, String auth) {
            return operation(host, auth, Operation.CLEAR_QUEUE);
        }

        /**
         * 重新加载Jenkins配置信息
         * Discard all the loaded data in memory and reload everything from file system.
         * Useful when you modified config files directly on disk.
         *
         * @param host Jenkins地址,比如:http://10.100.57.156:8080
         * @param auth Jenkins登录用户名:密码,比如:admin:admin
         * @return ResultDto
         */
        public static ResultDto reloadConfiguration(String host, String auth) {
            return operation(host, auth, Operation.RELOAD_CONFIGURATION);
        }

        /**
         * 基本操作
         *
         * @param host Jenkins地址,比如:http://10.100.57.156:8080
         * @param auth Jenkins登录用户名:密码,比如:admin:admin
         * @param op   操作
         * @return {@link ResultDto}
         */
        private static ResultDto operation(String host, String auth, Operation op) {
            CLI cli = doWork(host, auth, new String[]{op.op}, PROTOCOL_HTTP, null);
            int code = cli.code;
            String msg = cli.msg;
            String successMsg = StringUtils.hasText(msg) ? msg.replaceAll(END_SYMBOL, "") : "";
            return ResultDto.SUCCESS.equals(String.valueOf(code)) ?
                    ResultDto.buildSuccessDto(successMsg) : ResultDto.buildErrorDto().msg(msg);
        }
    }

    /**
     * 调用Jenkins CLI
     * 注意:查询类时xml为空;涉及到使用xml内容创建、更新操作的,xml不能为空!!!
     *
     * @param host     Jenkins地址,比如:http://10.100.57.156:8080
     * @param auth     Jenkins登录用户名:密码,比如:admin:admin
     * @param args     请求参数
     * @param protocol 请求协议,比如http,webSocket,默认http
     * @param xml      处理XML相关,不使用标准输入流,此时使用HTTP协议调用
     * @return CLI
     */
    private static CLI doWork(String host, String auth, String[] args, String protocol, String xml) {
        if (null == args || args.length == 0) {
            throw new IllegalArgumentException("args cannot be empty");
        }
        if (!StringUtils.hasText(protocol)) {
            protocol = PROTOCOL_HTTP;
        }
        byte[] xmlData = new byte[]{};
        if (StringUtils.hasText(xml)) {
            xmlData = xml.getBytes(StandardCharsets.UTF_8);
        }
        CLI cli = new CLI();
        String[] baseArgs = new String[]{"-auth", auth, "-s", host, protocol};
        String[] finalArgs = Stream.concat(Arrays.stream(baseArgs), Arrays.stream(args)).toArray(String[]::new);
        log.info("executing command: {}", JsonUtil.toJSONString(finalArgs));
        try {
            cli._main(finalArgs, xmlData);
        } catch (Exception e) {
            cli.code = -1;
            cli.msg = e.getMessage();
            log.error("executing command: {} cause error ", JsonUtil.toJSONString(finalArgs), e);
        }
        return cli;
    }

    private static <T> ResultDto<T> doGet(String urlString, String username, String password, Class clz) {
        URI uri = URI.create(urlString);
        HttpHost host = new HttpHost(uri.getHost(), uri.getPort(), uri.getScheme());
        CredentialsProvider credsProvider = new BasicCredentialsProvider();
        credsProvider.setCredentials(new AuthScope(uri.getHost(), uri.getPort()), new UsernamePasswordCredentials(username, password));
        AuthCache authCache = new BasicAuthCache();
        BasicScheme basicAuth = new BasicScheme();
        authCache.put(host, basicAuth);
        CloseableHttpClient httpClient = HttpClients.custom().setDefaultCredentialsProvider(credsProvider).build();
        HttpGet httpGet = new HttpGet(uri);
        HttpClientContext localContext = HttpClientContext.create();
        localContext.setAuthCache(authCache);
        if (ObjectUtils.isEmpty(clz)) {
            clz = String.class;
        }
        T data = (T) new Object();
        try {
            CloseableHttpResponse response = httpClient.execute(host, httpGet, localContext);
            String returnMsg = EntityUtils.toString(response.getEntity());
            System.out.println(returnMsg);
            if (StringUtils.hasText(returnMsg)) {
                data = (T) JsonUtil.string2Obj(returnMsg, clz);
                return ResultDto.buildSuccessDto().data(data);
            }
            return ResultDto.buildSuccessDto().data(returnMsg);
        } catch (Exception e) {
            log.error("call {} failed", urlString, e);
            return ResultDto.buildErrorDto().data(data);
        }
    }
}
相关推荐
fangzhanpeng1684 天前
快速掌握C#语言基础知识点(1.基础数据类型)
开发语言·c#·1024程序员节
无己心6 天前
面向多平台 AI 搜索引擎的适配层架构设计
前端·人工智能·搜索引擎·ai·1024程序员节
u01030552712 天前
AI驱动的安卓UI自动生成功能实现
人工智能·1024程序员节
u01030552713 天前
长株潭智能体赋能腾讯元器链接共享
1024程序员节
云贝贝贝14 天前
OceanBase认证体系介绍与备考指南
运维·服务器·oceanbase·1024程序员节
u01030552714 天前
Java图像处理实战指南
人工智能·1024程序员节
u01030552715 天前
Java AWT鼠标事件全解析
人工智能·1024程序员节
u01030552717 天前
Java实用类应用精讲
人工智能·1024程序员节
u01030552717 天前
Java I/O核心操作实战
人工智能·1024程序员节
u01030552718 天前
ArrayList操作详解与实战应用
人工智能·1024程序员节