【问题标题】:How to add static files to jar using Gradle build in Spring Boot + Angular 2 project如何在 Spring Boot + Angular 2 项目中使用 Gradle 构建将静态文件添加到 jar
【发布时间】:2017-12-22 02:33:53
【问题描述】:

我有一个 Spring Boot + Angular 2 项目。我想将它部署到 Heroku。 我可以运行 npm 构建,然后手动将生成的文件复制到公共文件夹(src/resources/public),然后运行后端构建。 我想要做的是建立一个 gradle 构建,它会一次完成所有这些。 到目前为止,我所拥有的是一个 gradle 构建,它将构建前端,构建后端,但是它不会在生成 jar 之前复制静态文件。由于 jar 不包含上述静态文件,因此无法在 Heroku 上运行。

这是项目文件夹结构:

root
 backend
  src/main/java
  src/main/resources
 frontend
  --> angular files go here
 build/libs -> where the JAR file goes

gradle 构建文件:

buildscript {
repositories {
    mavenCentral()
}
dependencies {
    // spring
    classpath('org.springframework.boot:spring-boot-gradle-plugin:1.5.2.RELEASE')
    classpath('org.springframework:springloaded:1.2.6.RELEASE')
    }
}

plugins {
    id "com.moowork.node" version "1.2.0"
}

// gradle wrapper
task wrapper(type: Wrapper) {
    gradleVersion = '3.4'
}

// configure gradle-node-plugin
node {
    version = '8.1.4'
    npmVersion = '5.0.3'
    download = true
    workDir = file("${project.projectDir}/node")
    nodeModulesDir = file("${project.projectDir}/")
}

// clean node/node_modules/dist
task npmClean(type: Delete) {
    final def webDir = "${rootDir}/frontend"
    delete "${webDir}/node"
    delete "${webDir}/node_modules"
    delete "${webDir}/dist"
    delete "${webDir}/coverage"
    delete "${rootDir}/backend/src/main/resources/public"
}

// clean task for npm

task copyFiles {
    doLast {
        copy {
            from "${rootDir}/frontend/dist"
            into "${rootDir}/backend/src/main/resources/public"
        }
    }    
}

// build task for npm
task frontendBuild {}
frontendBuild.dependsOn(npm_install)
frontendBuild.dependsOn(npm_run_build)

npm_install {
  args = ['--prefix', './frontend']
}

npm_run_build {
  args = ['--prefix', './frontend']
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'org.springframework.boot'

sourceSets {
    main {
        java {
            srcDirs = ['backend/src/main/java']
        }
        resources {
            srcDirs = ['backend/src/main/resources']
        }
    }
}

copyFiles.dependsOn(frontendBuild);
compileJava.dependsOn(frontendBuild);

task backendBuild {}
backendBuild.dependsOn(compileJava)
backendBuild.dependsOn(jar)

jar.dependsOn(copyFiles)

repositories {
    mavenCentral()
}

eclipse {
    classpath {
         containers.remove('org.eclipse.jdt.launching.JRE_CONTAINER')
         containers('org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8')
    }
}

idea {
    module {
        inheritOutputDirs = false
        outputDir = file("${buildDir}/classes/main/")
    }
}

jar {
    baseName = 'expense-splitter'
    version = '0.0.1'
}

sourceCompatibility = 1.8
targetCompatibility = 1.8

configurations {
    dev
}

dependencies {
    // spring
    compile('org.springframework.boot:spring-boot-starter-web:1.5.2.RELEASE')
    compile('org.springframework.boot:spring-boot-starter-data-jpa:1.5.2.RELEASE')
    compile('org.springframework.boot:spring-boot-starter-security:1.5.2.RELEASE')

    compile('org.apache.commons:commons-lang3:3.3.2')

    // to make hibernate handle java 8 date and time types correctly
    // it's marked as deprecated but we need to keep it until
    // spring boot jpa starts using hibernate 5.2
    compile('org.hibernate:hibernate-java8:5.1.0.Final')

    // json web tokens
    compile ('io.jsonwebtoken:jjwt:0.7.0')

    compile 'mysql:mysql-connector-java'
    // google gson
    compile('com.google.code.gson:gson:2.8.0')
    // jackson - parsing of java 8 date and time types
    compile('com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.8.7')


    // spring dev tools
    dev('org.springframework.boot:spring-boot-devtools:1.5.2.RELEASE')

    // testing
    testCompile('org.springframework.boot:spring-boot-starter-test:1.5.2.RELEASE')
}

// run spring boot app
bootRun {
    //addResources = true
    classpath = sourceSets.main.runtimeClasspath + configurations.dev
    jvmArgs = ["-Xdebug -agentlib:jdwp=transport=dt_socket,address=8080,server=y,suspend=n"]
}

// run all task
task runAll {}
runAll.dependsOn(bootRun)

提前致谢,

【问题讨论】:

    标签: java angular spring-boot heroku gradle


    【解决方案1】:

    假设前端位于以下文件夹:src/main/webapp/fe-ui/,则可以考虑 Spring Boot 版本 2.1.1.RELEASE 的以下解决方案:

    bootJar {
        baseName = 'jar-name'
        version = '0.1.0'
        from('src/main/webapp/fe-ui/build') {
            into 'public'
        }
    }
    
    task installFeDependencies(type: NpmTask) {
        args = ['install']
    }
    
    task buildFe(type: NpmTask) {
        args = ['run', 'build']
        dependsOn installFeDependencies
    }
    
    compileJava {
        dependsOn buildFe
    }
    

    运行gradlew build 将安装、构建前端以及调用bootJar。后者将打包构建的前端包。

    【讨论】:

      【解决方案2】:

      Spring Boot 1.5\2.x + Angular 2-6 的 Gradle 配置

      子文件夹frontend中的Angular

      前端模块

      板条箱build.gradle:

      plugins {
        id "com.moowork.node" version "1.2.0"
      }
      
      node {
        version = '8.11.3'
        npmVersion = '5.6.0'
        download = true
        workDir = file("${project.buildDir}/node")
        nodeModulesDir = file("${project.projectDir}")
      }
      
      task build(type: NpmTask) {
        args = ['run', 'build']
      }
      
      build.dependsOn(npm_install)
      

      Angular 6 的注意事项

      angular.json 中的outputPath 值更新为“dist”

      后端模块

      为后端模块编辑build.gradle

      Spring Boot 2.X:

      bootJar {
          archiveName = "yourapp.jar"
          mainClassName = 'com.company.app.Application'
      
          from('frontend/dist') {
              into 'static'
          }
      }
      

      Spring Boot 1.5.X:

      jar {
          archiveName = "yourapp.jar"
          manifest {
              attributes 'Main-Class': 'com.company.app.Application'
          }
          from('frontend/dist') {
              into 'static'
          }
          from {
              configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
          }
      }
      

      最后执行bootRepackagebootJar任务并查看builds/libs中的结果

      【讨论】:

      • bootJar 为我工作。我更喜欢它,因为我只想在捆绑到 jar 时复制我编译的 react js 文件。谢谢。
      【解决方案3】:

      尝试不同的方法。不要手动复制资源,而是告诉 Gradle 在处理 JAR 资源时,还要考虑 frontend/dist/ 中的内容:

      processResources {
          from ('frontend/dist/') {
              into 'public'
          }
      }
      

      这应该会生成一个包含 public/ 目录的 JAR,其中包含 frontend/dist/ 的内容。

      【讨论】:

      • war 文件还需要修改吗?
      猜你喜欢
      • 2019-06-08
      • 1970-01-01
      • 2018-11-11
      • 2021-02-20
      • 2017-11-03
      • 2016-02-08
      • 1970-01-01
      • 2018-06-24
      • 2020-04-13
      相关资源
      最近更新 更多