首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

Gradle 構建 Java Web 專案與 Jenkins 持續整合完整實戰

     編輯:Java 綜合教學

工具鏈準備

  • JDK 11/17/21
  • Gradle 7.6+ (Wrapper 推薦)
  • Eclipse + Buildship 插件 / IntelliJ IDEA (內建支援)
  • Jenkins 2.400+ + Git + Maven/Gradle 插件

Eclipse Buildship 整合

  1. 安裝:Help → Eclipse Marketplace → 搜尋 Buildship → Install。
  2. 可選:Minimalist Gradle Editor 提供 build.gradle 語法高亮。

建立 Gradle Java Web 專案

方式一:IDE 建立 (Buildship)

  1. File → New → Other → Gradle → Gradle Project
  2. 專案名、位置、選擇本地 Gradle 發佈版
  3. Finish → 觸發 gradle init --type java-library
  4. 轉為 Web 專案:專案右鍵 → Properties → Project Facets → 勾選 Dynamic Web Module、Java、JavaScript

方式二:手動建立標準目錄結構

my-webapp/
├── build.gradle
├── settings.gradle
├── src/
│   ├── main/
│   │   ├── java/com/example/
│   │   ├── resources/          # 配置檔、Mapper XML
│   │   └── webapp/             # Web 資源
│   │       ├── WEB-INF/web.xml
│   │       ├── static/         # CSS/JS/圖片
│   │       └── index.jsp
│   └── test/
│       ├── java/
│       └── resources/
└── gradle/wrapper/             # Gradle Wrapper

核心 build.gradle 配置

plugins {
    id 'war'                    // WAR 打包
    id 'org.akhikhl.gretty' version '3.0.2'  // 內嵌容器運行/測試
    id 'org.hidetake.ssh' version '2.10.0'   // SSH 部署
}

group = 'com.example'
version = '1.0.0-SNAPSHOT'
description = 'Gradle Java Web Demo'

java {
    sourceCompatibility = JavaVersion.VERSION_17
    targetCompatibility = JavaVersion.VERSION_17
}

repositories {
    mavenLocal()
    mavenCentral()
    maven { url 'https://maven.aliyun.com/repository/public' } // 國內鏡像
    gradlePluginPortal()
}

dependencies {
    // Servlet API (providedCompile 在 Gradle 7+ 為 compileOnly)
    compileOnly 'jakarta.servlet:jakarta.servlet-api:5.0.0'
    // 或舊版 javax.servlet:javax.servlet-api:4.0.1

    // Spring MVC
    implementation 'org.springframework:spring-webmvc:5.3.30'
    implementation 'org.springframework:spring-jdbc:5.3.30'
    implementation 'org.springframework:spring-tx:5.3.30'
    implementation 'org.springframework:spring-context-support:5.3.30'

    // MyBatis
    implementation 'org.mybatis:mybatis:3.5.13'
    implementation 'org.mybatis:mybatis-spring:2.0.7'

    // 連線池
    implementation 'com.alibaba:druid:1.2.20'

    // JSON
    implementation 'com.fasterxml.jackson.core:jackson-databind:2.15.2'

    // 日誌
    implementation 'org.slf4j:slf4j-api:2.0.9'
    implementation 'ch.qos.logback:logback-classic:1.4.11'

    // 測試
    testImplementation 'org.junit.jupiter:junit-jupiter:5.10.1'
    testImplementation 'org.mockito:mockito-core:5.5.1'
    testImplementation 'org.springframework:spring-test:5.3.30'
}

gretty {
    servletContainer = 'tomcat9'  // 或 jetty9
    contextPath = '/myapp'
    httpPort = 8080
    httpsPort = 8443
    fastReload = true             // 類變更熱重載
    reloadOnClassChange = true
    enableNaming = true           // JNDI 支援
    managedClassReload = true     // 受管類重載
}

war {
    archiveFileName = "${project.name}-${version}.war"
    // 包含額外資源 (如本地 lib 目錄)
    from('src/main/webapp') { into 'WEB-INF' }
    // from('lib') { into 'WEB-INF/lib' } // 若有本地 JAR
}

tasks.withType(Test) {
    useJUnitPlatform()
    testLogging {
        events "passed", "skipped", "failed", "standardOut", "standardError"
    }
}

自定義任務:關機、清理、複製、啟動 (SSH 部署)

// 關閉遠端 Tomcat
task shutdownTomcat {
    doLast {
        ssh.run {
            session(remotes.deployServer) {
                println 'Shutting down Tomcat...'
                executeScript '''#!/bin/bash
                    cd /opt/tomcat/bin
                    ./shutdown.sh
                    sleep 5
                    # 強制殺殘留進程
                    pkill -f "tomcat"
                '''
            }
        }
    }
}

// 清理舊部署
task cleanDeploy(dependsOn: shutdownTomcat) {
    doLast {
        ssh.run {
            session(remotes.deployServer) {
                println 'Cleaning old deployment...'
                executeScript '''#!/bin/bash
                    rm -rf /opt/tomcat/webapps/myapp
                    rm -f /opt/tomcat/webapps/myapp.war
                '''
            }
        }
    }
}

// 複製 WAR
task copyWar(dependsOn: cleanDeploy) {
    doLast {
        ssh.run {
            session(remotes.deployServer) {
                println 'Copying WAR...'
                put from: "build/libs/${war.archiveFileName.get()}", into: '/opt/tomcat/webapps'
            }
        }
    }
}

// 啟動 Tomcat
task startTomcat(dependsOn: copyWar) {
    doLast {
        ssh.run {
            session(remotes.deployServer) {
                println 'Starting Tomcat...'
                execute '/opt/tomcat/bin/startup.sh'
            }
        }
    }
}

// 一鍵部署
task deploy(dependsOn: startTomcat) {
    group = 'Deployment'
    description = 'Full deployment pipeline: shutdown → clean → copy → start'
}

// SSH 配置
ssh.settings {
    knownHosts = allowAnyHosts // 僅測試環境,生產請配置 known_hosts
}
remotes {
    deployServer {
        host = '192.168.1.100'
        user = 'deploy'
        password = 'deploy123' // 建議使用 SSH Key
        identity = file('~/.ssh/id_rsa') // 金鑰路徑
    }
}

執行 Gradle 任務

  • IDE:Gradle 任務視圖 → 雙擊任務 (如 war、gretty:run、deploy)
  • 命令列:./gradlew war、./gradlew gretty:run、./gradlew deploy
  • Wrapper 確保團隊版本一致:./gradlew wrapper --gradle-version 8.5

Jenkins Pipeline 配置

1. 安裝插件

  • Pipeline / Pipeline Stage View
  • Git / GitHub / GitLab
  • Gradle (或使用 Wrapper 無需安裝)
  • SSH Agent / Publish Over SSH (部署用)

2. Jenkinsfile (宣告式 Pipeline)

pipeline {
    agent any
    tools {
        // 若 Jenkins 全域配置了 Gradle,可指定版本名
        // gradle 'Gradle 8.5'
    }
    environment {
        GRADLE_OPTS = '-Dorg.gradle.daemon=false -Dorg.gradle.parallel=true'
    }
    stages {
        stage('Checkout') {
            steps {
                checkout scm
            }
        }
        stage('Build & Test') {
            steps {
                sh './gradlew clean test --info'
            }
            post {
                always {
                    junit 'build/test-results/test/**/*.xml'
                }
            }
        }
        stage('Package WAR') {
            steps {
                sh './gradlew war -x test'
                archiveArtifacts artifacts: 'build/libs/*.war', fingerprint: true
            }
        }
        stage('Deploy Staging') {
            when { branch 'develop' }
            steps {
                sh './gradlew deploy -Penv=staging'
            }
        }
        stage('Deploy Production') {
            when { branch 'main' }
            steps {
                input message: 'Confirm production deployment?', ok: 'Deploy'
                sh './gradlew deploy -Penv=prod'
            }
        }
    }
    post {
        always {
            cleanWs()
        }
        failure {
            mail to: 'team@example.com',
                 subject: "Build Failed: ${env.JOB_NAME} #${env.BUILD_NUMBER}",
                 body: "Check console: ${env.BUILD_URL}"
        }
    }
}

3. 多環境參數化

// build.gradle 讀取 -Penv
def env = project.hasProperty('env') ? project.env : 'dev'
def deployConfig = [
    dev:      [host: '192.168.1.10', user: 'dev', key: '~/.ssh/id_rsa_dev'],
    staging:  [host: '192.168.1.20', user: 'stage', key: '~/.ssh/id_rsa_stage'],
    prod:     [host: '192.168.1.30', user: 'prod', key: '~/.ssh/id_rsa_prod']
][env]

remotes {
    deployServer {
        host = deployConfig.host
        user = deployConfig.user
        identity = file(deployConfig.key)
    }
}

進階優化技巧

  1. 配置快取:gradle.properties 設 org.gradle.caching=true、org.gradle.parallel=true、org.gradle.daemon=true (本地開發)。
  2. 依賴鎖定:./gradlew dependencies --write-locks 生成 gradle.lockfile,提交版控確保可重現構建。
  3. 複合建構:settings.gradle includeBuild('../shared-lib') 替代發布快照版。
  4. 測試分類:test { useJUnitPlatform { includeTags 'unit' } }、task integrationTest(type: Test) { useJUnitPlatform { includeTags 'integration' } }。
  5. Docker 整合:plugins { id 'com.bmuschko.docker-remote-api' } 構建鏡像推送 Registry,Jenkins 部署改為 kubectl apply / docker stack deploy。

常見問題排查

問題解決
Gretty 熱重載不生效確認 fastReload=true、managedClassReload=true、IDE 啟用 Build Project Automatically
WAR 缺少依賴檢查 compileOnly vs implementation、war { classpath = configurations.runtimeClasspath }
Jenkins SSH 連線失敗憑證管理 → SSH Username with private key、Known hosts 驗證策略、防火牆/安全組放行 22
Gradle Daemon 記憶體溢出gradle.properties 加 org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m
多模組測試報告合併根 build.gradle 加 test { reports { html.enabled = true } }、Jenkins junit '**/build/test-results/**/*.xml'
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved