オンプレミス環境に Spring Framework 開発環境を構築するぞ

**このページは未完成人です** :cold_sweat:   

# はじめに

Java ベースのアプリケーションフレームワークである [Spring Framework](https://spring.io/) の開発環境をインターネット接続ができないオンプレミス環境へ構築しようという話です。

大きく、以下のテーマを取り上げます。

- Maven リポジトリサーバーの構築
- [Spring Initializr](https://start.spring.io/) のミラーを構築

コマンドの例は、Linux を基準に書いていますのでパスデリミタの / は環境に合わせて適宜、読み替えてください。

## 必要な知識等

- Java
- Apache Maven
- Git
- diff 出力が理解できること
- シェルまたはコマンドプロンプト
- 英語が読めなくてもページをそっ閉じしない気概 :stuck_out_tongue_winking_eye: 

# Maven リポジトリサーバーの構築

Spring Framework の依存ライブラリをキャッシュした Maven ローカルリポジトリ（ホームディレクトリの .m2 ディレクトリなど）を配布する手もありますが、メンテナンス性を考慮して Maven リポジトリサーバーを構築したいと思います。

Maven のリポジトリマネージャーとしては、公式でも使われている [Sonatype](https://www.sonatype.com/) の Nexus（[Professional Edition](https://www.sonatype.com/product-nexus-repository)、[OSS Edition](https://www.sonatype.com/nexus-repository-oss)）が有名なようですが、必要とするリソースや構築の容易性を考慮して [Apache Archiva](https://archiva.apache.org/) を使用したいと思います。

## 必要な環境

| 項目 | 説明 |
| :-- | :-- |
| JDK | 1.8 |
| ディスクスペース | Apache Archiva 展開時は 80M バイト程度ですが、実際にリポジトリをキャッシュしていくと G バイト単位で確保した方が良いでしょう。 |
| OS | Linux、Mac OS、Solaris、Windows |

### 2020/5/1 追記

以降の手順で「インターネットに接続できる環境にもデプロイします。」とありますが、インターネットに接続できる環境では、Apache Achiva を使わずに直接、Maven を使用し、ローカルの ~/.m2 にダウンロードし、~/.m2/repository の中身をターゲット環境の apache-archiva-2.2.4/repositories/internal へ何らかの手段でコピーすれば良いとご指摘を受けました。

## Apache Archiva のダウンロード

https://archiva.apache.org/download.html からダウンロードできます。

Tomcat を同梱したスタンドアロン版（tar.gz or zip）と WAR 版が選択できます。

既に稼働している Tomcat などの Java アプリケーションサーバーがあれば、WAR 版を利用する方が良さそうですが、設定ファイルの作成や依存ライブラリの配置などが必要です。詳細は、以下のリンクを参照してください。

- [Archiva Documentation – Installing Apache Archiva as a Web Application](https://archiva.apache.org/docs/2.2.4/adminguide/webapp.html)

ここでは、構築が簡単なスタンドアロン版を選択しました。

## Apache Archiva のデプロイ

ターゲットとするオンプレミス環境だけでなく、ターゲット環境にリポジトリの内容を移行するためにインターネットに接続できる環境にもデプロイします。それぞれの環境で以下の手順を踏んでください。

まず、アーカイブを展開します。リポジトリのディレクトリ階層が深くなることを考慮すると Windows の場合は、ドライブ直下など、できるだけ浅い階層に展開した方が良いと思います。

以下は、zip 版を unzip コマンドで展開する例です。（バージョン番号は投稿当時。）

```
$ unzip apache-archiva-2.2.4-bin.zip
```

展開ができたら、Apache Archiva を起動します。

```
$ cd apache-archiva-2.2.4/bin
$ ./archiva console
```

なお、サービス化する方法は、環境により異なりますので以下のドキュメントを参照してください。

- [Archiva Documentation – Installing Standalone Distribution of Apache Archiva](https://archiva.apache.org/docs/2.2.4/adminguide/standalone.html)

英語ですが、タイトルとコマンドの実行例が分かれば、何とかなると思います。

Apache Archiva が、起動出来たら、Web ブラウザーで http://localhost:8080/ にアクセスします。以下のような画面が表示されれば OK です。

![archiva.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36738/21cf784a-6e3a-7e2a-2b43-7b2948af07d1.png)

## 管理者ユーザーの作成

Apache Archiva の Web インターフェースの右上の方にある `Create Admin User` という赤いボタンをクリックします。管理者ユーザー作成用のフォームが表示されますので以下の必須項目を入力します。

- Password : パスワードを入力します。
- Confirm Password : 確認用に上記と同じパスワードを入力します。
- Email Address : メールを利用しない場合もダミーで良いのでメールアドレス風の文字列を入力します。

入力が完了したら、`Save` ボタンをクリックします。

### パスワードの有効期限について

デフォルトでは、パスワードの有効期限が90日で設定されています。この設定を変更したい場合は、次の手順を実行します。

- 左サイドのメニューから、`Users Runtime Configuration`をクリック
- `Properties` タブを開く
- ページナビゲーションで3ページ目を開く
- 以下の値を変更し、`Save`ボタンをクリック
  - security.policy.password.expiration.days : 有効期限を日数で入力
  - security.policy.password.expiration.enabled : 有効期限を設けない場合は、 false を入力

## Apache Archiva からアーティファクト（ライブラリ）を取得する設定

ホームディレクトリの .m2 というディレクトリに以下のような内容で settings.xml というファイルを配置します。（`localhost` の部分は適切なホスト名に変更します。）

```xml:settings.xml
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
	https://maven.apache.org/xsd/settings-1.0.0.xsd">
  <localRepository/>
  <interactiveMode/>
  <offline/>
  <pluginGroups/>
  <servers/>
  <mirrors>
    <mirror>
      <id>archiva.default</id>
      <url>http://localhost:8080/repository/internal/</url>
      <mirrorOf>external:*</mirrorOf>
    </mirror>
  </mirrors>
  <proxies/>
  <profiles/>
  <activeProfiles/>
</settings>
```

デフォルトでは、リモートリポジトリとして Maven Central が設定されているだけです。他のリポジトリも使用したい場合は、以下のリンクを参照してください。

- [Archiva Documentation – Using as a Repository](https://archiva.apache.org/docs/2.2.4/userguide/using-repository.html)
- [Archiva Documentation – Understanding Repository Configuration of Apache Archiva](https://archiva.apache.org/docs/2.2.4/adminguide/repositories.html)
- [Archiva Documentation – Understanding Proxy Connector Configuration of Apache Archiva](https://archiva.apache.org/docs/2.2.4/adminguide/proxy-connectors.html)

## 必要なアーティファクト（ライブラリ）の取得

インターネットに接続できる環境でにおいて、Maven プロジェクトで通常通り、`mvn` コマンドを利用します。通常、使うと思われる Goal や Phase を実行してください。（Spring Boot プロジェクトの場合は、同梱の `mvnw` を使用しても構いません。）

```
$ ./mvn spring-boot:run
$ mvn clean
$ mvn package
$ mvn test
```

上記で設定したホストから、ダウンロードされることを確認してください。

なお、Spring Tool Suite(Spring Tools for Eclipse) でも上記の設定を利用してくれます。

## ターゲット環境へリポジトリーをコピーしインデックスを更新

apache-archiva-2.2.4/repositories/internal 以下をターゲット環境の apache-archiva-2.2.4/repositories/internal へ何らかの手段でコピーします。

Apache Archiva の Web インターフェースにログインし、左サイドのメニューから、`Repositories` を選択し、`Action` というドロップダウンリストから、`Directories Scanning` を選択します。

![dir_scan.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36738/920b843a-5e69-c205-bc89-23c382494a1f.png)

しばらく時間がかかりますので時間をおいてから、左サイドのメニューから `Browse` を選択し、コピーしたディレクトリ等が表示されるか、確認します。

---

# Spring Initializr のミラーを構築

Spring Boot アプリケーションのひな形を生成できる [Spring Initializr](https://start.spring.io/) のミラーを構築します。

pom.xml を自力で書いたり必要なファイル構成が分かっていれば、必要ないとは思いますが、Spring Boot の手軽さが半減（言い過ぎ？）しますし、Spring Tool Suite(Spring Tools for Eclipse)との親和性も考慮して構築を行います。

:warning:  なお、以下の作業は、特に断りのない限り、インターネットに接続できる環境で行います。また、上記、Apache Archiva を経由する設定にしていると必要なライブラリが取得できないので一旦、設定を解除してください。（クライアント側）

:notebook_with_decorative_cover:  私は、Virtual Box 上の CentOS 8.1 に 20G バイトのハードディスクを割り当てて作業しましたが、色々、試している内に /tmp の使用量が肥大になり、ビルドが失敗する事象が発生しました。適宜、/tmp の中を掃除してください。

## start.spring.io を clone する

Spring Initializr の[ソース](https://github.com/spring-io/start.spring.io)は、GitHub で管理されています。以下のように clone します。

```
$ git clone https://github.com/spring-io/start.spring.io.git
```

## application.yml の修正（2020/05/30 bootVersions 修正）

clone したプロジェクトのままパッケージ化するとインターネットに接続できない環境で起動した際に以下のように選択できる Spring Boot のバージョンが、本家と異なってしまいます。（https://spring.io/project_metadata/spring-boot からメタデータを取得できないため。）

![no_internet.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36738/fd18267b-61a0-ee34-2cc0-1095dd92d6e3.png)

start.spring.io/start-site/src/main/resources/application.yml の `bootVersions` セクションを修正します。私の場合は SNAPSHOT 版は不要なので以下のように修正しました。

```diff
index 25dc9cb..2cd2e56 100644
--- a/start-site/src/main/resources/application.yml
+++ b/start-site/src/main/resources/application.yml
@@ -1431,12 +1432,17 @@ initializr:
       id: groovy
       default: false
   bootVersions:
-    - name : Latest SNAPSHOT
-      id: 2.2.0.BUILD-SNAPSHOT
-      default: false
-    - name : 2.1.1.
-      id: 2.1.1.RELEASE
+    - name : 2.3.0
+      id: 2.3.0.RELEASE
       default: true
+    - name : 2.2.7
+      id: 2.2.7.RELEASE
+      default: false
+    - name : 2.1.14
+      id: 2.1.14.RELEASE
+      default: false
 
 ---
 
```

:warning:  なお、`default: true` が確実に１つあるように修正する必要があります。すべて false になっていると画面が一瞬表示されたのち、真っ白になってしまいます。（経験者は語る） :warning: 

また、以下のように `bootVersions` セクションの次に `group-id` セクションを追加すると `Group` のデフォルトの値、`com.example` を `jp.co.example` に変更することができます。

```yaml
  group-id:
    value: jp.co.example
```

:warning:  インデントを `bootVersions` に合わせてください。 :warning:

### 2020/05/29 追記： 本家サイトに metadata の取得に行かないようにする

[古いリファレンスマニュアル](https://docs.spring.io/initializr/docs/0.3.x-SNAPSHOT/reference/htmlsingle/#_env_section)にしか記述がありませんが、 `initializr.env.springBootMetadataUrl` を空または null にすれば、本家に metadata を取得に行こうとしなくなります。

```diff
--- a/start-site/src/main/resources/application.yml
+++ b/start-site/src/main/resources/application.yml
@@ -24,6 +24,7 @@ spring:
 
 initializr:
   env:
+    springBootMetadataUrl: ""
     boms:
       azure:
         groupId: com.microsoft.azure

```


#### 参考

- [Local Spring Boot Version File · Issue #310 · spring-io/initializr](https://github.com/spring-io/initializr/issues/310)

> You can set initializr.env.springBootMetadataUrl to empty (or null), or to a location that you know will resolve correctly.

- [initializr/initializr-web/src/main/java/io/spring/initializr/web/support/DefaultInitializrMetadataUpdateStrategy.java](https://github.com/spring-io/initializr/blob/master/initializr-web/src/main/java/io/spring/initializr/web/support/DefaultInitializrMetadataUpdateStrategy.java)

```java
	@Override
	public InitializrMetadata update(InitializrMetadata current) {
		String url = current.getConfiguration().getEnv().getSpringBootMetadataUrl();
		List<DefaultMetadataElement> bootVersions = fetchSpringBootVersions(url);
		if (bootVersions != null && !bootVersions.isEmpty()) {
			if (bootVersions.stream().noneMatch(DefaultMetadataElement::isDefault)) {
				// No default specified
				bootVersions.get(0).setDefault(true);
			}
			current.updateSpringBootVersions(bootVersions);
		}
		return current;
	}
```

- [initializr/initializr-metadata/src/main/java/io/spring/initializr/metadata/InitializrConfiguration.java](https://github.com/spring-io/initializr/blob/master/initializr-metadata/src/main/java/io/spring/initializr/metadata/InitializrConfiguration.java)

```java
		private String springBootMetadataUrl = "https://spring.io/project_metadata/spring-boot";
/* (中略) */
		public String getSpringBootMetadataUrl() {
			return this.springBootMetadataUrl;
		}
```

## ビルド

[README.adoc](https://github.com/spring-io/start.spring.io/blob/master/README.adoc) にある通り、ビルドを行います。

```
$ cd start.spring.io
$ ./mvnw clean install
```

それなりに時間を要するので気長に待ちます。

## 動作確認

ビルドが問題なく終了したら、実際に起動してみます。できれば、インターネットに接続できない状態でテストすると良いでしょう。

```
$ cd start-site
$ ../mvnw spring-boot:run
```

起動が出来たら、 http://localhost:8080/ に Web ブラウザーでアクセスします。（過去に同じアドレスで他のサービスを動かしていた場合は、更新をかけてください。）

![change_group.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36738/47d125d0-7356-0627-916a-75510d7dc71e.png)

画面の幅によりデザインが異なりますが、上記のように表示できると思います。`Artifact` の変更、`Dependencies` の追加を行い、`Explore` や `Generate` が動作することを確認します。

## パッケージング

上記で問題なく動作していれば、パッケージングを行います。インターネットに接続して、以下のコマンドを実行します。

```
$ ../mvnw package
```

こちらもテストに時間がかかるので気長に待ちます。

パッケージングがうまくいくと `target` ディレクトリに `start-site-exec.jar` というファイルが生成されます。

## ターゲット環境へのデプロイ

何らかの方法で `start-site-exec.jar` をターゲット環境に配置します。以下のコマンドで起動します。

```
$ java -jar start-site-exec.jar
```

デフォルトのリッスンポート `8080` を変更したい場合は、`--server.port=ポート番号` を末尾に付与します。次の例は、ポート番号を `3000` に変更して起動します。

```
$ java -jar start-site-exec.jar --server.port=3000
```

:notepad_spiral: サービスとして起動したい場合は、以下のリンクなどを参照してください。

- [サービスとしてのSpring Bootアプリケーション](https://www.codeflow.site/ja/article/spring-boot-app-as-a-service) （機械翻訳のようなので読みづらいかもしれません。）

## Spring Tool Suite から利用する

### Initializr の設定

1. メニューから、`Window`→`Preferences` の順に選択し、設定画面を開きます。
2. 左側のカテゴリーから、`Spring`→`Boot`→`Initializr` を選択します。
3. `Initializr URLs` から、デフォルトの`https://start.spring.io`を`Remove`し、`New` でターゲット環境の Initializr の URL を追加します。

![sts_settings.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36738/f0a2d8fa-4695-4e52-c930-e34f6dfa7a8d.png)

画面の例のように変更できたら、`Apply and Close`をクリックします。
 
### Spring Starter Project の作成

`Package Explorer の何もないところで右クリック`→`New`→`Spring Starter Poject` を選択します。

以下のように設定した URL でインターネット接続環境と同様の作業が行えます。

![New_Spring_Starter_Project.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36738/5fc36c3d-ad02-bb8f-1686-c63807755bd5.png)

## 参考リンク

- [Spring Initializr Reference Guide](https://docs.spring.io/initializr/docs/current-SNAPSHOT/reference/html/)
- [spring-io/initializr: A quickstart generator for Spring projects](https://github.com/spring-io/initializr)
- [spring-io/start.spring.io: https://start.spring.io](https://github.com/spring-io/start.spring.io)
- [How to customize the Spring Initializr - Digital Frontiers — Das Blog - Medium](https://medium.com/digitalfrontiers/how-to-customize-the-spring-initializr-2439ecabb069)
- [Spring Sweets: Running Our Own Spring Initializr Server - Messages from mrhaki](https://mrhaki.blogspot.com/2016/06/spring-sweets-running-our-own-spring.html)