Artifact(artifactId):项目(模块)名称,是当前项目在组中的唯一标识。
推荐的做法是使用实际项目名称作为artifact的前缀
, 如appstore项目下的升级模块:appstore-upgrade。这样做的好处是方便寻找实际构件(jar包)默认情况下,Maven默认生成的构件会以artifactId作为开头,如appstore-upgrade-1.0.jar
Group+Artifact实际对应Java包的结构,是src/java/main目录中Java的目录结构,如com.xiaomi.mitv.appstore
Maven其中一个核心的作用就是管理项目的依赖,引入我们所需的各种jar包等
为了能自动化地解析任何一个Java构件,Maven必须将这些jar包或者其他资源进行唯一标识,这是管理项目的依赖的基础,也就是我们要说的坐标
包括我们自己开发的项目,也是要通过坐标进行唯一标识的,这样才能与其它项目中进行依赖引用
在Maven仓库中存储所有Maven项目共享的构件,每个构件都有一个唯一的坐标,对应在仓库中的唯一存储路径,该路径与坐标的大致关系为:groupId/artifactId/version/artifactId-version.packaging
Java Archive(Java归档文件),jar包就是java的类进行编译生成的class文件打包的压缩包,包里面就是一些class文件
在声明了main方法的类,并在jar文件中的META_INF/MANIFEST.MF文件中配置了Main-Class之后,是可以直接用 java -jar xxx.jar 通过内置的tomcat运行的,比较方便,简单
Web application Archive,与jar基本相同,但它通常表示这是一个Java的Web应用程序的包,是可以直接运行的web模块
Web项目有一个web资源目录,默认位置为src/main/webapp,其中需要包括WEB-INF目录,里面包含class文件、web.xml配置文件及前端页面文件,依赖的jar包在WEB-INF下的lib目录下
war包需要发布到一个容器里面,如将war包放在tomcat的webapps目录下,直接启动tomcat即可
src/main/java:项目主代码目录,项目的主代码最终会被打包到最终的构件中(jar包)
src/main/resources:项目主资源文件目录
src/main/test:项目测试代码目录,测试代码不会被打包
target:Maven构建的所有输出都在target目录中,项目主代码编译至target/classes,测试代码编译至target/test-classes
.idea存放项目的配置信息,包括历史记录,版本控制信息等(不会提交,可以设置隐藏)
.gitignore:用git做版本控制时 用这个文件控制那些文件或文件夹 不被提交(不用git的话可删除 没影响)
HELP.md:项目的帮助文档(不需要的话可删除 没影响)
mvnw(Maven wrapper):linux上处理mevan版本兼容问题的脚本(可删除 没影响)
mvnw.cmd:windows 上处理mevan版本兼容问题的脚本(可删除 没影响)
.mvn:Maven-wrapper.properties文件中记录你要使用的Maven版本,当用户执行mvnw clean 命令时,发现当前用户的Maven版本和期望的版本不一致,那么就下载期望的版本,然后用期望的版本来执行mvn命令(可删除)
appstore.iml:每个导入IDEA的项目都会生成一个项目同名的 .iml文件 用于保存你对这个项目的配置 (删了程序重新导入后还会生成 但由于配置丢失可能会造成程序异常)
2、多模块项目搭建
2.1、为什么搭建多模块项目?
对项目按功能、业务模块划分,使项目结构更清晰,降低项目耦合性
如电视商店项目,将电视商店的接口服务和升级服务拆分为单独的模块
抽取公共模块,实现一处开发多处引用,提高代码复用率和开发效率,更利于项目后期的维护和升级
如抽取common模块,放置共用的配置类、工具类、常量、枚举等
子模块的pom文件会继承父工程的pom文件,依赖jar包版本统一交由父pom来管理
2.2 、多模块项目建议
一个项目的子模块都应该使用相同的groupId
如果它们一起开发和发布,还应该使用同样的version
一个项目的子模块的artifactId还应该使用一致的前缀,以方便同其他项目区分
子模块的目录名称应当与其artifactId一致,即artifactId=项目名
子模块的包名,如groupId为com.xiaomi.mitv,artifactId为appstore-common,那么此子模块的包名应为 com.xiaomi.mitv.appstore.common
2.3、多模块项目搭建示例:
2.3.1、新建父模块
File-->New-->Project-->Maven
Finish
删除src目录
选择Parent,然后填写模块名即可,GroupId、ArtifactId、Version会自动填充
Finish,父模块pom.xml中会自动在modules标签内添加新增的子模块
<parent>
<artifactId>appstore</artifactId>
<groupId>com.xiaomi.mitv</groupId>
<version>1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>appstore-common</artifactId>
parent元素声明了父模块,parent下的子元素artifactId,groupId,version指定了父模块的坐标,这三个元素是必须的
元素relativePath元素表示父父模块pom的相对路径,默认值为 ../pom.xml,也就是说,Maven默认父pom在上一层目录下
父模块与子模块的目录结构不一定是父子关系,也可以是平行目录结构。这时,需要修改relativePath元素的值,指定父pom的位置,父模块pom中module元素的值也需要做相应的修改,以指向正确的子模块目录
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.xiaomi.mitv</groupId>
<artifactId>appstore</artifactId>
<packaging>pom</packaging>
<version>1.0</version>
<modules>
<module>appstore-common</module>
<module>appstore-upgrade</module>
</modules>
<groupId>com.xiaomi.mitv</groupId>
<artifactId>appstore-common</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
Maven按照父POM中modules标签的顺序读取POM,如果该POM没有依赖模块,那么就构建该模块,否则就先构建其依赖模块,如果该依赖还依赖其他模块,则进一步先构建依赖的依赖。
模块间的依赖关系会将反应堆构成一个有向非循环图(Directed Acyclic Graph,GAP),各个模块是该图的节点,依赖关系构成了有向边。这个图不允许出现循环,也就是Maven不允许循环依赖,当出现模块A依赖于B,而B又依赖于A的情况时,Maven就会报错
[INFO] Reactor Build Order:
[INFO]
[INFO] appstore [pom]
[INFO] appstore-common [jar]
[INFO] appstore-upgrade [jar]
2.4.4、自定义模块之间的依赖
创建多环境配置文件时,需要遵循Spring Boot允许的命名约定来命令,格式为application-{profile}.properties,其中{profile}为对应的环境标识
在resources目录下分别创建application-dev.properties、application-pre.properties、application-prd.properties,分别对应开发、预览、生产环境的配置文件
其中application.properties为项目主配置文件,包含项目所需的所有公共配置
当激活的环境对应的文件中配置项与application.properties中配置项相同时,会覆盖application.properties中的配置项
3.1.2、多环境的切换
application.properties配置文件中增加如下配置项:
spring.profiles.active=dev
IDEA编译器指定项目启动环境
我们可以在IDEA的Run/debug Configuration 页面配置项目启动环境。
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<executions>
<execution>
<id>copy-resources</id>
<phase>validate</phase>
<!--在default生命周期的validate阶段执行copy-resources操作-->
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<!--复制到哪-->
<outputDirectory>${basedir}/target/classes</outputDirectory>
<!--资源文件属性过滤-->
<resources>
<resource>
<directory>../appstore-config/dev</directory>
<filtering>true</filtering>
<!--复制哪些文件-->
<includes>
<include>logback.xml</include>
<include>redis.properties</include>
</includes>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>pre</id>
<properties>
<active.env>pre</active.env>
</properties>
......
</profile>
</profiles>
Maven <properties>中配置了 db.username=xiaomi,那么${db.username}只有在POM中才会被解析为具体的值xiaomi,如果是在 src/main/resources内的配置文件中引用了${db.username},构建的时候,它仍然为${db.username},不会被解析为具体的值xiaomi。
因此,
需要让Maven解析资源文件中的Maven属性
在pom中配置资源文件的目录,并开启资源属性过滤,如下,即可让maven-resources-plugin插件在将资源文件复制到编译输出目录中时,解析资源文件中的Maven属性
<directory>${basedir}/src/main/resources</directory>
<filtering>true</filtering>
<!--只对资源目录下的某些文件开启Maven属性过滤-->
<includes>
<include>xxx.properties</include>
</includes>
</resource>
</resources>
</build>
SpringBoot 1.3或更高版本,将Maven属性占位符修改为了 @xxx@,要想继续使用${}占位符,需要在POM properties中指定<resource.delimiter>${}</resource.delimiter>