0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Mavenのマルチモジュール例

Last updated at Posted at 2025-03-30

はじめに

mavenのビルドツールを使用しマルチモジュールで動作する場合の例を作成します。
mavenのビルドツールの理解において、とりあえず動いたものからpom.xmlについて理解、mavenのビルド等を理解していくという習うより慣れろです。

実施内容

WSL 上で動作確認できるシンプルな Maven マルチモジュールプロジェクトのサンプルです。my-app-parent という親プロジェクトの下に my-app-model(モデル)と my-app-web(Webアプリ)という構成になります。Spring Boot を使って、http://localhost:8080/hello にアクセスできる簡単なWebアプリを動かします。

ディレクトリ構成

my-app-parent/
├── pom.xml
├── my-app-model/
│   └── pom.xml
│   └── src/main/java/com/example/model/Greeting.java
├── my-app-web/
    └── pom.xml
    └── src/main/java/com/example/web/WebApplication.java
    └── src/main/java/com/example/web/HelloController.java

Spring Bootセット手順

1. Spring Initializr でプロジェクト雛形をダウンロード

🔗 https://start.spring.io/

設定は次のようにしてください:

項目
Project Maven
Language Java
Spring Boot 任意(例: 3.2.3)
Project Metadata group: com.example
artifact: my-app-parent
Packaging Jar
Java 17
Dependencies Web(spring-boot-starter-web)

Generate ボタンを押すと zip ファイルがダウンロードされます。

image.png

2. ダウンロード&展開(WSL内)

cd ~/Desktop/work  # 作業ディレクトリに移動(例)
unzip /mnt/c/Users/apple/Downloads/my-app-parent.zip
cd my-app-parent

Windows 側の ZIP ファイルを WSL から使う

WSL から Windows ファイルを見るには /mnt/c/ を使います。

ダウンロード場所を確認

通常、ブラウザでダウンロードした ZIP は以下にあります:

C:\Users\apple\Downloads\my-app-parent.zip

WSL では次のように見えます:

/mnt/c/Users/apple/Downloads/my-app-parent.zip

マルチモジュール構成へ変換

my-app-model フォルダを追加

mkdir my-app-model
mkdir -p my-app-model/src/main/java/com/example/model

my-app-model/pom.xml

<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.example</groupId>
    <artifactId>my-app-parent</artifactId>
    <version>0.0.1-SNAPSHOT</version>
  </parent>

  <artifactId>my-app-model</artifactId>
  <packaging>jar</packaging>
</project>

my-app-model/src/main/java/com/example/model/Greeting.java

package com.example.model;

public class Greeting {
    private String message;

    public Greeting(String message) {
        this.message = message;
    }

    public String getMessage() {
        return message;
    }
}

my-app-web フォルダを追加

mkdir my-app-web
mkdir -p my-app-web/src/main/java/com/example/web

my-app-web/pom.xml

<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.example</groupId>
    <artifactId>my-app-parent</artifactId>
    <version>0.0.1-SNAPSHOT</version>
  </parent>

  <artifactId>my-app-web</artifactId>
  <packaging>jar</packaging>

  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
      <groupId>com.example</groupId>
      <artifactId>my-app-model</artifactId>
      <version>0.0.1-SNAPSHOT</version>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build>
</project>

my-app-web/src/main/java/com/example/web/WebApplication.java

package com.example.web;

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

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

my-app-web/src/main/java/com/example/web/HelloController.java

package com.example.web;

import com.example.model.Greeting;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {
    @GetMapping("/hello")
    public Greeting hello() {
        return new Greeting("こんにちは、Spring Boot + マルチモジュール from WSL!");
    }
}

③ 親プロジェクトの pom.xml を修正

現在は Spring Boot の "親" になっていますが、マルチモジュールの "親" に変更しましょう。

置き換え後の my-app-parent/pom.xml

<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>

  <groupId>com.example</groupId>
  <artifactId>my-app-parent</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>pom</packaging>

  <modules>
    <module>my-app-model</module>
    <module>my-app-web</module>
  </modules>

  <properties>
    <java.version>17</java.version>
    <spring.boot.version>3.4.4</spring.boot.version>
  </properties>

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-dependencies</artifactId>
        <version>${spring.boot.version}</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>

  <build>
    <pluginManagement>
      <plugins>
        <plugin>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
</project>

✅ ビルドと起動確認

# 親プロジェクトのルートで実行
cd ~/Desktop/work/my-app-parent

# 依存関係ビルド
mvn clean install

# Webアプリ起動(my-app-web内で)
cd my-app-web
mvn spring-boot:run

🌐確認

ブラウザでアクセス:

http://localhost:8080/hello

👇 JSONが出れば成功!

{"message":"こんにちは、Spring Boot + マルチモジュール from WSL!"}

image.png

pom.xml

pom.xml の主な構成要素と役割

以下のような感じで分類できます:

1. <parent>:親プロジェクトの定義

マルチモジュールプロジェクトで共通設定をまとめたいときに使います。

<parent>
  <groupId>com.example</groupId>
  <artifactId>my-parent-project</artifactId>
  <version>1.0.0</version>
</parent>

🔹 役割:

  • バージョンや依存ライブラリの共通化
  • プラグインやプロパティの共通設定
  • 子プロジェクトでの <build><dependencies> の継承

2. <dependencies>:使用するライブラリの定義

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

🔹 役割:

  • プログラムで使う外部ライブラリを指定
  • Maven が自動でダウンロードしてクラスパスに追加

3. <build>:ビルドに関する設定

<build>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-compiler-plugin</artifactId>
      <version>3.8.1</version>
      <configuration>
        <source>1.8</source>
        <target>1.8</target>
      </configuration>
    </plugin>
  </plugins>
</build>

🔹 役割:

  • コンパイルやパッケージ化の設定
  • WAR/JAR のビルド手順
  • コンパイラのバージョン指定や JAR 名の指定など

4. <properties>:変数の定義

<properties>
  <java.version>1.8</java.version>
  <spring.boot.version>2.7.0</spring.boot.version>
</properties>

🔹 役割:

  • バージョンや環境設定の共通化・再利用
  • <dependency><plugin> の中で ${} を使って参照可能

🍝 他言語との違い

言語 / フレームワーク 依存管理ファイル 普段どれだけ意識するか
PHP (Laravel) composer.json ほぼ意識せず自動でOK(artisan がやってくれる)
JavaScript (React) package.json 開発者が必要最低限だけ記述
Java (Spring Boot) pom.xml ビルドもテストも全部ここが基盤
Python (Django等) requirements.txt or pyproject.toml ライブラリ管理用で軽量

Java では pom.xml に「親子関係」「バージョン依存」「プラグイン設定」などをガッツリ書くのが前提です。

親プロジェクトにあるこの記述って何なのか

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-dependencies</artifactId>
  <version>${spring.boot.version}</version>
  <type>pom</type>
  <scope>import</scope>
</dependency>

これは:

子モジュールが spring-boot-starter-web などを バージョン番号なしで使えるようにする共通設定

つまり、「バージョンはここでまとめて管理するから、子モジュールでは書かなくていいよ」っていう Maven の仕組みです。

子モジュール(my-app-web)では何をしているの?

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

これは:

「このモジュールは Webアプリケーションとして起動するから、必要なライブラリ一式(Tomcat, Jackson, Spring MVCなど)を入れてね」という指定です。

実際、これ1行で以下を全部まとめてくれるのが「starter」方式のいいところです:

  • Spring MVC
  • Jackson(JSON変換)
  • 内蔵Tomcat
  • エラーハンドリング etc...

Springの動き

「どうして /hello にアクセスすると JSON が返ってくるのか?」 を、Spring Boot の仕組みを含めて記載します。

流れ

Spring Boot は、以下の流れで動いています:

  1. ブラウザが /hello にアクセス
  2. HelloController.hello() メソッドが呼ばれる
  3. new Greeting(...) を返す
  4. Spring Boot(Spring MVC)が Greeting オブジェクトを 自動で JSON に変換
  5. ブラウザに JSON として表示される

各パーツの役割を分解して解説

🔹 @RestController

@RestController
public class HelloController {
  • @Controller + @ResponseBody の省略形
  • 「戻り値はHTMLではなくJSONなどのデータとして返します」という意味

🔹 @GetMapping("/hello")

@GetMapping("/hello")
public Greeting hello() {
  • /hello にアクセスが来たらこのメソッドを実行するというルーティング(URLマッピング)
  • 戻り値に Greeting を返す(=POJO)

🔹 new Greeting(...)

return new Greeting("こんにちは、Spring Boot + マルチモジュール from WSL!");
  • 単に Greeting クラスのインスタンスを作って返してるだけ

🔹 Greeting クラス

public class Greeting {
    private String message;

    public Greeting(String message) {
        this.message = message;
    }

    public String getMessage() {
        return message;
    }
}
  • message フィールドを持っただけのデータクラス
  • getter(getMessage)を持っているのがポイント!

🔹 自動で JSON にしてくれるのは誰?

Spring Boot に含まれる spring-boot-starter-web が内部で Jackson というライブラリを使っています。

  • Javaオブジェクト → JSON文字列 に変換
  • これは「シリアライズ」と呼ばれます

🔸 Jackson は以下のように変換します:

new Greeting("こんにちは")

こうなる

{"message":"こんにちは"}

Spring Bootの特徴だらけ

  • @RestController をつけるだけで「返すものはJSONだな」と判断してくれる
  • @GetMapping("/hello") でURLルーティング
  • Greeting はただのJavaクラスでも、getterがあれば勝手にJSONにしてくれる
  • 明示的に「JSONに変換しろ」って書かなくてもよい

まとめ

概念 実装したもの Springの役割
URLに応じた処理 @GetMapping("/hello") URLルーティング
コントローラー @RestController JSONとして返す
データを返す return new Greeting(...) Javaオブジェクトとして返す
JSONへの変換 Greeting + getter Jackson による自動変換

前準備

WSL設定

  • WSL 上に Java(JDK 8 以上)と Maven がインストール済み

maven

sudo apt update
sudo apt install maven

そして、優先パスを変えるか .bashrc.zshrc に以下を追記:

export PATH="/usr/share/maven/bin:$PATH"
source ~/.bashrc

Java

readlink -f $(which java)

例:/usr/lib/jvm/java-17-openjdk-amd64/bin/java

その後、以下を実行:

echo 'export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64' >> ~/.bashrc
echo 'export PATH=$JAVA_HOME/bin:$PATH' >> ~/.bashrc
source ~/.bashrc
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?