java 如何在 Spring Boot + Angular 2 项目中使用 Gradle 构建将静态文件添加到 jar

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/45146201/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 08:32:48  来源:igfitidea点击:

How to add static files to jar using Gradle build in Spring Boot + Angular 2 project

javaangularspring-bootherokugradle

提问by fpezzini

I have a Spring Boot + Angular 2 project. I want to deploy it to Heroku. I'm able to run the npm build then copy the generated files over to the public folder (src/resources/public) manually, then run the backend build. What I want to do is to set up a gradle build that will do all of that at once. What I have so far is a gradle build that will build the front end, build the backend, however it does not copy the static files before generating the jar. Since the jar does not contain said static files, it won't work on Heroku.

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

Here's the project folder structure:

这是项目文件夹结构:

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

The gradle build file:

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')
    // Hymanson - parsing of java 8 date and time types
    compile('com.fasterxml.Hymanson.datatype:Hymanson-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)

Thanks in advance,

提前致谢,

回答by nickb

Try a different approach. Instead of manually copying the resources, tell Gradle that when it processes resources for the JAR, also take into consideration what is in frontend/dist/:

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

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

This should result in a JAR containing a public/directory, with the contents of frontend/dist/inside of it.

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

回答by Evgeny Lebedev

Gradle configuration for Spring Boot 1.5\2.x + Angular 2-6

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

Angular in sub-folder frontend

子文件夹中的角度 frontend

Frontend module

前端模块

Crate build.gradle:

板条箱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)

Note for Angular 6

Angular 6 的注意事项

Update outputPathvalue in angular.jsonto 'dist'

outputPath值更新angular.json为“dist”

Backend module

后端模块

Edit build.gradlefor backend module:

编辑build.gradle后端模块:

Spring Boot 2.X:

春季启动 2.X:

bootJar {
    archiveName = "yourapp.jar"
    mainClassName = 'com.company.app.Application'

    from('frontend/dist') {
        into 'static'
    }
}

Spring Boot 1.5.X:

春季启动 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) }
    }
}

Finally execute bootRepackageor bootJartask and check results in builds/libs

最后执行bootRepackagebootJar任务并检查结果builds/libs

回答by mr.M

Assume that front end is located at the following folder: src/main/webapp/fe-ui/, the following solution for the Spring Boot version 2.1.1.RELEASE could be considered:

假设前端位于以下文件夹: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
}

Running gradlew buildwill install, build front end as well as will invoke bootJar. The latter will package built front end bundle.

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