最详细的 Spring Boot 多模块开发与排坑指南
创建项目
创建一个 SpringBoot 项目非常的简单,简单到这里根本不用再提。你可以在使用 IDEA 新建项目时直接选择 Spring Initlalize
创建一个 Spring Boot 项目,也可以使用 Spring 官方提供的 Spring Boot 项目生成页面得到一个项目。
下面介绍一下使用 Spring 官方生成的方式,如果你已经有了一个 Spring Boot 项目,这部分可以直接跳过。
填写
group
和Artifact
信息,选择依赖(我选择了 Spring Web 和 Lombok )。点击
Generate
按钮下载项目。打开下载的项目,删除无用的
.mvn
文件夹,mvnw
、mvnw.cmd
、HELP.md
文件。
到这里已经得到了一个 Spring Boot 初始项目了,我们直接导入到 IDEA 中,看一眼 pom.xml
的内容。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.wdbyte</groupId>
<artifactId>springboot-module-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-module-demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
把目录结构调整成自己想要的结构,然后添加 controller
和 entity
用于测试。
ProductController 类源代码。
@RestController
@RequestMapping("/product")
public class ProductController {
/**
* 获取商品列表
*
* @return
*/
@GetMapping("/list")
public Map list() {
// 模拟查询商品逻辑
Product product = new Product();
product.setProductName("小米粥");
product.setProductPrice(new BigDecimal(2.0));
product.setProductStock(100);
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("code", 000);
resultMap.put("message", "成功");
resultMap.put("data", Arrays.asList(product));
return resultMap;
}
}
Product 类源代码。
@Data
public class Product {
/** 商品名称. */
private String productName;
/** 商品价格. */
private BigDecimal productPrice;
/** 商品库存。 */
private int productStock;
}
模块化
借助 IDEA 工具可以快速的把项目改造成 maven 多模块,这里我们把准备测试 demo 拆分为 common 和 web 两个模块,common 模块存放实体类。web 模块存放 controller 层(这里项目虽小,拆分只是为了演示)。话不多说,直接开始。
配置主 pom.xml 打包方式 为 pom
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- 配置主 pom 打包方式为 pom -->
<packaging>pom</packaging>
....
....
创建 common 模块
项目直接 new -> module。
选择 maven -> next,填写模块名称。
继续 next 完成模块创建。
创建 web 模块
web 模块的创建和 common 模块如出一辙,不再赘述。完成两个模块的创建之后,你会发现你的主 pom.xml 文件里自动添加了 module 部分。
<modules>
<module>product-common</module>
<module>product-web</module>
</modules>
移动代码到指定模块
移动
Product.java
到product-common
模块,其他部分代码和 resource 部分直接移动到product-web
模块,移动完后你的代码结构是这个样子。
到这里,多模块已经拆分完成了, 但是 ProductController
代码里的红色警告让你发现事情还没有结束。
依赖管理
处理依赖问题
你发现了代码里的红色警告,不过你也瞬间想到了是因为把 Product
类移动到了 product-common
模块,导致这里引用不到了。
然后你查看了下 product-common
模块的 pom.xml 里的内容。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>springboot-module-demo</artifactId>
<groupId>com.wdbyte</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>product-common</artifactId>
</project>
机智的在 Product-web
模块的 pom.xml 里引入 product-common,手起键落,轻松搞定。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>springboot-module-demo</artifactId>
<groupId>com.wdbyte</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>product-web</artifactId>
<dependencies>
<dependency>
<groupId>com.wdbyte</groupId>
<artifactId>product-common</artifactId>
</dependency>
</dependencies>
</project>
满心欢喜的你快速的点击 Build-> Build Project,得到的 Error 警告刺痛了顶着黑眼圈的你。
不过你还是迅速定位了问题,查看 maven 依赖,你发现是因为没有指定 product-common
依赖的版本号。
原来如此,因为没有指定版本号,我们指定上不就完事了嘛。在最外层的主 pom.xml 中添加 <dependencyManagement>
添加上指定依赖和要指定的版本号。
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.wdbyte</groupId>
<artifactId>product-common</artifactId>
<version>0.0.1-SNAPSHOT</version><!-- maven 打包默认 0.0.1-SNAPSHOT 版本 -->
</dependency>
</dependencies>
</dependencyManagement>
刷新 maven ,发现项目已经不报错了,编译成功,运行启动类,熟悉的 Spring logo 又出现在眼前。
优化依赖
是的,Spring Boot 应用在改造成多模块后成功运行了起来,但是你貌似发现一个问题,模块 common
和模块 web
都继承了主 pom ,主 pom 中有 Lombok 、Spring Boot Web 和 Spring Boot Test 依赖,而 common
模块里只用到了 Lombok 啊,却一样继承了 Spring Boot 其他依赖,看来还是要改造一把。
只有
common
模块用到的依赖移动到common
模块。<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>springboot-module-demo</artifactId>
<groupId>com.wdbyte</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>product-common</artifactId>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>
只有
web
模块用到的依赖移动到web
模块。<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>springboot-module-demo</artifactId>
<groupId>com.wdbyte</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>product-web</artifactId> <dependencies>
<dependency>
<groupId>com.wdbyte</groupId>
<artifactId>product-common</artifactId>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</project>
抽取用到的版本号到
<properties>
,这里抽取common
模块的依赖版本。到这里最外层主 pom 的内容是这样的。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<packaging>pom</packaging>
<modules>
<module>product-common</module>
<module>product-web</module>
</modules>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.wdbyte</groupId>
<artifactId>springboot-module-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-module-demo</name>
<description>Demo project for Spring Boot</description> <properties>
<java.version>1.8</java.version>
<product-common.version>0.0.1-SNAPSHOT</product-common.version>
</properties> <dependencyManagement>
<dependencies>
<dependency>
<groupId>com.wdbyte</groupId>
<artifactId>product-common</artifactId>
<version>${product-common.version}</version>
</dependency>
</dependencies>
</dependencyManagement> <build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
看似完美,重新 Build-> Build Project ,发现一切正常,运行发现一切正常,访问正常。
打包编译
好了,终于到了最后一步了,你感觉到胜利的曙光已经照到了头顶,反射出耀眼的光芒。接着就是 mvn package
。
[INFO] springboot-module-demo ............................. SUCCESS [ 2.653 s]
[INFO] product-common ..................................... FAILURE [ 2.718 s]
[INFO] product-web ........................................ SKIPPED
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 6.084 s
[INFO] Finished at: 2020-03-19T08:15:52+08:00
[INFO] Final Memory: 22M/87M
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.springframework.boot:spring-boot-maven-plugin:2.2.5.RELEASE:repackage (repackage) on project product-common: Execution repackage of goal org.springframework.boot:spring-boot-m
aven-plugin:2.2.5.RELEASE:repackage failed: Unable to find main class -> [Help 1]
[ERROR]
ERROR 让你伤心了,但是你还是从报错中寻找到了一些蛛丝马迹,你看到是 spring-boot-maven-plugin 报出的错误。重新审视你的主 pom 发现 <build>
编译插件用到了 spring-boot-maven-plugin。
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
略加思索后将这段移动到 web
模块的 pom,因为这是 Spring Boot 的打包方式,现在放在主 pom 中所有的模块都会继承到,那么对于 common
模块来说是肯定不需要的。
移动后重新打包,不管你是运行命令 mvn package
还是双击 IDEA 中的 maven 管理中的 package ,想必这时候你都已经打包成功了
在 web
模块下的目录 target 里也可以看到打包后的 jar 文件 product-web-0.0.1-SNAPSHOT.jar。可以使用 java 命令直接运行。
$ \springboot-module-demo\product-web\target>java -jar product-web-0.0.1-SNAPSHOT.jar
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.2.5.RELEASE)
2020-03-19 08:33:03.337 INFO 15324 --- [ main] com.wdbyte.Application : Starting Application v0.0.1-SNAPSHOT on DESKTOP-8SCFV4M with PID 15324 (C:\Users\83981\Desktop\springboot-mod
ule-demo\product-web\target\product-web-0.0.1-SNAPSHOT.jar started by 83981 in C:\Users\83981\Desktop\springboot-module-demo\product-web\target)
2020-03-19 08:33:03.340 INFO 15324 --- [ main] com.wdbyte.Application : No active profile set, falling back to default profiles: default
2020-03-19 08:33:04.410 INFO 15324 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2020-03-19 08:33:04.432 INFO 15324 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2020-03-19 08:33:04.432 INFO 15324 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.31]
2020-03-19 08:33:04.493 INFO 15324 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2020-03-19 08:33:04.493 INFO 15324 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1107 ms
2020-03-19 08:33:04.636 INFO 15324 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2020-03-19 08:33:04.769 INFO 15324 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2020-03-19 08:33:04.772 INFO 15324 --- [ main] com.wdbyte.Application : Started Application in 1.924 seconds (JVM running for 2.649)
2020-03-19 08:33:07.087 INFO 15324 --- [extShutdownHook] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor'
想必少了点什么,多模块不仅为了结构清晰,更是为了其他项目可以复用模块(如 common 模块),现在这个时候如果你新打开了一个项目,依赖 common
发现是引用不到的,因为你需要把模块安装到本地仓库。可以点击 IDEA -> Maven -> install,也可以通过 maven 命令。
# -Dmaven.test.skip=true 跳过测试
# -U 强制刷新
# clean 清理缓存
# install 安装到本地仓库
$ \springboot-module-demo> mvn -Dmaven.test.skip=true -U clean install
重新引入发现没有问题了。
文中代码已经上传到 Github: https://github.com/niumoo/springboot
这篇文章到这里就结束了,如果你觉得不错可以关注我的公众号一起交流。
公众号满载干货,童叟无欺。
最详细的 Spring Boot 多模块开发与排坑指南的更多相关文章
- Spring boot 多模块项目 + Swagger 让你的API可视化
Spring boot 多模块项目 + Swagger 让你的API可视化 前言 手写 Api 文档的几个痛点: 文档需要更新的时候,需要再次发送一份给前端,也就是文档更新交流不及时. 接口返回结果不 ...
- Spring Boot Web应用开发 CORS 跨域请求支持:
Spring Boot Web应用开发 CORS 跨域请求支持: 一.Web开发经常会遇到跨域问题,解决方案有:jsonp,iframe,CORS等等CORS与JSONP相比 1. JSONP只能实现 ...
- Spring Boot 多模块项目创建与配置 (一) (转)
Spring Boot 多模块项目创建与配置 (一) 最近在负责的是一个比较复杂项目,模块很多,代码中的二级模块就有9个,部分二级模块下面还分了多个模块.代码中的多模块是用maven管理的,每个模块都 ...
- Spring Boot 多模块项目创建与配置 (一)
最近在负责的是一个比较复杂项目,模块很多,代码中的二级模块就有9个,部分二级模块下面还分了多个模块.代码中的多模块是用maven管理的,每个模块都使用spring boot框架.之前有零零散散学过一些 ...
- Spring Boot 多模块项目创建与配置 (转)
转载:https://www.cnblogs.com/MaxElephant/p/8205234.html 最近在负责的是一个比较复杂项目,模块很多,代码中的二级模块就有9个,部分二级模块下面还分了多 ...
- Maven 搭建spring boot多模块项目(附源码),亲测可以,感谢原创
原创地址:https://segmentfault.com/a/1190000005020589 我的DEMO码云地址,持续添加新功能: https://gitee.com/itbase/Spring ...
- Maven 搭建spring boot多模块项目
Maven 搭建spring boot多模块项目 备注:所有项目都在idea中创建 1.idea创建maven项目 1-1: 删除src,target目录,只保留pom.xml 1-2: 根目录pom ...
- Spring Boot 企业级应用开发实战 刘伟东-2018年3月第一版
Spring会自动搜索某些路径下的Java类 并将这些类注册微Bean实例,这样就省去了所有Bean都配置在XML的麻烦 Spring会适当地将显示指定路径下的的类全部注册微Spring Bean . ...
- 图书-技术-SpringBoot:《Spring Boot 企业级应用开发实战》
ylbtech-图书-技术-SpringBoot:<Spring Boot 企业级应用开发实战> Spring Boot 企业级应用开发实战,全书围绕如何整合以 Spring Boot 为 ...
随机推荐
- Spring中@Resorce和@Autowired的区别
@Resource的作用相当于@Autowired,只不过@Autowired按byType自动注入,而@Resource默认按 byName自动注入罢了.@Resource有两个属性是比较重要的,分 ...
- SpringBoot + JPA + mariadb
SpringBoot + JPA + MariaDB 源码:https://github.com/ldl326308/LiveGreen-SpringBoot.git JPA持久层方法名命名规则:
- Spring Boot 鉴权之—— JWT 鉴权
第一:什么是JWT鉴权 1. JWT即JSON Web Tokens,是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519),他可以用来安全的传递信息,因为传递的信息是 ...
- react router为什么推荐使用browserHistory而不推荐hashHistory?
首先 browserHistory 其实使用的是 HTML5 的 History API,浏览器提供相应的接口来修改浏览器的历史记录:而 hashHistory 是通过改变地址后面的 hash 来改变 ...
- 使用 JavaScript 创建并下载文件
先上代码 Blob 对象 Blob URLs 模拟 click 小结 参考 本文将介绍如何使用 JavaScript 创建文件,并自动/手动将文件下载.这在导出原始数据时会比较方便. 先上代码 /** ...
- Archlinux 自动挂载移动硬盘,开机自动启动smb服务
Archlinux + Raspberry 打造NAS: samba篇 树莓派自动挂载硬盘,并开启smb服务. 开机自动挂在移动硬盘ntfs 安装ntfs-3g sudo pacman -S ntfs ...
- git push的完整形式
现在的情况是,本地有两个分支:master.div, 远程仓库有一个分支:master,本地master分支和远程master分支建立有跟踪联系,这样本地master分支提交时直接git push(只 ...
- STL标准库中的容器
容器:顾名思义,我的理解就是把同一种数据类型括起来,作为一捆.如vector<int> ,vector就是个容器,里面全是一个个的int型数据. 容器包括三大块: 顺序型容器: (1)ve ...
- react-native 使用leanclound消息推送
iOS消息推送的基本流程 1.注册:为应用程序申请消息推送服务.此时你的设备会向APNs服务器发送注册请求.2. APNs服务器接受请求,并将deviceToken返给你设备上的应用程序 3.客户端应 ...
- sublime Text3 前端常用插件
sublime Text3 前端常用插件 - File Switching (文件切换) --- Sublime Text提供了一个非常快速的方式来打开新的文件.只要按下Ctrl+ P并开始输入你想要 ...