springboot学习第12期 - 多模块开发

157 阅读3分钟

本篇文章一步一步构建以下模块:

-- parent
    -- boot-starter // 启动模块, 只有这个模块有启动类和配置文件 (依赖api模块) 
    -- boot-api  	// 接口模块, 也可以取名web,看个人喜好(依赖service模块)
    -- boot-service  // 业务模块,写核心的业务逻辑(依赖repository模块和third-party模块) 
    -- boot-repository	// 访问数据库持久层模块
    -- boot-third-party	// 调用第三方接口
    -- boot-common	// 枚举等公共类 (被所有模块依赖)	

创建父项目

什么依赖不加,然后删除多余的文件,只留一个pom文件:

并修改pom文件:

1、添加 pom

2、artifactId 可以添加 - parent 结尾。

3、删除其他不需要的信息。

最后长这个样子:

<?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>3.5.4</version>
		<relativePath/>
	</parent>

	<groupId>com.congvee</groupId>
	<artifactId>weather-parent</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>weather</name>
	<description>Demo project for Spring Boot</description>

	<packaging>pom</packaging>

	<properties>
		<java.version>17</java.version>
	</properties>

</project>

添加模块

以添加starter模块为例子,其他模块都一样,唯一区别是 starter模块保留启动类和配置文件。

package name 可以在 weather 和 starter 添加个点,后面包扫描路径配置成 com.congvee.weather

整个过程可以先不添加依赖,后面我们统一添加,将不必要的文件删掉。

修改pom文件:

1、将weather-parent作为父

2、将其他的信息删掉

最后长这个样子:

<?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>com.congvee</groupId>
    <artifactId>weather-parent</artifactId>
    <version>0.0.1-SNAPSHOT</version>
   <relativePath>../pom.xml</relativePath>
  </parent>

  <artifactId>weather-starter</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <name>weather-starter</name>
  <description>weather-starter</description>

</project>

同时父pom文件,将starter模块添加进来:

<modules>
  <module>weather-starter</module>
</modules>

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>com.congvee</groupId>
      <artifactId>weather-starter</artifactId>
      <version>0.0.1-SNAPSHOT</version>
    </dependency>
  </dependencies>
</dependencyManagement>

后续将所有模块的所有用到的组件 统一 声明到 父pom中,并锁定版本,子模块引用的时候是不需要指定版本的。

使starter模块工作

父pom除了引入子模块依赖,额外声明以下依赖:

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
  <version>3.5.4</version>
</dependency>

<dependency>
  <groupId>org.projectlombok</groupId>
  <artifactId>lombok</artifactId>
  <version>1.18.38</version>
</dependency>

starter模块引入依赖:

  <dependencies>
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-web</artifactId>
      </dependency>
  </dependencies>

start模块启动类配置扫描包路径:

package com.congvee.weather.starter;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;


@SpringBootApplication(scanBasePackages = "com.congvee.weather")  // 关键
public class WeatherStarterApplication {

    public static void main(String[] args) {
        SpringApplication.run(WeatherStarterApplication.class, args);
    }

}

注意只有 starter模块才有配置文件,所有的配置统统配置到starter模块中。

然后尝试启动项目,能正常启动即可,starter模块配置结束。

使 api 模块工作

按照前面的添加模块示例,添加 weather-api 模块,并引入依赖:

<dependencies>
  <!-- 不推荐直接引入 spring-boot-starter-web, 会包含一堆不需要的东西 -->
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
  </dependency>

  <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
  </dependency>
</dependencies>

还需要在 starter 模块中添加 api 模块作为依赖:

<dependency>
  <groupId>com.congvee</groupId>
  <artifactId>weather-api</artifactId>
</dependency>

声明 HelloController 测试:

@RestController
@RequestMapping("/api/hello")
public class HelloController {

    @GetMapping
    public String hello() {
        return "Hello, World!";
    }

}

说明 api 模块也可以正常运行。

使 service 模块工作

按照前面创建模块的示例创建 weather-service模块。

添加依赖:

<dependencies>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
  </dependency>
</dependencies>

api模块需要添加service依赖:

<dependency>
  <groupId>com.congvee</groupId>
  <artifactId>weather-service</artifactId>
</dependency>

声明 HelloService:

@Service
public class HelloService {

    public String sayHello() {
        return "Hello, World! service";
    }

}

在 api 模块中调用:

@RestController
@RequestMapping("/api/hello")
@RequiredArgsConstructor
public class HelloController {

    private final HelloService helloService;

    @GetMapping
    public String hello() {
        return helloService.sayHello();
    }

}

说明service模块可以正常工作。

使 repository 模块工作

父pom声明新依赖:

			<dependency>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-starter-data-jpa</artifactId>
				<version>3.5.4</version>
			</dependency>

			<dependency>
				<groupId>com.mysql</groupId>
				<artifactId>mysql-connector-j</artifactId>
				<version>9.3.0</version>
			</dependency>

			<dependency>
				<groupId>org.flywaydb</groupId>
				<artifactId>flyway-core</artifactId>
				<version>11.7.2</version>
			</dependency>

			<dependency>
				<groupId>org.flywaydb</groupId>
				<artifactId>flyway-mysql</artifactId>
				<version>11.7.2</version>
			</dependency>

repository模块同样引入依赖:

<dependencies>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
  </dependency>

  <dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
  </dependency>

  <dependency>
    <groupId>org.flywaydb</groupId>
    <artifactId>flyway-core</artifactId>
  </dependency>

  <dependency>
    <groupId>org.flywaydb</groupId>
    <artifactId>flyway-mysql</artifactId>
  </dependency>
</dependencies>

service模块引入 repository模块:

<dependency>
  <groupId>com.congvee</groupId>
  <artifactId>weather-repository</artifactId>
</dependency>

然后声明sql文件存放在 repository 模块的 resource目录下的 db/migration 下,声明实体和Repository,这里就不过多讲述,可以参考之前的文章,关键词:springboot-data-jpa 和 flyway。

配置则放在 starter 模块中:

spring.datasource.url=jdbc:mysql://localhost:3306/multi-module
spring.datasource.username=root
spring.datasource.password=lkjhgfds
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

spring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect
spring.jpa.show-sql=true

这里还要做一个配置,还需要再启动类添加注解:

@EnableJpaRepositories(basePackages = "com.congvee.weather.repository")
@EntityScan(basePackages = "com.congvee.weather.repository")

Spring Boot 默认不会自动扫描其他模块的 Repository 接口,必须显式加 @EnableJpaRepositories

然后在service模块中调用:

@Slf4j
@Service
@RequiredArgsConstructor
public class HelloService {

    private final UserRepository userRepository;

    public String sayHello() {
        List<UserEntity> all = userRepository.findAll();
        log.info("All users: {}", all);
        return "Hello, World! service";
    }

}

正常打印信息,则说明repository模块也正常工作。

使 common 模块正常工作

common 模块主要存放常量,枚举等公共的类。

在common模块中定义工具类。

public class Utils {
    public static Integer add(int a, int b) {
        return a + b;
    }
}

然后 service 模块引入 common 模块:

<dependency>
  <groupId>com.congvee</groupId>
  <artifactId>weather-common</artifactId>
</dependency>

这样使用即可:

@Slf4j
@Service
@RequiredArgsConstructor
public class HelloService {

    public String sayHello() {
        Integer add = Utils.add(1, 2);
        log.info("add result: " + add);
        return "Hello, World! service";
    }

}