AngularJS+JAX-RSの環境構築(Maven,Grunt,grunt-maven-plugin)

以前[こんなエントリ](http://qiita.com/ko-aoki/items/6772963d7becec6c2495)を書いたのですが、イチから環境構築するとどんな手順にすればいいのか自分でもわからなくなるくらいだったので、まとめてみました。

ソースはこちら。
https://github.com/ko-aoki/angularJavaee

#環境
* Windows8.1
* JDK1.7
* NetBeans8.0.1
* GlassFish4.1
* Maven3.2.3
* node.js v0.10.32
* AngularJS 1.3.5

OSがWinでなんか申し訳ない感じ。
GlassFishは4.0だとCDIで障害あり。
NetBeans+GlassFishの手順はきしださんのエントリがわかりやすいです。
[WebSocketをネタにJava EE 7正式版を試してみる](http://d.hatena.ne.jp/nowokay/20130613)

nodeはnpm用に必要です。
nodeのインストールはmsi使用しました。msi使用するとnpmも自動インストールされるはず。

#概要

* MavenでJAX-RSアプリケーションのひな形を作成
* gruntでAngularJSのビルド環境構築
* maven-grunt-pluginでサーバサイドとフロントサイドのビルド環境の統合

#手順

##Java

###Mavenプロジェクトの作成

以下コマンドで作成しました。
groupId,artifactIdは適宜付け替えてください。

```:mvnコマンド
mvn archetype:generate -DarchetypeArtifactId=jersey-quickstart-webapp \
                -DarchetypeGroupId=org.glassfish.jersey.archetypes -DinteractiveMode=false \
                -DgroupId=example -DartifactId=angularJavaee \
                -DarchetypeVersion=2.13

```
こちらが大変参考になりました。
[Maven2使い方メモ２（Tomcat で JAX-RS）](http://qiita.com/opengl-8080/items/f36c570032e1a7555ed2)
[EclipseでJersey(JAX-RS)を始める](http://qiita.com/kamegu3/items/e492dacdb71a3f3a8c94)

###生成プロジェクトの修正
NetBeansで生成したMavenプロジェクトを「ファイル」-「プロジェクトを開く」でオープンします。

***
* pom.xmlの修正

生成されたpom.xmlに以下の修正をします。
* JavaEE7の依存性追加
* サーブレット2.x互換の排除
修正後は以下になります。

```: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 http://maven.apache.org/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <groupId>example</groupId>
    <artifactId>angularJavaee</artifactId>
    <packaging>war</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>angularJavaee</name>

    <build>
        <finalName>angularJavaee</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.5.1</version>
                <inherited>true</inherited>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.glassfish.jersey</groupId>
                <artifactId>jersey-bom</artifactId>
                <version>${jersey.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
                <groupId>javax.enterprise</groupId>
                <artifactId>cdi-api</artifactId>
                <version>1.1</version>
                <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.glassfish.jersey.containers</groupId>
            <artifactId>jersey-container-servlet</artifactId>
        </dependency>
        <dependency>
            <groupId>org.glassfish.jersey.media</groupId>
            <artifactId>jersey-media-moxy</artifactId>
        </dependency>
    <properties>
        <jaxrs.api.version>2.0</jaxrs.api.version>
        <jersey.version>2.13</jersey.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
</project>
```
***

* アプリケーションクラスの作成

先のリンク
[EclipseでJersey(JAX-RS)を始める](http://qiita.com/kamegu3/items/e492dacdb71a3f3a8c94)で説明されているのですが、アプリケーションクラスを作成します。
これで、web.xmlからJAX-RS記述を削除できます。

```java:WebResourceConfig.java
package example.angularjavaee.resource;

import javax.ws.rs.ApplicationPath;

import org.glassfish.jersey.server.ResourceConfig;

@ApplicationPath("webresource")
public class WebresourceConfig extends ResourceConfig {
    public WebresourceConfig() {
        packages(this.getClass().getPackage().getName());
    }
}
```

***

* web.xmlの作成

web.xmlはNetBeansで生成し直し。

```xml:web.xml
<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
	 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	 xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
	 version="3.1">
</web-app>
```

***

* ソース追加

Resource、Serviceクラスを作成します。
以前のエントリを踏襲してます。
http://qiita.com/ko-aoki/items/6772963d7becec6c2495

```:Javaソース構成
├─src
  └─main
      ├─java
        └─example
            └─angularjavaee
                ├─form
                │      LoginForm.java
                │      
                ├─resource
                │      LoginResource.java
                │      WebResourceConfig.java
                │      
                └─service
                        LoginService.java
                        LoginServiceImpl.java

```

##JavaScript

###クライアントサイド用フォルダ作成

* ```src/webapp```配下に```static```フォルダを作成します。

作成する位置、名称とも後述するgrunt-maven-pluginのデフォルト設定です。

* AngularJSファイル配置
```static```配下に```vendor```フォルダを作成し、AngularJSファイルを配置します。

###ソース追加

クライアントサイドのロジックを追加します。
こちらも以前のエントリを踏襲してます。
http://qiita.com/ko-aoki/items/6772963d7becec6c2495
※今回はRequireJSを使用していません。

```:JavaScriptソース構成
      └─webapp
          │  index.html
          │  
          ├─static
            ├─js
            │  ├─apps
            │  │  │  app.js
            │  │  │  controllers.js
            │  │  │  main.js
            │  │  │  services.js
            │  │  │  
            │  │  └─login
            │  │          login.tpl.html
            │  │          loginCtrl.js
            │  │          
            │  └─common
            │      └─services
            │              loginResource.js
            │              
            └─vendor
                └─angularJS
                        angular-resource.js
                        angular-route.js
                        angular.js
```

###ビルド用フォルダ作成

コンテキストルート配下に```target-grunt```フォルダを作成します。
gruntの実行フォルダになります。
作成する位置、名称とも後述するgrunt-maven-pluginのデフォルト設定です。

作成した```target-grunt```フォルダに移動し、以下の手順を実行します。

* grunt-cliのインストール（これはグローバルなので実行場所はどこでもいいです）
```npm install -g grunt-cli```

* package.jsonの配置
以下内容でpackage.jsonを```target-grunt```フォルダに配置します。

```js:package.json
{
  "name": "angularJavaee",
  "devDependencies": {
    "grunt": "^0.4.5",
    "grunt-contrib-clean": "^0.6.0",
    "grunt-contrib-concat": "^0.5.0",
    "grunt-contrib-copy": "^0.7.0",
    "grunt-maven": "^1.1.0"
  }
}
```

* npmパッケージのインストール

package.jsonで指定したパッケージをインストールします。

```npm install --ignore-scripts```

* GruntFile.jsの配置

ビルド結果を```target-grunt/dist```フォルダに格納する内容です。
こちらが大変参考になりました。
[JavaとJavaScriptの間に - MavenからGruntを起動する"grunt-maven-plugin"を使ってみました](http://java-and-js.blogspot.jp/2014/11/mavengruntgrunt-maven-plugin.html)


* ```copy```：テンプレートのhtmlファイルをコピー
* ```concat```：JavaScriptファイルを結合
* ```mavenPrepare```：ビルド対象をwebapp/staticからtarget-gruntにコピー
* ```mavenDist```:ビルド結果をtarget-grunt/distおよびtarget/コンテキストルートにコピー

参考：
https://github.com/allegro/grunt-maven-plugin
https://github.com/allegro/grunt-maven-npm 

```js:GruntFile.js
module.exports = function (grunt) {

    grunt.loadNpmTasks('grunt-contrib-concat');
    grunt.loadNpmTasks('grunt-contrib-clean');
    grunt.loadNpmTasks('grunt-contrib-copy');
    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-maven');

    grunt.registerTask('default', ['build']);
    grunt.registerTask('build', ['clean', 'mavenPrepare','concat', 'copy:templates', 'mavenDist']);

    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),
        distdir: 'dist',
        src: {
            js: ['js/**/*.js'],
            tpl: {
                app: ['**/*.tpl.html']
            }
        },
        clean: ['<%= distdir %>/*'],
        copy: {
            templates: {
                files: [{dest: '<%= distdir %>/partials/app', expand: true, src: '<%= src.tpl.app %>', cwd: 'js/apps/'}]
            }
        },
        concat: {
            dist: {
                src: ['<%= src.js %>'],
                dest: 'dist/js/<%= pkg.name %>.js'
            },
            angular: {
                src: ['vendor/angularJS/angular.js', 'vendor/angularJS/angular-resource.js', 'vendor/angularJS/angular-route.js'],
                dest: '<%= distdir %>/vendor/angular.js'
            }
        },
        mavenPrepare: {
            options: {
                resources: ['**']
            },
            prepare: {}
        },
        mavenDist: {
            options: {
                warName: 'angularJavaee',
                deliverables: ['js'],
                gruntDistDir: 'dist'
            },
            dist: {}
        },
    });

};
```

##MavenからGruntの実行

pom.xmlを編集して、MavenからGruntを実行できるようにします。
```maven-war-plugin```では、maven-grunt-pluginに処理を任せたいので、static配下を対象外としています。

```:pom.xml

<!-- 前略 -->
    <build>
        <finalName>angularJavaee</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.5.1</version>
                <inherited>true</inherited>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>pl.allegro</groupId>
                <artifactId>grunt-maven-plugin</artifactId>
                <version>1.4.1</version>
                <configuration>
                    <gruntBuildDirectory>target-grunt</gruntBuildDirectory>
                    <jsSourceDirectory>static</jsSourceDirectory>
                    <gruntOptions>
                        <gruntOption>--verbose</gruntOption>
                    </gruntOptions>
                    <filteredResources>
                        <filteredResource>maven-properties.json</filteredResource>
                        <filteredResource>gruntFile.js</filteredResource>
                    </filteredResources>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>create-resources</goal>
                            <goal>npm</goal>
                            <goal>grunt</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.3</version>
                <configuration>
                    <warSourceExcludes>**/static/**</warSourceExcludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

<!-- 後略 -->
```

これで、```mvn install```すると、targetは以下の構成になります。

```:target
├─angularJavaee
  │  index.html
  │  
  ├─META-INF
  ├─static
  │  ├─js
  │  │      angularJavaee.js
  │  │      
  │  ├─partials
  │  │  └─app
  │  │      └─login
  │  │              login.tpl.html
  │  │              
  │  └─vendor
  │          angular.js
  │          
  └─WEB-INF
        glassfish-web.xml
        web.xml
```

これでやっと終わりです！