创建springboot多模块项目
参考若依后台管理项目,感觉一个好的项目程序的健壮性十分重要,其中很多程序设计思路和技巧规范值得我们好好学习。其中碰到的第一个那便是创建 Springboot 多模块项目,实际操作中遇到很多问题,特此记录一下。
多模块项目优点:https://www.yuque.com/xihuanxiaorang/ng3te7/awrxnc多模块项目通常由一个父模块和若干个子模块构成,每个模块对应着一个 pom 文件。父模块与子模块之间通过继承与聚合相互关联。多模块适用于一些比较大的项目,通过合理的模块拆分,实现代码的复用,便于维护和管理。
1、RuoYi 项目文件结构
com.ruoyi
├── common // 工具类
│ └── annotation // 自定义注解
│ └── config // 全局配置
│ └── constant // 通用常量
│ └── core // 核心控制
│ └── enums // 通用枚举
│ └── exception // 通用异常
│ └── filter // 过滤器处理
│ └── utils // 通用类处理
├── framework // 框架核心
│ └── aspectj // 注解实现
│ └── config // 系统配置
│ └── datasource // 数据权限
│ └── interceptor // 拦截器
│ └── manager // 异步处理
│ └── security // 权限控制
│ └── web // 前端控制
├── ruoyi-generator // 代码生成(可移除)
├── ruoyi-quartz // 定时任务(可移除)
├── ruoyi-system // 系统代码
├── ruoyi-admin // 后台服务
├── ruoyi-xxxxxx // 其他模块
2、RuoYi 各模块间的依赖关系
3、创建 Springboot 多模块项目
在创建多模块项目的时候,得先捋一捋每个模块的作用,搞清楚每个模块干什么用的动起手来才更加清晰,有目的性。
如上图所示,分为4个子模块和一个父模块。
其中,common 模块用于存放一些工具类,system 模块主要存放 entity,service 和 mapper 文件,framwork 模块主要用于管理框架的配置,admin 模块作为整个后台管理系统的入口,主要存放一些 controller 文件。
1、创建 my-ruoyi
父模块
新建项目,选择新建 maven 项目,填写所需的项目坐标。
pom.xml 文件配置:
<properties>
<my-ruoyi.version>1.0.0-SNAPSHOT</my-ruoyi.version>
<maven-jar-plugin.version>3.1</maven-jar-plugin.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.5.5</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- 通用工具-->
<dependency>
<groupId>top.xiaorang</groupId>
<artifactId>ruoyi-common</artifactId>
<version>${my-ruoyi.version}</version>
</dependency>
<!-- 系统模块-->
<dependency>
<groupId>top.xiaorang</groupId>
<artifactId>ruoyi-system</artifactId>
<version>${my-ruoyi.version}</version>
</dependency>
<!-- 核心模块-->
<dependency>
<groupId>top.xiaorang</groupId>
<artifactId>ruoyi-framework</artifactId>
<version>${my-ruoyi.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<modules>
<module>ruoyi-common</module>
<module>ruoyi-system</module>
<module>ruoyi-framework</module>
<module>ruoyi-admin</module>
</modules>
<packaging>pom</packaging>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-jar-plugin.version}</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>public</id>
<name>aliyun nexus</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<releases>
<enabled>true</enabled>
</releases>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>public</id>
<name>aliyun nexus</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
删除 src 目录:因为父模块不用来写代码,所以删除不必要的目录。
2、创建 ruoyi-common
模块
点击 my-ruoyi
父模块,创建 ruoyi-common
公共模块。
pom.xml 文件配置:
<dependencies>
<!-- 自定义验证注解 -->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
</dependency>
<!-- JSON工具类 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
3、创建 ruoyi-system
模块
同上面创建 ruoyi-common
模块一样创建 ruoyi-system
系统模块。
pom.xml 文件配置:
<dependencies>
<!-- SpringDataJpa -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>top.xiaorang</groupId>
<artifactId>ruoyi-common</artifactId>
</dependency>
</dependencies>
该模块主要用来编写实体类,业务层和数据访问层。
4、创建 ruoyi-framework
模块
同上面创建 ruoyi-common
模块一样创建 ruoyi-framework
核心模块。
pom.xml 文件配置:
<dependencies>
<dependency>
<groupId>top.xiaorang</groupId>
<artifactId>ruoyi-system</artifactId>
</dependency>
</dependencies>
5、创建 ruoyi-admin
模块
同上面创建 ruoyi-common
模块一样创建 ruoyi-admin
后台管理模块,即 web 模块。
pom.xml 文件配置:
<dependencies>
<!-- SpringBoot Web容器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Mysql驱动包 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>top.xiaorang</groupId>
<artifactId>ruoyi-framework</artifactId>
</dependency>
</dependencies>
该模块主要用来编写 Controller 层代码。
最后,使用 postman 工具来测试一下是否能够正确的访问数据库获取数据:
代码已经上传到 GitHub,地址为 https://github.com/xihuanxiaorang/my-ruoyi
知识点扩展重要
1、scope=import
在使用 springboot 时,项目可能需要使用自己的父模块,而不能继承 spring-boot-starter-parent
时,任然可以通过使用 scope=import
来保持依赖管理,springboot 官方文档推荐配置:
<dependencyManagement>
<dependencies>
<dependency>
<!-- 从Spring Boot导入依赖管理 -->
<groupId> org.springframework.boot </groupId>
<artifactId> spring-boot-dependencies </artifactId>
<version> 2.1 .12.RELEASE </version>
<type> pom </type>
<scope> import </scope>
</dependency>
</dependencies>
</dependencyManagement>
根据 maven 官方文档对依赖范围的描述:
- import
This scope is only supported on a dependency of type pom in thesection. It indicates the dependency is to be replaced with the effective list of dependencies in the specified POM's section. Since they are replaced, dependencies with a scope of import do not actually participate in limiting the transitivity of a dependency.
import
只能用在 dependencyManagement
块中,它是将 spring-boot-dependencies
中 dependencyManagement
的 dependencies
全部引入到当前工程的 dependencyManagement
中,所以不存在依赖传递。
2、type=pom
根据 maven 官方文档对 type 的描述:
- type:
Corresponds to the chosen dependency type. This defaults to jar. While it usually represents the extension on the filename of the dependency, that is not always the case: a type can be mapped to a different extension and a classifier. The type often corresponds to the packaging used, though this is also not always the case. Some examples are jar, ejb-client and test-jar: see default artifact handlers for a list. New types can be defined by plugins that set extensions to true, so this is not a complete list.
type,和被选择依赖的类型相对应,默认为 jar。通常它和依赖模块的扩展名一致,不过也不一定,因为一个模块的类型,可以被映射为不同的扩展名或分类上。通常 type 和依赖模块的 packaging 对应,尽管并不总是这样。比如 type 的值 ejb-client
, test-jar
,具体可以看看默认的构件处理器。这里说的是,大多数的模块,其实是有个默认的 packaging 与被依赖时候的 type 对应关系的,这个对应关系应该是有个构件处理器来决定的。
总结重要:
type=pom
说白了就是为了完全继承对方的管理依赖和属性定义。绿线解释有些时候 dependency
里面的 type
不用加,有些时候不加却报错(即通常为了获取继承来的 pom.xml
里面的 properties
里面的各种包的版本号之类的信息,没有的话就不能确定版本,当然报错)
3、maven-compiler-plugin
插件
maven 是个项目管理工具,如果不告诉它代码要使用什么样的 jdk 版本编译,它就会使用 maven-complier-plugin
编译插件默认的 jdk 版本来编译代码,这样就很容易出现版本不匹配的问题,以至于可能导致编译不通过的问题。例如代码中要是使用了 jdk1.8 的新特性(函数式编程),但是 maven 在编译的时候使用的是 jdk7,那带有 jdk1.8 新特性的代码是不可能编译通过的。为了避免此类问题的出现,在构件 mvane 项目的时候,应该先配置 maven-compiler-plugin
插件,指定项目源码的 jdk 版本,编译后的 jdk 版本,以及编码方式。
从 3.8.0
版本后,maven-compiler-plugin
插件默认的 jdk 版本就由 1.5 变成 1.6 。但是这任然跟不上 jdk 的更新速度,目前大多数系统都在使用 jdk1.8。
maven-compiler-plugin
插件中 compiler:compile
有如下关于 jdk 版本变更的描述:
详细配置:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
4、@Transient注解
实体类中如果使用了 @Table 注解后,要想添加表中不存在的字段,就可以使用 @Transient 注解。@Transient 注解表示该属性并非是一个要映射到数据库的字段,ORM框架会忽略该属性。注解可以加在属性上,也可以加上 get() 方法上。
5、@EqualsAndHashCode注解
这个注解的作用就是自动给 model bean 实现 equals 方法和 hashcode 方法。
如果使用 @EqualsAndHashCode(callSuper=false),就表示不调用父类的属性,如果子类的属性完全相同,那么 hashcode 的值就相同啦,用 equals 方法比较的时候就会返回 true。如果使用 @EqualsAndHashCode(callSuper=true),那就是用自己的属性和父类继承的属性一起生成 hashcode,equals 方法比较的结果返回 false。
6、@DynamicInsert 和 @DynamicUodate 注解
@DynamicInsert:默认为 true,指定用于 insert 的 sql 将会再运行时动态生成,并且只包含那些非空值字段。
@DynamicUpdate:默认为 true,指定用于 update 的 sql 将会在运行时动态生成,并且只更新那些改变过的字段。
如果希望在新增的时候只包含设置了值的字段,更新时只包含发生变化的字段,那么就可以使用 @DynamicInsert 和 @DynamicUpdate 注解。
7、@IdClass 注解
@IdClass 注解可以实现一个实体类中有两个主键,即联合主键。首先我们需要创建一个联合主键类并且实现序列化接口,类名为 SysUserRoleKey,该类中有 userId 和 roleId 这两个字段,这个类的要求有三个:
-
需要实现 Serializable 接口
-
需要一个默认的 public 的 无参构造方法,使用 Lamada 的 @NoArgsConstructor 注解帮我们实现,或者如果没有定义有参构造的情况下,这个注解也可以不需要,因为有默认的无参构造方法
-
重写 equals 和 hashCode 方法。
使用的时候,在 SysUserRole 实体类上使用 @IdClass(value = SysUserRoleKey.class) 注解,然后 userId 和 roleId 都分别使用 @Id 注解即可。
参考链接
创建 springboot 多模块项目:
https://blog.csdn.net/MacWx/article/details/103787209
type=pom 的理解: