【初めてのJava】Intellijでとりあえず動くものを作る

## 概要
Java初心者が、Intellijでプログラムを作って、パッケージ化して、とりあえず動くものを作るまでの手順です。

今回はキータのトップページのtitleの内容を取得するだけのプログラムを作ります。
Javaの勉強というより、Javaの開発の流れを知るためのtutorial的なものです。

## 環境
- macOS Sierra 10.12.6
- [jdk-9.0.1_osx-x64_bin.dmg](http://www.oracle.com/technetwork/java/javase/downloads/jdk9-downloads-3848520.html)
- Apache Maven 3.5.2
    - maven-assembly-plugin 3.1.0
    - Jsoup 1.10.2
- [IntelliJ IDEA Community Version: 2017.3.2](https://www.jetbrains.com/idea/download/#section=mac)

jdkとIntellijは上記リンクからダウンロードして、インストールしておいてください。

## プロジェクトの作成
Intellijを起動したら、 `Create New Project` をクリック

<img width="889" alt="Screen Shot 2017-12-27 at 9.49.30.png" src="https://qiita-image-store.s3.amazonaws.com/0/105936/c0d6b8df-16c4-be7c-f2be-a5b6eca6fab4.png">

`Maven` を選択して `Next` をクリック

<img width="1392" alt="Screen Shot 2017-12-27 at 9.50.50.png" src="https://qiita-image-store.s3.amazonaws.com/0/105936/9ed0d750-bb44-da62-f4ac-ecfd9eae49a6.png">


以下の値を入力して `Next` をクリック

| 項目 | 値 |
| --- | --- |
| GroupId | jp.sample |
| ArtifactId | sample-artifact |
| Version | デフォルト |

<img width="1392" alt="Screen Shot 2017-12-27 at 10.00.47.png" src="https://qiita-image-store.s3.amazonaws.com/0/105936/29177c2b-57d7-754a-2167-6fdb38628ba4.png">

Project nameと、Projectのファイルを設置する場所を入力して `Finish` をクリック

<img width="1392" alt="Screen Shot 2017-12-27 at 10.01.23.png" src="https://qiita-image-store.s3.amazonaws.com/0/105936/3a13fd2f-bf1e-a2fa-74e5-5bd80cc7b87f.png">

以下のような画面が表示されたら成功です。

<img width="1372" alt="Screen Shot 2017-12-27 at 10.02.46.png" src="https://qiita-image-store.s3.amazonaws.com/0/105936/2c82b687-4fcc-25ea-35d2-f07af0c5e3a8.png">


## pom.xmlを作成
プロジェクト管理のためのファイル。
RailsでいうGemfileみたいなものかな？

以下の内容で作成します。

```xml: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">
    <modelVersion>4.0.0</modelVersion>

    <groupId>jp.sample</groupId>
    <artifactId>sample-artifact</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>1.6</maven.compiler.source>
        <maven.compiler.target>1.6</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.jsoup</groupId>
            <artifactId>jsoup</artifactId>
            <version>1.10.2</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>RELEASE</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-assembly-plugin</artifactId>
                <version>3.1.0</version>
                <configuration>
                    <finalName>sample-${project.version}</finalName>
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                    <archive>
                        <manifest>
                            <mainClass>jp.sample.Main</mainClass>
                        </manifest>
                    </archive>
                </configuration>
                <executions>
                    <execution>
                        <id>make-assembly</id>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>
```

pom.xmlに追記したら、
右下に、 `Maven projects need to be imported` と表示された場合は、 `Enable Auto-Import` をクリック

<img width="1392" alt="Screen Shot 2017-12-28 at 17.53.45.png" src="https://qiita-image-store.s3.amazonaws.com/0/105936/9b056212-f611-e35a-98cf-c591336b0230.png">


## 各設定の説明
### dependencies
依存ライブラリの設定。
今回は以下のライブラリを利用します。

| ライブラリ名 | 用途 |
| --- | --- |
| Jsoup | スクレイピング用 |
| junit | テスト用 |

### properties
build時の以下のエラー回避のために記述する。

```
[ERROR] Source option 1.5 is no longer supported. Use 1.6 or later.
[ERROR] Target option 1.5 is no longer supported. Use 1.6 or later.
```

### maven-assembly-plugin
依存関係を全て含めたパッケージを作成するためのプラグイン。
archive -> manifestに、Main-Classを指定する。
これにより、Manifest.MFは不要となる。

```xml
<archive>
    <manifest>
        <mainClass>jp.sample.Main</mainClass>
    </manifest>
</archive>
```


## プログラムの作成
スクレイピングをするプログラムを作成します。

まず、Java Classを作成します。

<img width="1280" alt="Screen Shot 2017-12-28 at 17.55.34.png" src="https://qiita-image-store.s3.amazonaws.com/0/105936/c30ad733-edfe-2c8a-0cbd-de98ae781550.png">


`Main` という名前のクラスを作成します。

<img width="461" alt="Screen Shot 2017-12-27 at 11.43.07.png" src="https://qiita-image-store.s3.amazonaws.com/0/105936/dda0034d-8227-99d4-f59c-0d2ccc3e58b9.png">

作成されたらMain.javaに以下を記述します。

```java:Main.java
package jp.sample;

import java.io.IOException;

public class Main {
    public static void main(String[] args) throws IOException {
        final ScrapeService scrapeService = new ScrapeService();
        System.out.println(scrapeService.getTitle());
    }
}
```

同じ要領で、ScrapeService.javaを作成します。
キータのtitleを取得するプログラムです。

```java:ScrapeService.java
package jp.sample;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;
import java.io.IOException;

public class ScrapeService {
    private String url = "https://qiita.com/";

    public String getTitle() throws IOException {
        Document document = Jsoup.connect(url).get();
        Elements title = document.select("title");
        return title.text();
    }
}
```

Main.javaを開き、 `public class Main {` の左の再生ボタンをクリックして、 `Run 'Main.main()'` をクリックして、プログラムを実行させてみましょう。

<img width="1280" alt="Screen Shot 2017-12-28 at 17.11.01.png" src="https://qiita-image-store.s3.amazonaws.com/0/105936/87576060-51b2-633c-3901-5d4c6e7c9902.png">

すると、下のデバッガに、以下のような結果が表示されます。
キータのtitleが表示されれば成功です。

<img width="1392" alt="Screen Shot 2017-12-28 at 17.13.16.png" src="https://qiita-image-store.s3.amazonaws.com/0/105936/a8bfb8d5-6b93-b64a-34a6-f6a1cff868b3.png">


## テストコードの作成
次に、テストコードを作成します。

ScrapeService.javaを開いて、クラス名の `ScrapeService` にカーソルが当たっている状態で、 `Alt` + `Enter` を押します。

すると、以下の画像のように、 `Create Test` という選択肢が表示されるのでクリックします。

<img width="902" alt="Screen Shot 2017-12-28 at 17.15.49.png" src="https://qiita-image-store.s3.amazonaws.com/0/105936/769e69d1-55bd-2f97-b353-eb5791a93b50.png">

今回は、JUnit4を使います。 `FIX` というボタンが表示されている場合はクリックしてください。
`Generate test methods for:` の下にテスト可能なmethod一覧があるので、チェックしたら、OKをクリックします。

<img width="554" alt="Screen Shot 2017-12-28 at 17.57.41.png" src="https://qiita-image-store.s3.amazonaws.com/0/105936/cdfaa45c-5664-f9d8-b634-75e8794a1311.png">

すると、以下のように、テストコードファイルが作成されます。

<img width="1392" alt="Screen Shot 2017-12-28 at 17.59.34.png" src="https://qiita-image-store.s3.amazonaws.com/0/105936/f1234e8a-38f2-552f-c439-552b0b41f662.png">

そうしたら、以下のように編集してください。

```java:LoginServiceTest.java
package jp.sample;

import org.junit.Test;
import java.io.IOException;
import static org.junit.Assert.assertEquals;

public class ScrapeServiceTest {

    @Test
    public void getTitle() throws IOException {
        final ScrapeService scrapeService = new ScrapeService();
        assertEquals("Qiita - A technical knowledge sharing platform for programmers.", scrapeService.getTitle());
    }
}
```


`public class LoginServiceTest {` の左の再生ボタンをクリックして、 `Run 'Main.main()'` をクリックして、テストを実行させます。

<img width="1280" alt="Screen Shot 2017-12-28 at 18.05.53.png" src="https://qiita-image-store.s3.amazonaws.com/0/105936/a3e647a2-a85b-6b5b-05c4-3d3465564b4a.png">

以下のように、デバッガに表示されれば、テスト成功です。

<img width="1392" alt="Screen Shot 2017-12-28 at 18.06.41.png" src="https://qiita-image-store.s3.amazonaws.com/0/105936/617fcfe8-f077-5fe7-7461-de566071f07d.png">


## build
ビルドをして、パッケージ化します。
ここから先は、Intellijではなく、コマンドラインで操作します。

pom.xmlがあるsampleartifact/ディレクトリに移動して、以下のコマンドを実行します。

```
$ mvn package

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running jp.sample.ScrapeServiceTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 1.786 sec

Results :

Tests run: 1, Failures: 0, Errors: 0, Skipped: 0

[INFO]
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ sample-artifact ---
[INFO] Building jar: /Users/username/IdeaProjects/sampleartifact/target/sample-artifact-1.0-SNAPSHOT.jar
[INFO]
[INFO] --- maven-assembly-plugin:3.1.0:single (make-assembly) @ sample-artifact ---
[INFO] Building jar: /Users/username/IdeaProjects/sampleartifact/target/sample-1.0-SNAPSHOT-jar-with-dependencies.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 6.910 s
[INFO] Finished at: 2017-12-28T18:10:59+09:00
[INFO] Final Memory: 20M/67M
[INFO] ------------------------------------------------------------------------
```

## 生成されたjarファイルを実行

sampleartifact/targetに、 `sample-1.0-SNAPSHOT-jar-with-dependencies.jar` というjarファイルが生成されているので、実行してみます。

```
$ java -jar sample-1.0-SNAPSHOT-jar-with-dependencies.jar
Qiita - A technical knowledge sharing platform for programmers.
```

このようにキータのタイトルが表示されれば成功です！

## mvn install
`mvn install` をすると、 `target` の下だけでなく、 `~/.m2/` の下のLocal repositoryにもファイルが生成されます。

```
$ mvn install
```

```
$ ls -1 -a ~/.m2/repository/jp/sample/sample-artifact/1.0-SNAPSHOT/
.
..
_remote.repositories
maven-metadata-local.xml
sample-artifact-1.0-SNAPSHOT-jar-with-dependencies.jar
sample-artifact-1.0-SNAPSHOT.jar
sample-artifact-1.0-SNAPSHOT.pom
```

## targetディレクトリを削除する
以下のコマンドで削除できます。
targetを一度空にしてからbuildしなおすときに使います。

```
$ mvn clean
```

## 関連
- [MacでIntelliJ IDEAのDocker Pluginを使う設定手順](https://qiita.com/Esfahan/items/439711ddf4e3991ddc6a)

## 参考
- http://yuu.1000quu.com/use_maven_in_eclipse
- https://qiita.com/takahiroSakamoto/items/c2b269c07e15a04f5861
- https://qiita.com/opengl-8080/items/d4864bbc335d1e99a2d7
- [Let's Enjoy PhantomJS](https://qiita.com/satoshi_nishinaka/items/eb78d9a74b35d98dbb4e)
- [MavenでMANIFEST.MFを取り込む。](http://namihira.hatenablog.com/entry/2012/09/01/111901)
- [Mavenビルド](http://www.ne.jp/asahi/hishidama/home/tech/apache/maven/build.html)
- [mavenコマンドの使い方（主にgoal）について調べたのでメモ](https://kakakikikeke.blogspot.jp/2013/10/mavengoal.html)
- [Mavenの使い方](https://kengotoda.gitbooks.io/what-is-maven/primer/abstract.html)
- [Maven で依存 JAR ライブラリを target/dependency にコピー](http://blog.kymmt.com/entry/maven_dependency)
- [[Maven]mvnコマンドの備忘録](https://atuweb.net/201508_mvn_commands/)