惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Jina AI
Jina AI
V
Vulnerabilities – Threatpost
Security Latest
Security Latest
AI
AI
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
量子位
H
Help Net Security
Attack and Defense Labs
Attack and Defense Labs
The GitHub Blog
The GitHub Blog
L
LINUX DO - 最新话题
A
Arctic Wolf
博客园_首页
S
Securelist
S
Secure Thoughts
Google DeepMind News
Google DeepMind News
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
T
Tailwind CSS Blog
Apple Machine Learning Research
Apple Machine Learning Research
酷 壳 – CoolShell
酷 壳 – CoolShell
Stack Overflow Blog
Stack Overflow Blog
N
Netflix TechBlog - Medium
Cyberwarzone
Cyberwarzone
小众软件
小众软件
T
Threatpost
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Blog — PlanetScale
Blog — PlanetScale
N
News and Events Feed by Topic
NISL@THU
NISL@THU
Forbes - Security
Forbes - Security
博客园 - 聂微东
F
Fortinet All Blogs
Simon Willison's Weblog
Simon Willison's Weblog
H
Heimdal Security Blog
罗磊的独立博客
S
Security @ Cisco Blogs
B
Blog
T
Troy Hunt's Blog
Engineering at Meta
Engineering at Meta
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
The Hacker News
The Hacker News
The Last Watchdog
The Last Watchdog
Hacker News - Newest:
Hacker News - Newest: "LLM"
I
Intezer
T
Threat Research - Cisco Blogs
C
Cybersecurity and Infrastructure Security Agency CISA
The Cloudflare Blog
S
Schneier on Security
月光博客
月光博客
L
LINUX DO - 热门话题
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org

二丫讲梵

学习周刊-总第258期-2026年第15周 学习周刊-总第257期-2026年第14周 学习周刊-总第256期-2026年第13周 学习周刊-总第255期-2026年第12周 学习周刊-总第254期-2026年第11周 学习周刊-总第253期-2026年第10周 临时插播一条羊毛,免费领取450元大模型API代金券 学习周刊-总第252期-2026年第09周 学习周刊-总第251期-2026年第08周 学习周刊-总第250期-2026年第07周 学习周刊-总第249期-2026年第06周 诚邀评论,聊聊你所知欲知的我 学习周刊-总第248期-2026年第05周 我的QQ动态之2015年 我的QQ动态之2014年 我的QQ动态之2013年 我的QQ动态之2012年 我的QQ动态-2010-2011年 我的QQ动态-创栏小叙 学习周刊-总第247期-2026年第04周 Nexus社区版权益阉割--一文告诉你有哪些版本可以选择 学习周刊-总第246期-2026年第03周 学习周刊-总第245期-2026年第02周 学习周刊-总第244期-2026年第01周 学习周刊-总第243期-2025年第52周 学习周刊-总第242期-2025年第51周 开源项目ZenOps:带你领略禅意运维 学习周刊-总第241期-2025年第50周 用京东金融,享负债人生 学习周刊-总第240期-2025年第49周 学习周刊-总第239期-2025年第48周 整理我在静态服务透明代理上的极致求索之路,最后一个你绝想不到 学习周刊-总第238期-2025年第47周 我们输了,但收获颇多 太多了,太多了 学习周刊-总第237期-2025年第46周 学习周刊-总第236期-2025年第45周 学习周刊-总第235期-2025年第44周 二五年国庆二三事 学习周刊-总第234期-2025年第43周 学习周刊-总第233期-2025年第42周 学习周刊-总第232期-2025年第41周 学习周刊-总第231期-2025年第40周 学习周刊-总第230期-2025年第39周 西湖毅行 2025年开源世界逸闻三则 学习周刊-总第229期-2025年第38周 手抄《与妻书》 CNB开发与构建基于docker-cache缓存复用的配置实践心得 学习周刊-总第228期-2025年第37周 父亲善行录 学习周刊-总第227期-2025年第36周 带你认识我之看看我的高中同学录(其二) 学习周刊-总第226期-2025年第35周 带你认识我之看看我的高中同学录(其一) 认识神级MCP工具系列--用anyquery和数据库交互 学习周刊-总第225期-2025年第34周 学习周刊-总第224期-2025年第33周 学习周刊-总第223期-2025年第32周 学习周刊-总第222期-2025年第31周 学习周刊-总第221期-2025年第30周 CNB云原生开发环境届的瑞士军刀,详解qifei项目 vuepress-vdoing主题配置自建不蒜子统计 学习周刊-总第220期-2025年第29周 写在博客发表文章1000篇的节点 从claude cli的体验聊聊最大的敌人是我们自己的成见 学习周刊-总第219期-2025年第28周 学习周刊-总第218期-2025年第27周 学习周刊-总第217期-2025年第26周 理论正确,事实错误 学习周刊-总第216期-2025年第25周 学习周刊-总第215期-2025年第24周 学习周刊-总第214期-2025年第23周 学习周刊-总第213期-2025年第22周 学习周刊-总第212期-2025年第21周 从赵心童世锦赛夺冠聊聊我的斯诺克情缘 学习周刊-总第211期-2025年第20周 记录二五年五一之短暂回归家庭 学习周刊-总第210期-2025年第19周 学习周刊-总第209期-2025年第18周 学习周刊-总第208期-2025年第17周 Go开发实践之Gin框架将前端的dist目录embed到二进制 学习周刊-总第207期-2025年第16周 近期关于cobra库的一些实践心得总结 学习周刊-总第206期-2025年第15周 我的嗜好--嗑瓜子 记大宝参加幼儿园组织的清明烈士陵园扫墓活动 学习周刊-总第205期-2025年第14周 学习周刊-总第204期-2025年第13周 前端开发小笔记--在数组中给字段添加值与删除字段的操作 学习周刊-总第203期-2025年第12周 人生实苦,何以自渡 学习周刊-总第202期-2025年第11周 近期发现的一些优秀的工具提名(一) 学习周刊-总第201期-2025年第10周 学习周刊-总第200期-2025年第09周 记一次女友喝醉使我忍术破功 爱情风波--一次分手又复合的经历 学习周刊-总第199期-2025年第08周 整理我的信息源
Jenkins-pipeline之利用activity choice插件对接查询MySQL数据实现动态参数化的功能
二丫讲梵 · 2023-09-10 · via 二丫讲梵

# 前言

之前写过一篇文章介绍通过接口获取到数据来渲染构建过程中的动态参数,详见:Jenkins 中 pipeline 对接 CMDB 接口获取主机列表的发布实践 (opens new window)。那么既然能够通过接口渲染数据,是否可以直接在 activity choice 参数的 groovy 脚本中直接通过 MySQL 来实现动态参数的需求呢。

答案是可以的,只不过,一开始我没有料想到,这条路走的是如此曲折。

前后折腾了两次,花费了很多精力去寻找解决方案,最后终于算是摸索出来了一条可行的路。

赶快分享,不在话下!

# 环境

也许不同的 Jenkins 版本,或者插件版本在使用此功能的时候,会遇到与我不一样的问题,或者甚至压根儿不会遇到问题,这都说不准,具体你还要根据你的实际现状来测试,来验证,来观测。

那么我使用的环境基本信息如下:

我习惯使用 Tomcat 部署 war 包的形式来部署 Jenkins。

# 准备数据

因为需要与数据库交互,因此这里需要先有一个数据库,并准备一些基础数据。

创建数据库:

CREATE DATABASE IF NOT EXISTS jkdata DEFAULT CHARACTER SET utf8mb4;

1

创建用户表:

CREATE TABLE jkdata.users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(50),
    department VARCHAR(50)
);

1
2
3
4
5

添加几个测试用户:

INSERT INTO jkdata.users (username, department) VALUES ('zhangsan', 'ops');
INSERT INTO jkdata.users (username, department) VALUES ('lisi', 'ops');
INSERT INTO jkdata.users (username, department) VALUES ('wangwu', 'test');
INSERT INTO jkdata.users (username, department) VALUES ('zhaoliu', 'test');

1
2
3
4

我们的需求是先有一个选项参数,用于指定部门信息,然后动态参数通过查询数据库,列出对应部门的用户。

# 代码

经过一些检索实验,我这边调试后的代码如下:

properties([
    parameters([
        choice(
                name: 'department',
                choices: ['ops','test'],
                description: "ops==运维组<br>test==测试组"
        ),
        [
            $class: 'CascadeChoiceParameter',
            choiceType: 'PT_RADIO',
            name: 'username',
            description: "请选择对应的用户",
            referencedParameters: 'department',
            filterable: true,
            script:
                [
                    $class: 'GroovyScript',
                    fallbackScript: [
                        classpath: [],
                        sandbox: true,
                        script: "return['An error occured']"
                    ],
                    script: [
                        classpath: [],
                        sandbox: true,
                        script:
                            '''
import groovy.sql.Sql

def output = []

def sql = Sql.newInstance('jdbc:mysql://192.168.1.1:3306/jkdata', 'root', 'password', 'com.mysql.jdbc.Driver')
String sqlString = "SELECT DISTINCT username FROM user WHERE department = \'${department}\'"
    sql.eachRow(sqlString){ row ->
        output.push(row[0])
    }
return output
                                            '''
                    ]
                 ]
         ]
    ])
])

pipeline {
    agent any
    stages {
        stage("执行") {
            steps {
                sh '''
                    println"""
                        部门为: ${department}
                        用户为: ${username}
                    """
                '''
            }
        }
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

前边使用了选项参数来写死了部门信息,下边用户信息则是根据选择的部门,通过查询数据库而将符合条件的用户列出来。

# 核心代码踩坑

里边的核心代码是:

import groovy.sql.Sql

def output = []

def sql = Sql.newInstance('jdbc:mysql://192.168.1.1:3306/jkdata', 'root', 'password', 'com.mysql.jdbc.Driver')
String sqlString = "SELECT DISTINCT username FROM user WHERE department = \'${department}\'"
    sql.eachRow(sqlString){ row ->
        output.push(row[0])
    }
return output

1
2
3
4
5
6
7
8
9
10

调试的过程就是这段代码踩坑的过程。主要问题出在 MySQL 的驱动上,我们可以把如上代码,来到 Jenkins 的 系统设置Script Console 中,尝试运行一下,然后就遇到了如下错误:

java.lang.ClassNotFoundException: com.mysql.jdbc.Driver
	at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1420)
	at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1228)
	at java.base/java.lang.Class.forName0(Native Method)

1
2
3
4

如下图:

就是这样一个错误,我查遍了全网,进行了大量的阅读浏览,基本上都是货不对板的解决方案,或者不够详尽。

问题似乎不复杂,无非就是 Jenkins 在运行 groovy 脚本的时候,无法正确加载到驱动,那么,如何才能解决这个驱动问题呢?

直到经过了上百个网页浏览之后,我遇到了这样一篇文章:Jenkins 工程中 SQL 语句执行的方法 (opens new window) 里边介绍了,需要下载 com.mysql.jdbc_5.1.38.jar,然后将 jar 包放到 jenkins 的 lib 目录当中。

接下来问题又来了,文章只说了下载这个包,但没有直接放下载链接,经过检索之后,我发现可以通过这个链接下载这个包: http://www.java2s.com/Code/Jar/c/Downloadcommysqljdbc515jar.htm

这个链接下载的是 com.mysql.jdbc_5.1.15.jar 版本的,不过实测仍旧能够使用。

我的 jenkins 的 lib 路径是在 /usr/local/tomcat/webapps/ROOT/WEB-INF/lib,将下载的 jar 放到这个目录下,然后 重启 Jenkins,之后再到 Script Console 运行脚本,可以看到有结果了:

# 效果呈现

当代码调试通过之后,就可以将如上 groovy 创建为项目,然后运行项目,查看效果。

嗯,舒服!!

# 最后

虽然现在跑通了,但这里边我仍有一些疑惑,如果有人找到了答案,欢迎在评论区一块儿交流:

  • 在 activity choice 插件的参数当中,有一个参数项是 classpath,看起来像是能自定义 jar 包,但我做了许多尝试,都没能成功。
  • 上边的 groovy 脚本中的部门信息是通过选项参数写死的,你如果有兴趣让这个信息也通过数据库取出,那你可以尝试改造一些 groovy 来实现。