0%

jenkins使用pipeline

脚本名词解释

pipeline <必须> Pipeline是CD管道的用户定义模型。Pipeline的代码定义了您的整个构建过程,通常包括构建应用程序,测试和交付应用程序的阶段。
agent <必须> 定义pipeline的执行环境,必须存在
stages<阶段> 包含多个子阶段stage(‘子阶段名’)

jenkins 的工作空间目录 /var/jenkins_home/workspace/

node vs agent 区别

agent是声明性的pipelines,node是脚本性的pipelines

实践

pipeline使用gradle

学习到如何使用工具,和配置工具全局变量

  1. 配置工具系统管理->全局工具配置->Gradle->Gradle 安装

    name:gradle4.8

    • 自动安装

    版本 Gradle 4.8

    Apply->Save即可

    注释:如果没有Gradle设置,先去安装Gradle插件,默认推荐设置是安装了的

  2. 编写Jenkinsfile进行测试

    1
    2
    3
    4
    5
    6
    7
    8
    #!/usr/bin/env groovy Jenkinsfile
    node {
    def gradleHome = tool 'gradle4.8' //这里的gradle4.8要和gradle工具的配置里的name要一致
    env.PATH = "${gradleHome}/bin:${env.PATH}"
    stage('build') {
    sh 'gradle -v'
    }
    }

pipeline使用gradle打包java spring boot

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/usr/bin/env groovy Jenkinsfile
node {
def gradleHome = tool 'gradle4.8' //这里的gradle4.8要和gradle工具的配置里的name要一致
env.PATH = "${gradleHome}/bin:${env.PATH}"
stage('gradle build') {
if (isUnix()) {
//sh './gradlew clean :eurekaserver:build' //这里会自动下载项目里的gradle版本(4.7)
sh 'gradle clean :eurekaserver:build' //使用jenkns安装的gradle工具(4.8)
} else {
// bat 'gradlew.bat clean :eurekaserver:build'
bat 'gradle clean :eurekaserver:build'
}
}
}

打包jar为镜像

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!/usr/bin/env groovy Jenkinsfile
node {
def gradleHome = tool 'gradle4.8' //这里的gradle4.8要和gradle工具的配置里的name要一致
env.PATH = "${gradleHome}/bin:${env.PATH}"
stage('gradle build') {
if (isUnix()) {
//sh './gradlew clean :eurekaserver:build' //这里会自动下载项目里的gradle版本(4.7)
sh 'gradle clean :eurekaserver:build' //使用jenkns安装的gradle工具(4.8)
} else {
// bat 'gradlew.bat clean :eurekaserver:build'
bat 'gradle clean :eurekaserver:build'
}
}
stage('docker build image'){
dir('eurekaserver'){ //dockerfile的跟目录
docker.build("springcould/eurekaserver:${env.BUILD_NUMBER}")
}
}
}

运行镜像

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#!/usr/bin/env groovy Jenkinsfile
node {
def gradleHome = tool 'gradle4.8' //这里的gradle4.8要和gradle工具的配置里的name要一致
env.PATH = "${gradleHome}/bin:${env.PATH}"
stage('gradle build') {
if (isUnix()) {
sh 'gradle clean :eurekaserver:build' //使用jenkns安装的gradle工具(4.8)
} else {
bat 'gradle clean :eurekaserver:build'
}
}
stage('docker build image'){
dir('eurekaserver'){ //dockerfile的跟目录
docker.build("springcould/eurekaserver:${env.BUILD_NUMBER}")
}
}
stage('docker run Application'){
sh "docker run -p 8091:8091 springcould/eurekaserver:${env.BUILD_NUMBER}"
}
}

pipeline 环境变量选择设置

**严重注意**这个需要第二次运行才会生效,第一次设置之后运行,不会出来,第二次拉去运行才会出来
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/usr/bin/env groovy Jenkinsfile
pipeline {
agent any
parameters {
choice(name: 'door_choice',
choices: 'one\ntwo\nthree\nfour',
description: 'What door do you choose?')
}
stages {
stage('build') {
steps {
echo "${params.door_choice}"
}
}
}
}

pipeline agent版gradle脚本

not support tool "gradle4.8"单个设置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#!/usr/bin/env groovy Jenkinsfile
pipeline {
agent any
parameters {
choice(name: 'door_choice',
choices: 'one\ntwo\nthree\nfour',
description: 'What door do you choose?')
}
stages {
stage('build') {
tools{
gradle "gradle4.8"
}
steps {
echo "${params.door_choice}"
sh 'gradle -v'
}
}
}
}

申明式使用脚本式语言script

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/usr/bin/env groovy Jenkinsfile

pipeline {
agent any
parameters {
choice(name: 'project_choice',
choices: 'eurekaserver\neurekaclient\neurekafeign\neurekazuul',
description: '你要编译构建那个项目?')
}
stages {
stage('docker build'){
steps{
dir("${params.project_choice}"){
sh "pwd"
script { //需要用script包裹,就能使用脚本式语言
docker.build("my-image:${env.BUILD_ID}")
}
}
}
}
}
}

环境变量

env.BUILD_ID 当前的编译id,和Jenkins versions 1.597+ 的env.BUILD_NUMBER一样

env.JOB_NAME 当前项目名

env.JENKINS_URL only available if Jenkins URL set in “System Configuration”

git diff HEAD^ eurekaserver/ 和上个版本比较eurekaserver目录,可以不要

常见问题

  1. 提示如下错误

    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
    > git --version # timeout=10
    > git --version # 'git version 1.8.3.1'
    using GIT_ASKPASS to set credentials
    > git ls-remote http://gitlab.admin.exxk.com.cn/exxk/exxk-server.git # timeout=10
    > git rev-parse --resolve-git-dir /var/jenkins_home/caches/git-d065127b6d5e88dbce5baaa6da0dd31a/.git # timeout=10
    Setting origin to http://gitlab.admin.exxk.com.cn/exxk/exxk-server.git
    > git config remote.origin.url http://gitlab.admin.exxk.com.cn/exxk/exxk-server.git # timeout=10
    Fetching & pruning origin...
    Listing remote references...
    > git config --get remote.origin.url # timeout=10
    > git --version # timeout=10
    > git --version # 'git version 1.8.3.1'
    using GIT_ASKPASS to set credentials
    > git ls-remote -h http://gitlab.admin.exxk.com.cn/exxk/exxk-server.git # timeout=10
    Fetching upstream changes from origin
    > git config --get remote.origin.url # timeout=10
    using GIT_ASKPASS to set credentials
    > git fetch --tags --progress --prune origin +refs/heads/*:refs/remotes/origin/* # timeout=10
    ERROR: [星期三 六月 29 07:55:33 UTC 2022] Could not fetch branches from source
    [星期三 六月 29 07:55:33 UTC 2022] Finished branch indexing. Indexing took 0.5 秒
    FATAL: Failed to recompute children of prd-exxk6xljd » prd-exxk-server
    hudson.plugins.git.GitException: Command "git fetch --tags --progress --prune origin +refs/heads/*:refs/remotes/origin/*" returned status code 1:
    stdout:
    stderr: error: there are still refs under 'refs/remotes/origin/release'
    From http://gitlab.admin.exxk.com.cn/exxk/exxk-server
    ! [new branch] release -> origin/release (unable to update local ref)

    at org.jenkinsci.plugins.gitclient.CliGitAPIImpl.launchCommandIn(CliGitAPIImpl.java:2671)
    at org.jenkinsci.plugins.gitclient.CliGitAPIImpl.launchCommandWithCredentials(CliGitAPIImpl.java:2096)
    at org.jenkinsci.plugins.gitclient.CliGitAPIImpl.access$500(CliGitAPIImpl.java:84)
    at org.jenkinsci.plugins.gitclient.CliGitAPIImpl$1.execute(CliGitAPIImpl.java:618)
    at jenkins.plugins.git.AbstractGitSCMSource$8.run(AbstractGitSCMSource.java:602)
    at jenkins.plugins.git.AbstractGitSCMSource$8.run(AbstractGitSCMSource.java:588)
    at jenkins.plugins.git.AbstractGitSCMSource.doRetrieve(AbstractGitSCMSource.java:394)
    at jenkins.plugins.git.AbstractGitSCMSource.doRetrieve(AbstractGitSCMSource.java:350)
    at jenkins.plugins.git.AbstractGitSCMSource.retrieve(AbstractGitSCMSource.java:588)
    at jenkins.scm.api.SCMSource._retrieve(SCMSource.java:373)
    at jenkins.scm.api.SCMSource.fetch(SCMSource.java:283)
    at jenkins.branch.MultiBranchProject.computeChildren(MultiBranchProject.java:641)
    at com.cloudbees.hudson.plugins.folder.computed.ComputedFolder.updateChildren(ComputedFolder.java:278)
    at com.cloudbees.hudson.plugins.folder.computed.FolderComputation.run(FolderComputation.java:166)
    at jenkins.branch.MultiBranchProject$BranchIndexing.run(MultiBranchProject.java:1032)
    at hudson.model.ResourceController.execute(ResourceController.java:101)
    at hudson.model.Executor.run(Executor.java:442)
    Finished: FAILURE

    分析:关键错误error: there are still refs under 'refs/remotes/origin/release' From http://gitlab.admin.exxk.com.cn/exxk/exxk-server ! [new branch] release -> origin/release (unable to update local ref)这句表示本地已经有release分支了,服务器的release删了,然后又重新建了,导致不一样,解决清空本地分支,执行git remote prune origin删除旧的分支和冲突分支,但是这是在jenkins里面删除难度较大,因此采用删除git在jenkins里面的缓存,因此需要找到分支的缓存,可以在日志git rev-parse --resolve-git-dir /var/jenkins_home/caches/git-d065127b6d5e88dbce5baaa6da0dd31a/.git这一行发现缓存的目录

    解决:登录jenkins容器,进入cd /var/jenkins_home/caches/然后删除或重命名git-d065127b6d5e88dbce5baaa6da0dd31agit-d065127b6d5e88dbce5baaa6da0dd31a@tmp即可

    总结:kubesphere的devops流程是,先在jenkins容器里面扫描git里面的jenkins部署脚本,然后缓存,然后启动新的容器根据jekins部署脚本拉取代码,运行编译过程。

  2. 流水线卡在‘Jenkins’ doesn’t have label ‘maven’这个提示

    分析:检查jekins输出了一个info信息Maximum number of concurrently running agent pods (100) reached for Kubernetes Cloud kubernetes, not provisioning: 100 running or pending in namespace kubesphere-devops-system with Kubernetes labels {jenkins=slave}这句话意思是agent pods 已经有100个在运行或pending等待中,然后执行kubectl get pod -A发行maven和nodejs的代理镜像加起来刚刚100个,都处于error状态。

    解决:执行kubectl delete pod maven-xxx -n kubesphere-devops-system进行删除错误的pod。

    总结:注意每个日志,不是错误警告日志,也要注意重复多次的提示信息。

  3. 在2基础上分析为什么有100个error的pod,执行kubectl logs maven-0n5wf -n kubesphere-devops-system提示如下错误

    1
    error: a container name must be specified for pod maven-0n5wf, choose one of: [jnlp maven]

    在执行kubectl logs maven-0n5wf -n kubesphere-devops-system -c jnlp提示如下错误

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
       ```



    4. [ks-jenkins:2.249.1](registry.cn-beijing.aliyuncs.com/kubesphereio/ks-jenkins:2.249.1)启动出现异常,找不到原因时,快速删除缓存重建配置可以解决大多数问题。执行

    ````bash
    #命令详解:ls列举所有文件然后通过管道grep ,-v代表反转,-E代表正则,多个匹配,去掉-v可以检查正则是否正确
    #该命令是删除除了jobs、secret.key、secret.key.not-so-secret、secrets、userContent、users、workspace之外的所有文件
    rm -rf `ls | grep -vE "^jobs$|^secret.key$|^secret.key.not-so-secret$|^secrets$|^userContent$|^users$|^workspace$"`

    rm -rf `ls | grep -vE "^jobs$|^secret.key$|^secret.key.not-so-secret$|^secrets$|^userContent$|^users$|^workspace$|^plugins$"`
    ````

    5. 升级[jenkins镜像](registry.cn-beijing.aliyuncs.com/kubesphereio/ks-jenkins:2.249.1)为`jenkins/jenkins:2.354-centos7-jdk8`,然后清理挂载目录(按第4个问题的命令清理),出现如下错误

    ```bash
    2022-08-25 06:29:48.180+0000 [id=10] WARNING h.i.i.InstallUncaughtExceptionHandler#handleException: Caught unhandled exception with ID 077a9ea8-f2e2-4590-a73a-477279c34ccb

    hudson.security.AccessDeniedException3: anonymous is missing the Overall/Read permission

    at hudson.security.ACL.checkPermission(ACL.java:80)

    解决:

参考

https://github.com/arun-gupta/docker-jenkins-pipeline

参考工具

github: osmdroid/osmdroid

compile 'org.osmdroid:osmdroid-android:<VERSION>'

离线地图制作工具: Mobile Atlas Creator

使用Mobile Atlas Creator

wiki map sources

离线地图工具类SampleOfflineOnly.java

离线地图官方教程Offline-Map-Tiles

操作步骤

离线地图制作
  1. 打开Mobile Atlas Creator工具
  2. 新建地图册(可选Osmdroid ZIP/SQLite/GEMF)
  3. 选择地图源
  4. 勾选图片转换,设置图块格式(重要,要和代码的设置一致)
  5. 设置缩放比例
  6. 地图上框选区域
  7. 在当前地图册点击添加选择区域
  8. 最后开始点击下载地图册
  9. 得到一个压缩文件,存储备用
离线地图自定义地图源(geoserver)
  1. Mobile Atlas Creator工具目录的mapsources目录添加地图源配置文件

  2. geoserver地图地图源配置文件geoserver_maps.xml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <customWmsMapSource>
    <name>My Geoserver WMS</name>
    <minZoom>0</minZoom>
    <maxZoom>18</maxZoom>
    <tileType>PNG</tileType>
    <version>1.1.1</version>
    <!-- 图层名字hws(工作空间):china_net(图层名字) -->
    <layers>hws:china_net</layers>
    <!-- hws替换为自己的工作区间,ip端口替换自己服务器的,其他不变 -->
    <url>http://192.168.1.230:8082/geoserver/hws/wms?service=WMS&amp;</url>
    <!-- 投影坐标系 -->
    <coordinatesystem>EPSG:4326</coordinatesystem>
    <aditionalparameters></aditionalparameters>
    <backgroundColor>#000000</backgroundColor>
    </customWmsMapSource>
  3. 多图层配置

    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
    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <customMultiLayerMapSource>
    <name>多图层自定义</name>
    <tileType>png</tileType>
    <backgroundColor>#000000</backgroundColor>
    <!-- 0~1由透明到不透明,1.0是设置对底层的图层,0.5是设置底层上一层图层,以此类推n图层以此设置即可-->
    <layersAlpha>1.0 1.0 0.5 1.0</layersAlpha>
    <layers>
    <customMapSource>
    <name>Google 卫星图</name>
    <minZoom>0</minZoom>
    <maxZoom>20</maxZoom>
    <tileType>PNG</tileType>
    <tileUpdate>None</tileUpdate>
    <url>http://mt0.google.cn/vt/lyrs=s@124&amp;hl=zh-CN&amp;gl=CN&amp;src=app&amp;x={$x}&amp;s=&amp;y={$y}&amp;z={$z}&amp;s=Galileo</url>
    <backgroundColor>#000000</backgroundColor>
    </customMapSource>

    <customMapSource>
    <name>Google 地名图</name>
    <minZoom>0</minZoom>
    <maxZoom>20</maxZoom>
    <tileType>PNG</tileType>
    <tileUpdate>None</tileUpdate>
    <url>http://mt0.google.cn/vt/imgtp=png32&amp;lyrs=h@207000000&amp;hl=zh-CN&amp;gl=CN&amp;src=app&amp;x={$x}&amp;y={$y}&amp;z={$z}&amp;s=Galil</url>
    </customMapSource>

    <customWmsMapSource>
    <name>林班界</name>
    <minZoom>0</minZoom>
    <maxZoom>20</maxZoom>
    <tileType>PNG</tileType>
    <tileUpdate>None</tileUpdate>
    <layers>hws:linbanjie</layers>
    <url>http://192.168.1.230:8082/geoserver/hws/wms?service=WMS&amp;transparent=TRUE&amp;</url>
    <!-- 投影坐标系 -->
    <coordinatesystem>EPSG:4326</coordinatesystem>
    <aditionalparameters></aditionalparameters>
    </customWmsMapSource>

    <customWmsMapSource>
    <name>巡护路线</name>
    <minZoom>0</minZoom>
    <maxZoom>20</maxZoom>
    <tileType>PNG</tileType>
    <tileUpdate>None</tileUpdate>
    <!-- 图层名字hws(工作空间):china_net(图层名字) -->
    <layers>hws:xunhuluxian</layers>
    <!-- hws替换为自己的工作区间,ip端口替换自己服务器的,其他不变 -->
    <!-- 多参数,每个参数用&amp;分开-->
    <!-- 背景设置透明transparent=TRUE-->
    <url>http://192.168.1.230:8082/geoserver/hws/wms?service=WMS&amp;transparent=TRUE&amp;</url>
    </customWmsMapSource>
    </layers>
    </customMultiLayerMapSource>
离线地图自定义地图源(google地图)
  1. Mobile Atlas Creator工具目录的mapsources目录添加地图源配置文件

  2. google地图地图源配置文件google_maps.xml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    <?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
    <customMultiLayerMapSource>
    <name>Google 卫星</name>
    <tileType>PNG</tileType>
    <layers>
    <customMapSource>
    <name>Google 卫星图</name>
    <minZoom>0</minZoom>
    <maxZoom>20</maxZoom>
    <tileType>PNG</tileType>
    <tileUpdate>None</tileUpdate>
    <url>http://mt0.google.cn/vt/lyrs=s@124&amp;hl=zh-CN&amp;gl=CN&amp;src=app&amp;x={$x}&amp;s=&amp;y={$y}&amp;z={$z}&amp;s=Galileo</url>
    <backgroundColor>#000000</backgroundColor>
    </customMapSource>
    <customMapSource>
    <name>Google 地名图</name>
    <minZoom>0</minZoom>
    <maxZoom>20</maxZoom>
    <tileType>PNG</tileType>
    <tileUpdate>None</tileUpdate>
    <url>http://mt0.google.cn/vt/imgtp=png32&amp;lyrs=h@207000000&amp;hl=zh-CN&amp;gl=CN&amp;src=app&amp;x={$x}&amp;y={$y}&amp;z={$z}&amp;s=Galil</url>
    </customMapSource>
    </layers>
    </customMultiLayerMapSource>
  3. 地图源文件xml的设置搜索Mobile Atlas Creator自定义地图源

    IPad 離線地圖:「Mobile Atlas Creator + 地圖加加」,讓google map成為好用的離線地圖!!

Android代码设置

  1. 导包compile 'org.osmdroid:osmdroid-android:<VERSION>'

  2. 手动设置离线地图的文件

    1
    2
    3
    4
    5
    6
    7
    //路径压缩包的路径放在存储目录下/osmdroid/Google Maps(世界墨卡托).zip这个是刚刚用工具制作得到的压缩文件
    String path=Environment.getExternalStorageDirectory().getAbsolutePath() + "/osmdroid/"+"Google Maps(世界墨卡托).zip";
    //设置为离线工作模式。路径一定要对,而且只支持 ZIP/SQLite/GEMF
    mapView.setTileProvider(new OfflineTileProvider(new SimpleRegisterReceiver(this),new File[]{new File(path)}));
    //这里Google Map为压缩文件的第一层目录名,一定要一致,.png.tile为最内层目录的文件后缀名一点定要一致,一般是png,这里比较特殊
    mapView.setTileSource(new XYTileSource("Google Map", 7, 16,
    256, ".png.tile", null));
  3. 上面那步基本就可以解析了,官方使用SampleOfflineOnly.java做自动解析

    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
    //设置离线地图的路径
    File f = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/osmdroid/");
    if (f.exists()) { //判断目录是否存在
    File[] list = f.listFiles(); //得到该目录下的文件
    if (list != null) {
    for (int i = 0; i < list.length; i++) { //遍历的得到的所有目录和文件
    if (list[i].isDirectory()) { //目录跳过
    continue;
    }
    String name = list[i].getName().toLowerCase();
    if (!name.contains(".")) { //没有后缀跳过
    continue; //skip files without an extension
    }
    name = name.substring(name.lastIndexOf(".") + 1); //得到后缀名
    if (name.length() == 0) {
    continue;
    }
    if (ArchiveFileFactory.isFileExtensionRegistered(name)) { //后缀名是否是ZIP/SQLite/GEMF其中一个
    try {
    OfflineTileProvider tileProvider = new OfflineTileProvider(new SimpleRegisterReceiver(this),
    new File[]{list[i]}); //如果是把该文件作为离线地图的提供者
    mapView.setTileProvider(tileProvider); // <重要>
    String source = "";
    IArchiveFile[] archives = tileProvider.getArchives();
    if (archives.length > 0) {
    Set<String> tileSources = archives[0].getTileSources();
    if (!tileSources.isEmpty()) {
    source = tileSources.iterator().next(); //活动压缩文件第一级目录的目录名
    //自定义设置 <重要> ,其中文件后缀名要和压缩文件内的后缀一致
    this.mapView.setTileSource(new FileBasedTileSource(source,0, 18, 256, ".png", null));
    // this.mapView.setTileSource(FileBasedTileSource.getSource(source)); //默认设置
    } else {
    this.mapView.setTileSource(TileSourceFactory.DEFAULT_TILE_SOURCE);
    }
    } else {
    this.mapView.setTileSource(TileSourceFactory.DEFAULT_TILE_SOURCE);
    }
    this.mapView.invalidate();
    return;
    } catch (Exception ex) {
    ex.printStackTrace();
    }
    }
    }
    }
    Toast.makeText(this, f.getAbsolutePath() + " did not have any files I can open! Try using MOBAC", Toast.LENGTH_SHORT).show();
    } else {
    Toast.makeText(this, f.getAbsolutePath() + " dir not found!", Toast.LENGTH_SHORT).show();
    }

常见问题

  1. 当mobac配置多图层时,geoserver wms不加transparent=TRUE&amp;会有白色背景,设置透明度会导致最底层的地图上覆盖了一层半透明的白色,导致看不起低图
  2. mobac加载geoserver gwc连接,如果图层只有一部分,会导致Google map在图层之外的也加载不出来
参考

How to use Custom map in MOBAC?

简介

官网

全平台通用数据库

  1. 特点自带通知
  2. 实体类方式

使用

  1. 在project中的build.gradle添加

    1
    2
    3
    dependencies {
    classpath "io.realm:realm-gradle-plugin:5.1.0"
    }
  2. 在model中的build.gradle添加

    1
    apply plugin: 'realm-android'
  3. 新建实体类,两种方式

    方式一

    1
    2
    3
    4
    5
    @RealmClass
    public class TestEntiy implements RealmModel {
    private Long id;
    ......
    }

    方式二

    1
    2
    3
    4
    public class TestEntiy extends RealmModel {
    private Long id;
    ......
    }
  4. 在application中初始化realm

    1
    2
    3
    4
    5
    6
    7
    Realm.init(context); //数据库初始化
    RealmConfiguration config = new RealmConfiguration.Builder().name("mulun.realm").build();
    Realm.setDefaultConfiguration(config); //设置配置,数据库文件名为mulun.realm
    //测试
    Realm realm = Realm.getDefaultInstance(); //获取数据库实例
    Log.i("MyApplication","数据库路径为:"+realm.getPath()); //打印路径
    realm.close(); //用完需要关闭实例
  5. 在data/data/包名/file目录下可以找到数据库文件mulun.realm

  6. 该文件可以通过Realm Studio打开

进阶

数据库插入/删除数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Realm realm = Realm.getDefaultInstance(); //获取数据库实例
//方式一
TestEntiy testEntiy=new TestEntiy();
realm.executeTransaction(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
realm.copyToRealm(testEntiy);
}
});
//查询删除数据,该查询是异步的,如果数据testEntiy发生了修改和增加会在这里收到通知
realm.where(TestEntiy.class).findAllAsync().asFlowable().subscribe(new Consumer<RealmResults<TestEntiy>>() {
@Override
public void accept(final RealmResults<TestEntiy> testEntiy) throws Exception {
TestEntiy testEntiyRes = realm.copyFromRealm(testEntiy); //此种方式才能真正取到实体类,不能直接用testEntiy
realm.executeTransaction(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
testEntiy.deleteAllFromRealm(); //上传失败删除数据
}
});
}
}
realm.close();

另一种操作方式

1
2
3
4
5
Realm realm = Realm.getDefaultInstance(); //获取数据库实例
realm.beginTransaction();
realm.copyToRealm(testEntiy);
realm.commitTransaction();
realm.close();

简介

github文档:jenkinsci/docker

jenkins官网

Docker hub:jenkins/jenkins

蓝色主题版:jenkinsci/blueocean

安装

脚本文件https://github.com/xuanfong1/config/blob/master/dockerStack/stack-jenkins.yml

创建挂载目录

启动提示:

1
2
3
touch: cannot touch '/var/jenkins_home/copy_reference_file.log': Permission denied

Can not write to /var/jenkins_home/copy_reference_file.log. Wrong volume permissions?

解决:执行chown -R 1000:1000 /dockerdata/v-jenkins/jenkins_home改变用户组为1000 用户1000

jenkins 之docker插件

docker-build-step 构建步骤使用docker命令

CloudBees Docker Build and Publish镜像构建以及推送仓库

Docker 远程连接docker进行代理构建

Docker API提供其他插件docker服务api

CloudBees Docker Custom Build Environment构建镜像或从仓库拉去镜像

Docker Swarm集群

https://github.com/boxboat/jenkins-demo

错误处理

  1. 连接错误,解决添加挂在卷"/var/run/docker.sock:/var/run/docker.sock"

    1
    2
    3
    Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?

    script returned exit code 1
  2. 连接没权限,解决

    1
    2
    3
    Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Post http://%2Fvar%2Frun%2Fdocker.sock/v1.35/build?buildargs=%7B%7D&cachefrom=%5B%5D&cgroupparent=&cpuperiod=0&cpuquota=0&cpusetcpus=&cpusetmems=&cpushares=0&dockerfile=Dockerfile&labels=%7B%7D&memory=0&memswap=0&networkmode=default&rm=1&session=6ec5bc5a7afd427649abb0a03b733c9586dd9271474c89359e31a3910ed971e8&shmsize=0&t=e5e2d0e18760db6972a9c42a9a81653e633ff131&target=&ulimits=null: dial unix /var/run/docker.sock: connect: permission denied

    script returned exit code 1

    执行sudo ls -la /var/run/docker.sock

    1
    srw-rw----. 1 root docker 0 5月  15 16:36 /var/run/docker.sock

    --group-add=$(stat -c %g /var/run/docker.sock)

    sudo usermod -a -G docker jenkins

    解决方案

    方案一

    改变socke所属的用户组

    用root用户进入jenkins容器

    执行chown :jenkins /var/run/docker.sock

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    -------------宿主机------------------------------
    [root@worker ~]# ls -la /var/run/docker.sock
    srw-rw----. 1 root docker 0 66 16:58 /var/run/docker.sock
    执行后
    [root@worker ~]# ls -la /var/run/docker.sock
    srw-rw----. 1 root 1000 0 66 16:58 /var/run/docker.sock
    ------------------jenkins容器---------------------
    srw-rw---- 1 root 994 0 Jun 6 08:58 var/run/docker.sock
    执行后
    srw-rw---- 1 root jenkins 0 Jun 6 08:58 var/run/docker.sock

    cat /etc/group查看用户组id

    自我理解:

    这里通过挂载卷的形式共享/var/run/docker.sock套接字,但是默认套接字属于root docker组,这里docker的组id为994,但是容器内没有994的组,所以直接显示994,最后执行这个chown :jenkins /var/run/docker.sock之后把组更改为乐jenkins组,但是默认宿主机是没有jenkins组,所以直接显示jenkins的id 1000,这里直接修改为jenkins用户组,虽然可以解决权限问题,不知道会不会影响其他的使用该sock套接字(隐患

    完善思路:

    新建个jenkins组

    添加docker用户到jenkins组

    但是发现

    宿主机id docker 没有docker用户

    且docker组没有任何用户,因此可以放心更改组,所以要不要新建组待考虑

    1
    2
    3
    4
    cat /etc/group #查看组信息
    cgred:x:995:
    docker:x:994:jenkins
    #组名:口令(默认空/*):组标识号(gid):组内用户列表
    方案二

    自我新思路

    宿主机创建个jenkins用户组指定id1000

    宿主机执行useradd -u 1000 jenkins

    然后执行sudo usermod -a -G docker jenkins

    失败,没有权限

    方案三(未实验)

    root用户可以访问docker,需要重写dockerfile

    1
    2
    FROM <base-image>
    USER root

    隐患:不知到用root用户登陆会不会影响jenkins的一些功能

    方案四(未实验)

    修改groupadd -g 994 docker,找不到命令

    然后执行usermod -a -G docker jenkins

    此法每次重启容器都会丢失配置,虽然可以通过挂载目录形式保存设置,太麻烦。

  3. Jenkins 第一次打开,一直显示启动中

    解决:

    修改jenkins_home/updates/default.json

    把 “connectionCheckUrl”:”http://www.google.com/" 改为 “connectionCheckUrl”:”http://www.baidu.com/"

    https://github.com/jenkinsci/docker/issues/263

centos 安装jenkins,需要jdk8

1
2
3
4
5
sudo wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat-stable/jenkins.repo
sudo rpm --import https://pkg.jenkins.io/redhat-stable/jenkins.io.key
yum install jenkins
sudo service jenkins start/stop/restart
sudo chkconfig jenkins on

简介

Apache Shiro是java的一个安全框架,和Spring Security比相对简单,功能简单,使用简单,适合小型简单的项目。

功能

  • Authentication:身份认证/登陆,验证用户身份
  • Authorization:授权,权限验证,验证已认证的用户是否拥有某个权限
  • session manager:会话管理
  • cryptography:加密
  • web support:web支持
  • caching:缓存
  • concurrency:多线程并发验证,即如在一个线程中开启另一个线程,能把权限自动传播过去;
  • testing:测试支持
  • run as:运行一个用户假装另一个用户的身份进行登陆
  • remember me:记住我密码功能

原理

graph LR
a[object/用户]-->b[SecurityManager/shiro]
b-->c[Realm/数据源]

简单体验登陆

  1. 在gradle引入依赖compile group: 'org.apache.shiro', name: 'shiro-core', version: '1.4.0'

  2. 在目录resources下新建一个shiro.ini文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # users 标签下面格式为
    # 用户名 = 密码,角色1,角色2,....,角色N
    [users]
    root = secret, admin
    guest = guest, guest
    test = 123456,test

    # roldes 角色标签下面格式为
    # 角色 = 权限1,权限2, ....权限N
    [roles]
    admin = *
  3. 创建登陆方法,IniSecurityManagerFactory该方法在1.4已经过期了,用下面的方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    //Factory<SecurityManager> factory=new IniSecurityManagerFactory("classpath:shiro.ini"); //此方法过期
    IniRealm iniRealm=new IniRealm("classpath:shiro.ini"); //读取shiro配置文件
    DefaultSecurityManager securityManager=new DefaultSecurityManager(iniRealm);
    SecurityUtils.setSecurityManager(securityManager);
    Subject currentUser=SecurityUtils.getSubject();
    if (!currentUser.isAuthenticated()){
    UsernamePasswordToken token=new UsernamePasswordToken("admin","1");
    token.setRememberMe(true);
    try {
    currentUser.login(token);
    }catch (UnknownAccountException una){
    System.out.print("用户名不存在"+una.getMessage());
    }catch (IncorrectCredentialsException ice){
    System.out.print("无效的认证"+ice.getMessage());
    }catch (LockedAccountException lae){
    System.out.print("你的账户被锁定"+lae.getMessage());
    }catch (AuthenticationException ae){
    System.out.print("未知错误"+ae.getMessage());
    }
    }

shiro名词概念解释

  • subject :当前操作的用户
  • SecurityManager :shiro框架核心,内部组件管理
  • realm : 连接桥梁,用于和用户数据,权限数据连接(来源文件、数据库)

xml配置

1
2
3
4
5
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realms" ref="customRealm"/>
<property name="cacheManager" ref="cacheManager"/>
<property name="sessionManager" ref="sessionManager"/>
</bean>

数据库表设计:

1529049788944

参考

Shiro权限控制框架入门

配置方式一xml

在resources目录dubbo-provider.xml配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<!--该提供者服务名称-->
<dubbo:application name="dubbo-provider"/>
<!--组播模式的注册中心,推荐用zookeeper-->
<!--<dubbo:registry address="zookeeper://10.14.1.7:2181"/>-->
<!--暴露的端口服务-->
<dubbo:protocol name="dubbo" port="20880"/>
<!--声明暴露服务公共接口类-->
<dubbo:service interface="exxk.dubbo.commonimpl.DemoService" ref="demoService"/>
<!--提供者实现类-->
<bean id="demoService" class="exxk.dubbo.provider.impl.DemoServiceImpl"/>
</beans>

需要在dubbo启动器指向xml名字

1
2
3
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
new String[]{"dubbo-provider.xml"}); //读取dubbo配置文件
context.start();

配置方式二dubbo.properties

注:配置文件名字是固定的

1
dubbo.registry.address=zookeeper://10.14.1.7:2181

配置方式三jvm

注:gradle application task run启动vm设置无效

1
-Ddubbo.registry.address=zookeeper://10.14.1.7:2181

覆盖策略

JVM>XML>Properties其中jvm优先级最高

源码:https://github.com/xuanfong1/DubboLearning

  1. 新建目录 mkdir DubboLearning,然后cd Dubbolearning进去之后执行gradle init初始化gradle项目

  2. 新建三个子项目目录mkdir library,provider,consumer 分别为公共依赖项目、提供者、消费者

  3. 复制build.gradle到三个子项目目录

  4. 分别为三个子项目创建目录mkdir -p src/main/java,src/test/java,src/main/resources

  5. 修改顶级项目目录的setting.gradle添加三个子项目

    1
    2
    3
    include 'library'
    inclede 'provider'
    inclede 'consumer'
  6. 复制项目helloworld的源码到项目目录

  7. 然后修改顶级项目目录build.gradle

    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
    plugins {
    id "org.springframework.boot" version "2.0.1.RELEASE"
    }
    allprojects {
    repositories {
    jcenter() //将jcenter仓库配置到所有项目
    }
    }
    subprojects {
    version = '1.0' //设置版本号
    }
    configure(subprojects.findAll {it.name == 'provider' || it.name == 'consumer'} ) {

    apply plugin: 'java'
    apply plugin: 'eclipse'
    apply plugin: "org.springframework.boot"
    apply plugin: 'io.spring.dependency-management'

    group = 'exxk.dubbo'
    version = '0.0.1-SNAPSHOT'
    sourceCompatibility = 1.8

    dependencies {
    compile('org.springframework.boot:spring-boot-starter')
    compile group: 'com.alibaba', name: 'dubbo', version: '2.6.1'
    testCompile('org.springframework.boot:spring-boot-starter-test')
    compile project(':library')
    }
    }

额外

https://plugins.gradle.org/plugin/org.springframework.boot

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//低版本,动态
buildscript {
ext {
springBootVersion = '2.0.1.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
//等效于
//高版本
plugins {
id "org.springframework.boot" version "2.0.2.RELEASE"
}

报错:

1
2
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/curator/RetryPolicy
at com.alibaba.dubbo.remoting.zookeeper.curator.CuratorZookeeperTransporter.connect(CuratorZookeeperTransporter.java:26)

解决:添加依赖compile group: 'org.apache.curator', name: 'curator-framework', version: '4.0.1'

gradle init --type <name>其中name可选

  • java-application
  • java-library
  • scala-library
  • groovy-library
  • basic

build java-library

This guide walks you through the process of using Gradle’s Build Init plugin to produce a JVM library which is suitable for consumption by other JVM libraries and applications.

本指南引导您完成使用Gradle的Build Init插件生成适合其他JVM库和应用程序使用的JVM库的过程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
mkdir demo-java-lib #创建项目目录
cd demo-java-lib
gradle init --type java-library #初始化构建为java-library
tree #查看生成的目录树
├── build.gradle
├── gradle
│   └── wrapper
│   ├── gradle-wrapper.jar
│   └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
└── src
├── main #java资源为件
│   └── java
│   └── Library.java
└── test #java测试文件
└── java
└── LibraryTest.java

build.gradle解读

1
2
3
4
5
6
7
8
9
10
11
12
13
14
plugins {
// Java Library依赖插件
id 'java-library'
}
dependencies {
// 依赖该api
api 'org.apache.commons:commons-math3:3.6.1'
implementation 'com.google.guava:guava:23.0'
testImplementation 'junit:junit:4.12'
}
repositories {
// 仓库
jcenter()
}

执行./gradew build第一次构建会下载依赖jar包比较慢,下载到目录~/.gradle/wrapper/dists,编译完成后生成

  • build/reports/tests/test/index.html 测试报告
  • build/libs/building-java-libraries.jar 编译生成的jar

jar tf build/libs/building-java-libraries.jar命令查看jar包内容,其中-f指定jar文件名,-t列出包的内容

修改build.gradle文件在文件里添加版本好version = '0.1.0',结果会修改打包的名称为build/libs/demo-java-lib-0.1.0.jar

修改build.gradle文件在文件里添加jar task任务

1
2
3
4
5
6
jar {
manifest {
attributes('Implementation-Title': project.name,
'Implementation-Version': project.version)
}
}

会修改build/libs/building-java-libraries-0.1.0.jar/META-INF/MANIFEST.MFjar包文件的内容为

1
2
3
Manifest-Version: 1.0
Implementation-Title: demo-java-lib
Implementation-Version: 0.1.0

java-library内置支持javadoc,执行./gradlew javadoc会生成/build/docs/javadoc/index.html文档

build java-application

java项目和library项目一样,只是多了tasks任务 run

多项目构建

初始化顶级项目
  1. 项目初始化

    1
    2
    3
    mkdir multi-project
    cd multi-project
    gradle init
  2. 顶级构建,也就是采用跟项目的配置,从而减少子项目的重复配置,可以把子项目的公共配置抽离到跟项目配置里。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    //跟项目build.gradle添加
    allprojects {
    repositories {
    jcenter() //将jcenter仓库配置到所有项目
    }
    }
    subprojects {
    version = '1.0' //设置版本号
    }
添加Groovy library子项目
  1. 执行mkdir multi-library创建一个子项目名为multi-library

  2. 进入multi-library子项目根目录,新建一个build.gradle

    1
    2
    3
    4
    5
    6
    7
    8
    //multi-library/build.gradle
    apply plugin : 'groovy'
    dependencies {
    compile 'org.codehaus.groovy:groovy:2.4.10'
    testCompile 'org.spockframework:spock-core:1.0-groovy-2.4', {
    exclude module : 'groovy-all'
    }
    }
  3. 修改顶级项目根项目的settings.gradle,添加include 'multi-library'

  4. 完善子项目,创建两个目录mkdir -p multi-library/src/main/groovy/greetermkdir -p multi-library/src/test/groovy/greeter

  5. 在目录src/main/groovy/greeter新建GreetingFormatter.groovy文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    //multi-library/src/main/groovy/greeter/GreetingFormatter.groovy
    package greeter
    import groovy.transform.CompileStatic
    @CompileStatic
    class GreetingFormatter {
    static String greeting(final String name) {
    "Hello, ${name.capitalize()}"
    }
    }
  6. 在目录src/test/groovy/greeter新建GreetingFormatterSpec.groovy文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    //multi-library/src/test/groovy/greeter/GreetingFormatterSpec.groovy
    package greeter
    import spock.lang.Specification
    class GreetingFormatterSpec extends Specification {
    def 'Creating a greeting'() {
    expect: 'The greeting to be correctly capitalized'
    GreetingFormatter.greeting('gradlephant') == 'Hello, Gradlephant'

    }
    }
  7. 最后在顶级项目的根目录运行./gradlew build,到此一个项目依赖一个子项目就完成了

添加一个java 子项目
  1. 执行mkdir java-demo创建一个子项目名为java-demo

  2. 进入java-demo子项目根目录,新建一个build.gradle

    1
    2
    apply plugin : 'java' 
    apply plugin : 'application'
  3. 完善子项目,创建目录mkdir -p java-demo/src/main/java/greeter

  4. 修改顶级项目根项目的settings.gradle,添加include 'java-demo'

  5. 在目录java-demo/src/main/java/greeter新建Greeter.java文件

    1
    2
    3
    4
    5
    6
    7
    8
    package greeter;

    public class Greeter {
    public static void main(String[] args) {
    final String output = GreetingFormatter.greeting(args[0]);
    System.out.println(output);
    }
    }
  6. 进入java-demo子项目根目录,修改build.gradle

    1
    2
    3
    apply plugin : 'java' 
    apply plugin : 'application'
    mainClassName = 'greeter.Greeter'
  7. 最后在顶级项目的根目录运行./gradlew build,会出现依赖错误

    1
    2
    3
    * What went wrong:
    Execution failed for task ':java-demo:compileJava'.
    > Compilation failed; see the compiler error output for details.
  8. 解决,进入java-demo子项目根目录,修改build.gradle

    1
    2
    3
    4
    5
    6
    apply plugin : 'java' 
    apply plugin : 'application'
    mainClassName = 'greeter.Greeter'
    dependencies {
    compile project(':multi-library')
    }
  9. 重新执行./gradlew build,编译成功

  10. 添加test测试编译,进入java-demo子项目根目录,修改build.gradle

1
2
3
4
5
6
7
8
9
10
apply plugin : 'java' 
apply plugin : 'application'
apply plugin : 'groovy'
mainClassName = 'greeter.Greeter'
dependencies {
compile project(':multi-library')
testCompile 'org.spockframework:spock-core:1.0-groovy-2.4', {
exclude module : 'groovy-all'
}
}
  1. 创建测试目录mkdir -p java-demo/src/test/groovy/greeter,添加GreeterSpec.groovy文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    //java-demo/src/test/groovy/greeter/GreeterSpec.groovy
    package greeter

    import spock.lang.Specification

    class GreeterSpec extends Specification {

    def 'Calling the entry point'() {

    setup: 'Re-route standard out'
    def buf = new ByteArrayOutputStream(1024)
    System.out = new PrintStream(buf)

    when: 'The entrypoint is executed'
    Greeter.main('gradlephant')

    then: 'The correct greeting is output'
    buf.toString() == "Hello, Gradlephant\n".denormalize()
    }
    }
  2. 单项目编译,执行./gradlew :java-demo:test 其中java-demo为项目名,test为那种编译类型,也可以执行去子项目跟目录执行../gradlew test进行单模块编译

添加文档子项目
  1. 在顶级项目的build.gradle添加插件asciidoctor该插件的作用主要是将文档生成网页文件

    1
    2
    3
    4
    plugins {
    //apply false将插件添加到整个项目中,但不会将其添加到根项目中。
    id 'org.asciidoctor.convert' version '1.5.6' apply false //文档插件
    }
  2. 创建文档项目目录,在顶级项目跟目录,执行mkdir docs

  3. 然后在docs目录新建个build.gradle,在里头添加如下内容

    1
    2
    3
    4
    5
    6
    7
    8
    9
    apply plugin : 'org.asciidoctor.convert'  //将插件用于该子项目
    //asciidoctor任务
    asciidoctor {
    sources {
    include 'greeter.adoc' //文档资源文件,需要自己新建
    }
    }
    //将asciidoctor任务添加到构建生命周期中,以便如果为顶级项目执行构建,则也将构建文档。
    build.dependsOn 'asciidoctor'
  4. 修改顶级项目根项目的settings.gradle,添加include 'docs'

  5. 然后新建个文档docs/src/docs/asciidoc/greeter.adoc,没有该目录创建就行,内容随便,后面会把此文件文档转为网页文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    = Greeter Command-line Application

    A simple application demonstrating the flexibility of a Gradle multi-project.

    == Installation

    Unpack the ZIP or TAR file in a suitable location

    == Usage

    [listing]
    ----
    $ cd greeter-1.0
    $ ./bin/greeter gradlephant

    Hello, Gradlephant
    ----
  6. 然后在顶级项目跟目录,运行task任务asciidoctor,执行./gradlew asciidoctor

  7. 会在目录docs/build/asciidoc/html5目录生成网页文件greeter.html

将文档包含到发布的项目
  1. 要将文档包含到发布的项目的目录可以新建task任务即可,修改java-demo项目的配置文件build.gradle增加如下内容

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    distZip {
    from project(':docs').asciidoctor, {
    into "${project.name}-${version}"
    }
    }
    distTar {
    from project(':docs').asciidoctor, {
    into "${project.name}-${version}"
    }
    }
  2. 然后重新编译文件即可,在顶级项目跟目录执行./gradlew build

  3. 最后会在java-demo//build/distributions目录生成两个greeter-1.0.zipgreeter-1.0.tar,里面包含了编译好了的网页文件

整理顶级构建脚本

在java-demo和muilt-library项目中有相同的配置,这里把他们抽到顶级项目里配置

  1. 在顶级项目的build.gradle里添加公共配置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    configure(subprojects.findAll {it.name == 'java-demo' || it.name == 'multi-library'} ) { //指定配置那些项目

    apply plugin : 'groovy'
    dependencies {
    testCompile 'org.spockframework:spock-core:1.0-groovy-2.4', {
    exclude module : 'groovy-all'
    }
    }
    }
  2. 删除子项目公有的配置,最终所有build.gradle配置如下

    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
    //顶级项目build.gradle
    plugins {
    //apply false将插件添加到整个项目中,但不会将其添加到根项目中。
    id 'org.asciidoctor.convert' version '1.5.6' apply false //文档插件
    }
    allprojects {
    repositories {
    jcenter() //将jcenter仓库配置到所有项目
    }
    }
    subprojects {
    version = '1.0' //设置版本号
    }
    configure(subprojects.findAll {it.name == 'java-demo' || it.name == 'multi-library'} ) {

    apply plugin : 'groovy'

    dependencies {
    testCompile 'org.spockframework:spock-core:1.0-groovy-2.4', {
    exclude module : 'groovy-all'
    }
    }
    }
    //----------------------------------------------------------
    //multi-library项目build.gradle
    dependencies {
    compile 'org.codehaus.groovy:groovy:2.4.10'
    }
    //-----------------------------------------------------------
    //java-demo项目build.gradle
    apply plugin : 'java'
    apply plugin : 'application'
    mainClassName = 'greeter.Greeter'

    dependencies {
    compile project(':multi-library')
    }

    distZip {
    from project(':docs').asciidoctor, {
    into "${project.name}-${version}"
    }
    }
    distTar {
    from project(':docs').asciidoctor, {
    into "${project.name}-${version}"
    }
    }
  3. 最后执行./gradlew clean build重新构建

总结

  1. 子项目只需build.gradle配置即可,且子项目不能gradle init

  2. 要父项目包含子项目,需要在setting.gradle设置include '项目名'

  3. 子项目依赖其他子项目只需要设置compile project(':子项目名')

  4. 插件需要在最顶部定义

  5. 运行单模块执行./gradlew :子项目名:构建命令构建命令目前包括test、build、clean

  6. 抽离子项目共有配置到父项目用configure

  7. 常用命令

    1
    gradle :eurekaserver:build //执行子项目eurekaserver构建build命令