ruoyi-vue是基于maven进行的多模块一体化打包,可以在该基础上转化为gradle一体化打包。同时也可以对ruoyi-vue进行多模块jar和resources分离打包。本文主要讲通过gradle多模块方式,进行jar和resources分离打包配置。
1、ruoyi-vue项目根目录配置
配置build.gradle 、settings.gradle和gradle.properties
build.gradle内容如下:
// 插件配置
plugins {
// 使用spring boot
id 'org.springframework.boot' version "${springboot_version}"
// spring boot的自动依赖管理
id 'io.spring.dependency-management' version '1.1.0'
}
// 全局配置
configure(allprojects) { project ->
group = PROJ_GROUP
version = PROJ_VERSION
apply plugin: "java"
apply plugin: "maven-publish"
apply plugin: "eclipse"
apply plugin: "idea"
apply plugin: "signing"
apply plugin: "java-library"
// apply plugin: "application"
// apply plugin: "maven"
// 应用依赖管理插件,自动给插件追加版本号(建议使用此配置),并解决版本冲突问题
apply plugin: 'io.spring.dependency-management'
apply plugin: 'org.springframework.boot'
eclipse {
jdt {
// if you want to alter the java versions (by default they are configured with gradle java plugin settings):
sourceCompatibility = SOURCE_COMPILER_LEVEL
targetCompatibility = TARGET_COMPILER_LEVEL
// javaRuntimeName = "../../org.eclipse.jdt.launching.JRE_CONTAINER"
}
}
// 将依赖包复制到lib目录
task copyBootJar(type: Copy, dependsOn: ['jar']) {
// 分组到build
group "build"
from configurations.api {
canBeResolved = true
}
// 清除现有的lib目录
delete "$buildDir/libs/lib"
from configurations.getByName('runtimeClasspath')
into "$buildDir/libs/lib"
}
// 拷贝resources资源文件
task copyBootResources(type: Copy, dependsOn: 'copyBootJar') {
// 分组到build
group "build"
// 清除现有的lib目录
delete "$buildDir/libs/resources"
from fileTree(dir: 'src/main/resources')
filteringCharset = 'UTF-8'
into "$buildDir/libs/resources"
}
// 配置bootJar进行打包
tasks.named("bootJar") {
// lib目录的清除和复制任务
dependsOn copyBootJar
dependsOn copyBootResources
def libStr = ''
// configurations 只能放入任务中
doFirst() {
manifest {
if (configurations.getByName('runtimeClasspath').isCanBeResolved()) {
// 获取运行时jar包
libStr = configurations.getByName('runtimeClasspath').getFiles().sort().collect { "lib/$it.name" }.join(' ') + " resources/"
// println(libStr)
}
attributes(
'Implementation': DEVELOPER_NAME,
'Specification-Version': DEVELOPER_NAME,
'Implementation-Vendor': DEVELOPER_ID,
'Implementation-ProductID': project.name,
'Compile-DateTime': new Date().format('yyyy-MM-dd HH:mm:ss'),
'Compile-User': DEVELOPER_NAME,
'Class-Path': "$libStr"
)
}
}
mainClass = "${MainClassName}"
// 排除所有的jar和resources(jar和resources分离需打开)
excludes = ["*.jar","*.properties","*.xml","*.yml","mybatis/","i18n/"]
}
// 打包不包含Test
if (project.getProperty('skipTest').equals("true")) {
compileTestJava.enabled = false
processTestResources.enabled = false
testClasses.enabled = false
test.enabled = false
}
repositories {
// 本地
mavenLocal()
// 引入中央仓库
mavenCentral()
// 阿里云
maven {
name 'Alibaba Maven Repository'
url "https://maven.aliyun.com/nexus/content/groups/public"
}
}
// 下面我们配置,当 Gradle 构建遇到依赖冲突时,就立即构建失败
// configurations.all() {
// Configuration configuration ->
// //当遇到版本冲突时直接构建失败
// configuration.resolutionStrategy.failOnVersionConflict()
// }
}
// 配置子工程
configure(subprojects) { subproject ->
task sourcesJar(type: Jar) {
// 分组到dev
group "releaseVersion"
archiveClassifier = "sources"
from sourceSets.main.allJava
duplicatesStrategy = DuplicatesStrategy.INCLUDE
}
task javaDocJar(type: Jar, dependsOn: javadoc) {
// 分组到dev
group "releaseVersion"
archiveClassifier = "javadoc"
from javadoc.destinationDir
}
artifacts {
archives sourcesJar, javaDocJar
}
processResources {
// 分组到dev
group "releaseVersion"
// doFirst {
// // 生产环境的打包任务
// // System.getProperty("profile", "dev") 表示获取系统变量 profile 的值,如果没有就用 dev。
// // 编译:gradle releaseVersion -Dprofile=prod
// filter ReplaceTokens, tokens: [activeProfile: System.getProperty("profile", "dev")]
// }
duplicatesStrategy = DuplicatesStrategy.INCLUDE
}
tasks.withType(JavaCompile) {
sourceCompatibility = SOURCE_COMPILER_LEVEL
targetCompatibility = TARGET_COMPILER_LEVEL
options.encoding = 'UTF-8'
}
tasks.withType(Javadoc) {
sourceCompatibility = JAVADOC_SOURCE_LEVEL
targetCompatibility = JAVADOC_COMPILER_LEVEL
options.encoding = 'UTF-8'
// disable the crazy super-strict doclint tool in Java 8
// noinspection SpellCheckingInspection
if (JavaVersion.current().isJava8Compatible()) {
options.addStringOption('Xdoclint:none', '-quiet')
}
}
// 配置子模块的基础包
dependencies {
// 开发过程
developmentOnly "org.springframework.boot:spring-boot-devtools"
// lombok
compileOnly "org.projectlombok:lombok:${lombok_version}"
annotationProcessor "org.projectlombok:lombok:${lombok_version}"
testAnnotationProcessor "org.projectlombok:lombok:${lombok_version}"
testCompileOnly "org.projectlombok:lombok:${lombok_version}"
// 单元测试
testImplementation "org.springframework.boot:spring-boot-starter-test"
// testImplementation "org.junit.jupiter:junit-jupiter:${jupiterVersion}"
}
}
settings.gradle内容如下:
rootProject.name = 'ruoyi'
include('ruoyi-framework')
include('ruoyi-system')
include('ruoyi-common')
include('ruoyi-quartz')
include('ruoyi-admin')
include('ruoyi-generator')
gradle.properties内容如下:
# 项目信息
PROJ_GROUP=com.ruoyi
PROJ_VERSION=3.8.6
#主程序(bootJar)
MainClassName=com.ruoyi.RuoYiApplication
# 测试不打包
skipTest=true
# 开发信息
DEVELOPER_ID=ruoyi
DEVELOPER_NAME=ruoyi
DEVELOPER_EMAIL=ruoyi@qq.com
# maven
SOURCE_COMPILER_LEVEL=1.8
TARGET_COMPILER_LEVEL=1.8
JAVADOC_SOURCE_LEVEL=1.8
JAVADOC_COMPILER_LEVEL=1.8
# jar包版本
druid_version=1.2.18
bitwalker_version=1.21
kaptcha_version=2.3.3
fastjson_version=2.0.39
oshi_version=6.4.4
commons_io_version=2.11.0
commons_collections_version=3.2.2
#Swagger3RESTfulAPI文档
swagger_version=3.0.0
swagger_models=1.6.11
swagger_annotations=1.6.11
#引入美化swagger-bootstrap-ui包
swagger_bootstrap_ui=1.9.6
knife4j_version=3.0.3
poi_version=5.2.2
velocity_version=2.3
jwt_version=0.9.1
#spring
lombok_version=1.18.28
springboot_version=2.7.14
spring_version=5.3.29
mysql_version=8.0.33
#mybatis
mybatis_plus_version=3.5.3.2
mybatis_version=3.5.13
mybatis_spring_version=2.1.1
pagehelper_boot_version=1.4.6
jsqlparser_version=4.6
#beetlesql数据库ORM开发框架
beetlsql_version=3.23.11-RELEASE
bboss_version=6.1.1
hutool_version=5.8.21
# 补充
quartz=2.3.2
javax_servlet_api=4.0.1
commons_lang3=3.12.0
jackson_databind=2.13.5
dynamic_datasource=4.1.3
snakeyaml=1.3.0
jaxb_api=2.4.0-b180830.0359
commons_pool2=2.11.1
##################################
#gradle配置信息
##################################
## 开启并行编译
org.gradle.parallel=true
## 开启守护进程
org.gradle.daemon=true
## 按需编译(启用新的孵化模式)
org.gradle.configureondemand=true
#开启 Gradle 缓存
org.gradle.caching=true
2、ruoyi-vue的项目子模块配置build.gradle
2.1、ruoyi-admin的build.gradle等配置
/*判断 build命令是否指定属性 profile。
例如 gradle buildTar -xtest -Pprofile=prod*/
import org.apache.tools.ant.filters.ReplaceTokens
def profile = System.getProperty("profile") ?: "dev" // 启动配置文件类型
// def profile = project.hasProperty('profile') ?: "dev" // 启动配置文件类型
println "profile:" + profile
// 时间
// def signTime = new Date().format("yyyyMMddHHmmss")
// 时间戳
def timesTamp = System.currentTimeMillis().toString();
// println "${timesTamp}"
sourceSets {
main {
java {
srcDir 'src/main/java'
}
// 开发环境
if (profile == "dev") {
// printf("测试:" + profile)
resources {
// 这边会影响插件releaseVersion和idea的run app
// No active profile set, falling back to 1 default profile: "default"
srcDir 'src/main/resources'
srcDir 'src/main/java' exclude '**/*.java'
}
} else {
resources {
srcDir 'src/main/resources' exclude '**/*'
srcDir 'src/main/java' exclude '**/*.java'
}
}
// compileClasspath = configurations.api + configurations.runtime
}
test {
java {
srcDir 'src/test/java'
}
resources {
srcDir 'src/test/resources'
srcDir 'src/test/java' exclude '**/*.java'
}
}
}
// 闭包,相当与一个代码快,path是一个传参,这个闭包用于根据传入的path,创建相应的目录
def createDir = { path ->
File dir = new File(path);
if (!dir.exists()) {
dir.mkdirs();
println("build dir:" + path.toString())
}
}
/*任务 描述
Copy 将文件复制到目标目录
Delete 删除文件和目录
Exec 执行命令行程序
GradleBuild 执行Gradle构建
JavaExec 在一个子进程中执行一个Java程序
Sync 同步源文件文件或者目录(增量或改变)
Upload 将源文件配置的组件上传到执行的仓库*/
// clean task
task cleanRelease(type: Delete) {
// 分组到dev
group "releaseVersion"
doFirst {
println "clean begin..."
}
// delete rootProject.buildDir
delete 'out/'
delete "${buildDir}/"
}
// 自定义打jar包
jar {
def libStr = ''
// configurations 只能放入任务中
doFirst() {
manifest {
if (configurations.getByName('runtimeClasspath').isCanBeResolved()) {
// 第一种处理方法:
libStr = configurations.getByName('runtimeClasspath').getFiles().sort().collect { "lib/$it.name" }.join(' ') + " resources/"
// println(libStr)
}
attributes(
'Implementation': archiveVersion,
'Specification-Version': archiveVersion,
'Implementation-Vendor': DEVELOPER_ID,
'Implementation-ProductID': project.name,
'Compile-DateTime': new Date().format('yyyy-MM-dd HH:mm:ss'),
'Compile-User': DEVELOPER_NAME,
'Class-Path': "$libStr",
'Main-Class': "${MainClassName}"
)
}
}
}
// gradle 编译打包
task copyJarFiles(type: Copy, dependsOn: ['cleanRelease', 'jar']) {
// 分组到dev
group "releaseVersion"
from configurations.api {
canBeResolved = true
}
from jar.outputs
//
// from configurations.runtime
// from configurations.compileClasspath
// 排除
exclude { details -> details.file.name.startsWith('bboss-rt') }
// exclude { details -> details.file.name.startsWith("${project.name}") }
into "${buildDir}/dist/${project.name}/lib"
}
copyJarFiles.mustRunAfter('cleanRelease')
// 引导启动程序
task copyRTJarFiles(type: Copy, dependsOn: ['cleanRelease', 'jar']) {
// 拷贝jar浏览
/*def libList = ''
doFirst {
libList = new File("${buildDir}/dist/${project.name}/lib").list().findAll { it.endsWith('.jar') }.collect { "lib/$it" }.join(' ')
println(libList)
}*/
// 分组到dev
group "releaseVersion"
from configurations.api {
canBeResolved = true
}
from jar.outputs
// 包含
include { details -> details.file.name.startsWith('bboss-rt') }
include { details -> details.file.name.startsWith("${project.name}") }
into "${buildDir}/dist/${project.name}"
// 重新命名
rename("bboss-rt-${bboss_version}.jar", "${project.name}-${bboss_version}.jar")
rename("${project.name}-${project.version}-plain.jar", "${project.name}.jar")
// rename { String filename ->
// filename.replace("${project.name}-${project.version}-plain.jar", "${project.name}.jar")
// }
}
copyRTJarFiles.mustRunAfter('cleanRelease')
// 运行脚本和jvm参数
task copyToolFiles(type: Copy, dependsOn: 'copyJarFiles') {
// 分组到dev
group "releaseVersion"
from('runfiles') {
// 替换参数
filter(ReplaceTokens, tokens: [
project_name : project.name,
project_version: project.version,
bboss_version : bboss_version
],
beginToken: '${', endToken: '}')
}
// linux文件权限
// fileMode = 0755
filteringCharset = 'UTF-8'
into "${buildDir}/dist/${project.name}"
}
copyToolFiles.mustRunAfter('cleanRelease')
// 拷贝resources资源文件
task copyResourcesfiles(type: Copy, dependsOn: 'copyJarFiles') {
// 分组到dev
group "releaseVersion"
from fileTree(dir: 'src/main/resources')
filteringCharset = 'UTF-8'
into "${buildDir}/dist/${project.name}/resources"
}
copyResourcesfiles.mustRunAfter('cleanRelease')
// 拷贝docker容器脚本
task copyDockerfiles(type: Copy, dependsOn: 'copyJarFiles') {
// 分组到dev
group "releaseVersion"
from('docker') {
filter(ReplaceTokens, tokens: [
project_name : project.name,
project_version : project.version,
docker_registry_url: docker_registry_url,
docker_registry : docker_registry,
project_net : project_net,
project_releasedate: timesTamp
],
beginToken: '${', endToken: '}')
}
// include { details -> details.file.name.endsWith('*.yml') }
// include { details -> details.file.name.startsWith('Dockerfile') }
// include("**/*.html")
filteringCharset = 'UTF-8'
into "${buildDir}/dist"
}
copyDockerfiles.mustRunAfter('cleanRelease')
// shell脚本
task copyScriptsfiles(type: Copy, dependsOn: 'copyResourcesfiles') {
// 分组到dev
group "releaseVersion"
from('scripts') {
// 替换变量
filter(ReplaceTokens, tokens: [
project_name : project.name,
project_version: project.version],
beginToken: '${', endToken: '}')
}
filteringCharset = 'UTF-8'
into "${buildDir}/dist/${project.name}"
}
task releaseVersion(type: Zip, dependsOn: ['copyJarFiles', 'copyRTJarFiles', 'copyToolFiles', 'copyResourcesfiles', 'copyDockerfiles', 'copyScriptsfiles']) {
// 打包前创建目录
doFirst {
println "releaseVersion init ..."
// 定义一个数组,数组里的是目录路径[默认为日志logs/]
def paths = ["${buildDir}/dist/${project.name}/logs"]
// 增加初始化目录
// paths.add("${buildDir}/dist/${project.name}/entrypoint-initdb.d/")
// 遍历数组,调用createDir闭包,创建目录
paths.forEach(createDir)
}
// 分组到dev
group "releaseVersion"
// appendix = 'wrapper'
// 描述
description = "appName:${project.name},version:${project.version},compileTime:${timesTamp}"
// 程序压缩包名称,默认为:${project.name}-${project.version}-${archiveClassifier}.zip
// 项目基本名,默认为:${project.name}
archiveBaseName = "${project.name}"
// 项目版本,默认为:${project.version}
archiveVersion = "${project.version}"
// 项目后缀(发布标志,时间戳等),默认为空
archiveClassifier = 'released'
// 项目默认输出目录: ${buildDir}/distributions
destinationDirectory = file("${buildDir}/distributions")
// 项目打包目录
from "${buildDir}/dist/${project.name}"
doLast {
println "releaseVersion end..."
}
}
releaseVersion.mustRunAfter('cleanRelease')
dependencies {
// 引入子模块
api project(':ruoyi-framework')
api project(':ruoyi-quartz')
api project(':ruoyi-generator')
// 引入本地jar包
// implementation fileTree(dir:'libs',includes: ['*.jar'])
// Swagger3 RESTful API文档
// swagger-models和swagger-annotation 1.5.22升级,解决冲突问题(springfox-boot-starter和knife4j-spring-boot-starter)
// Swagger3依赖
api("io.springfox:springfox-boot-starter:${swagger_version}")
{
// 解决版本冲多
exclude group: 'io.swagger', module: 'swagger-models'
exclude group: 'io.swagger', module: 'swagger-annotations'
}
// 引入美化swagger-bootstrap-ui包
api "com.github.xiaoymin:swagger-bootstrap-ui:${swagger_bootstrap_ui}"
// 基于Swagger 2的在线API文档框架
api("com.github.xiaoymin:knife4j-spring-boot-starter:${knife4j_version}") {
// 解决版本冲多
exclude group: 'io.swagger', module: 'swagger-models'
// exclude group: 'io.swagger', module: 'swagger-annotations'
}
// 解决版本冲多swagger-annotations、swagger-models 1.5.22与1.5.20冲突
// swagger生成客户端和服务器代码的库
api "io.swagger:swagger-models:${swagger_models}"
// swagger 注解
api "io.swagger:swagger-annotations:${swagger_annotations}"
// Mysql驱动包
api "mysql:mysql-connector-java:${mysql_version}"
// beetlsql ORM框架
api "com.ibeetl:sql-springboot-starter:${beetlsql_version}"
// bboss 微服务容器组件
api "com.bbossgroups:bboss-bootstrap-rt:${bboss_version}"
// Java工具类库
api "cn.hutool:hutool-all:${hutool_version}"
}
2.2、其他ruoyi-common等build.gradle配置
sourceSets {
main {
java {
srcDir 'src/main/java'
}
resources {
srcDir 'src/main/resources'
srcDir 'src/main/java' exclude '**/*.java'
}
}
test {
java {
srcDir 'src/test/java'
}
resources {
srcDir 'src/test/resources'
srcDir 'src/test/java' exclude '**/*.java'
}
}
}
jar {
manifest {
attributes(
'Implementation': archiveVersion,
'Specification-Version': archiveVersion,
'Implementation-Vendor': 'ruoyi',
'Implementation-ProductID': project.name,
'Compile-Timestamp': new Date().format('yyyy-MM-dd HH:mm:ss'),
'Compile-User': DEVELOPER_NAME,
)
}
}
dependencies {
// v6.0.0版本后需要高版本java11+支持
// api "org.springframework:spring-context-support:${spring_version}"
// api "org.springframework:spring-web:${spring_version}"
// springboot核心框架
api "org.springframework.boot:spring-boot-starter-security"
// 自定义验证注解
api "org.springframework.boot:spring-boot-starter-validation"
// redis 缓存操作
api "org.springframework.boot:spring-boot-starter-data-redis"
api "org.springframework.boot:spring-boot-configuration-processor"
// 常用工具类
api "org.apache.commons:commons-lang3:${commons_lang3}"
// JSON工具类
api "com.fasterxml.jackson.core:jackson-databind:${jackson_databind}"
// 动态数据源
api("com.baomidou:dynamic-datasource-spring-boot-starter:${dynamic_datasource}")
// 阿里JSON解析器
api "com.alibaba.fastjson2:fastjson2:${fastjson_version}"
// io常用工具类
api "commons-io:commons-io:${commons_io_version}"
// excel工具
api "org.apache.poi:poi-ooxml:${poi_version}"
// api "org.yaml:snakeyaml:${snakeyaml}"
api("io.jsonwebtoken:jjwt:${jwt_version}") {
// 解决版本冲多
exclude group: 'com.fasterxml.jackson.core', module: 'jackson-databind'
}
// Jaxb
api "javax.xml.bind:jaxb-api:${jaxb_api}"
// pool 对象池
api "org.apache.commons:commons-pool2:${commons_pool2}"
// 解析客户端操作系统、浏览器等
api "eu.bitwalker:UserAgentUtils:${bitwalker_version}"
// servlet包
api "javax.servlet:javax.servlet-api:${javax_servlet_api}"
// mybatis-plus 增强CRUD
api("com.baomidou:mybatis-plus-boot-starter:${mybatis_plus_version}") {
// 解决版本冲多
exclude group: 'org.mybatis', module: 'mybatis'
exclude group: 'org.mybatis', module: 'mybatis-spring'
}
// pagehelper 分页插件
api("com.github.pagehelper:pagehelper-spring-boot-starter:${pagehelper_boot_version}") {
// 解决版本冲多
exclude group: 'org.mybatis', module: 'mybatis'
exclude group: 'org.mybatis', module: 'mybatis-spring'
}
// 解决mybatis、pagehelper冲突问题
api "org.mybatis:mybatis:${mybatis_version}"
api "org.mybatis:mybatis-spring:${mybatis_spring_version}"
api "com.github.jsqlparser:jsqlparser:${jsqlparser_version}"
// 阿里数据库连接池
api "com.alibaba:druid-spring-boot-starter:${druid_version}"
// beetlsql ORM框架
api "com.ibeetl:sql-springboot-starter:${beetlsql_version}"
// bboss 微服务容器组件
api "com.bbossgroups:bboss-bootstrap-rt:${bboss_version}"
// Java工具类库
api "cn.hutool:hutool-all:${hutool_version}"
}
description = 'ruoyi-common'
2.3、ruoyi-admin的application.yml配置
在最后增加一行,用于bboss-rt启动设置主程序
## 主程序发布(bboss-rt) ##
mainclass: #[mainclassevn:com.ruoyi.RuoYiApplication]
3、编译打包
在项目根目录下运行:
#!/bin/bash
gradle clean -Dprofile=releaseVersion && gradle releaseVersion -Dprofile=releaseVersion
# gradle pushDockerImage
打包后目录如图:
4、运行程序
4.1、基于bboss-rt工具的运行方式
java $RT_JAVA_OPTS -jar ruoyi-admin-6.1.1.jar --conf=resources/application.yml
$RT_JAVA_OPTS 为jvm参数,ruoyi-admin-6.1.1.jar为bboss-rt-6.1.1.jar改名而来,请看程序。
4.2、基于ruoyi-admin.jar的启动方式(常规)
java -jar ruoyi-admin.jar