yoおさらい
ここ2,3ヶ月、AngularJSでアプリケーション作ってたんですが、
もう一つAngularJSでアプリケーションを作る事になり、
あれ、最初どうやったんだっけとボケてしまっていたので、
yoでひな形作るとこをおさらいです。
YEOMANによって、Yo, Grunt, Bowerが動作する環境です。
yo angular
で実行したディレクトリにAngularJSのひな形が出来上がります。
AngularJSのテンプレートが無い場合は、
npm install -g generator-angular
でインストールしておきます。
あとはもう
grunt server
でGruntでWebサーバが起動するので、ガシガシ実装します。
ひな形作る作業としてはこれだけですね。
いやー楽過ぎる。ミスもしないし。
AngularJSでSelectが一文字しか表示されない。
解決に苦労したので、メモ。
select書く場合、こんな感じですね。
<select ng-model="type" ng-options="item.val as item.name for item in types" disabled> </select>
これをモーダル表示させた場合、
http://i.stack.imgur.com/3kb0w.png
こんなんなります。IE9で発生します。Chrome、Firefox、IE10以降では発生しません。
試行錯誤した結果、
原因としては、ng-optionsからのng-repeatが発生する時に
既にブラウザではselectの幅が決定されている為、一文字しか表示されないのだと思います。
実際、
・素直にselect,optionを記述すると発生しない。
・ng-optionsを使わず、optionでng-repeatを使い、固定で何かoptionを追加指定すると、
固定で追加した分の文字のバイト数分だけは表示される。(hogeと追加すると4バイトは表示される。UTF-8)
IE9だけの為に個別対応はしたくないので、調べた所、解決策ありました。
angularjs - ng-options populated by ajax only displaying first letter in IE - Stack Overflow
<select ng-style="{'width': '100%'}" ng-model="type" ng-options="item.val as item.name for item in types" disabled> </select>
ng-styleで幅を100%にしてあげるだけでOKです。
よかったよかった。
Java7 Zip
Java7からnioにFilesが追加されたりと諸々ファイル周りのAPIが強化されてますね。
個人的には、Zipをライブラリに頼らず、Javaだけでサクッとやりたいと思ってました。
Zip File System Provider
まぁドキュメントやらgoogle先生に助けてもらって実装出来たんですけど、
圧縮は問題なさそうですね。
SimpleFileVisitorでディレクトリを探索して、Zipに追加って感じで。
相対パスをちゃんと考えないといけないので、
変数名を分かりやすくしとかないと若干混乱します。
で、解凍なんですが、圧縮と同じような考えでいけます。
解凍のほうがコードは短くすみます。
ただ、どうにも分からなかったのが、
手動で圧縮したファイルやJavaで圧縮したZipは問題なく解凍出来たのですが、
HttpClientで取得したファイルの解凍が出来ませんでした。
InputStream in = responce.getEntityInputStream(); byte[] bytes = ByteStreams.toByteArray(in); // guava File file = new File("C:/Users/nosa/AppData/Local/Temp/temp.zip"); Files.write(file.toPath(), bytes, StandardOpenOption.CREATE);
これを解凍したかったんですが、このZipをFileSystemに食わすと
java.util.zip.ZipError: zip END header not found at com.sun.nio.zipfs.ZipFileSystem.zerror(ZipFileSystem.java:1605) at com.sun.nio.zipfs.ZipFileSystem.findEND(ZipFileSystem.java:1021) at com.sun.nio.zipfs.ZipFileSystem.initCEN(ZipFileSystem.java:1030) at com.sun.nio.zipfs.ZipFileSystem.<init>(ZipFileSystem.java:130) at com.sun.nio.zipfs.ZipFileSystemProvider.newFileSystem(ZipFileSystemProvider.java:117) at java.nio.file.FileSystems.newFileSystem(FileSystems.java:322) at java.nio.file.FileSystems.newFileSystem(FileSystems.java:272)
が発生します。
昔ながらの方法(ZipFile,ZipEntry)の方法だと解凍出来ました。(もちろん手動でも解凍出来る)
また、zip4jでも解凍出来ました。
圧縮
File zipDir = new File(dirPath); final Path zipPath = zipDir.toPath(); // 圧縮 URI zipUri = zipFile.toURI(); URI uri = new URI("jar:" + zipUri.getScheme(), zipUri.getPath(), null); Map<String, String> env = new HashMap<>(); env.put("create", "true"); env.put("encoding", "UTF-8"); try (FileSystem zipfs = FileSystems.newFileSystem(uri, env)) { for (File srcFile : zipDir.listFiles()) { if (srcFile.isDirectory()) { // ディレクトリ Files.walkFileTree(srcFile.toPath(), new SimpleFileVisitor<Path>() { @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { // zipするディレクトリでのファイルの相対パス Path targetPath = zipPath.relativize(file); Files.copy(file, zipfs.getPath(targetPath.toString()), StandardCopyOption.REPLACE_EXISTING); return FileVisitResult.CONTINUE; } @Override public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { // zipするディレクトリでのディレクトリの相対パス Path targetPath = zipPath.relativize(dir); Files.createDirectory(zipfs.getPath(targetPath.toString())); return FileVisitResult.CONTINUE; } }); } else { // ファイル Path dest = zipfs.getPath(srcFile.getName()); Files.copy(srcFile.toPath(), dest, StandardCopyOption.REPLACE_EXISTING); } } }
解凍
// 解凍 URI zipUri = zipFile.toURI(); URI uri = new URI("jar:" + zipUri.getScheme(), zipUri.getPath(), null); Map<String, String> env = new HashMap<>(); env.put("create", "false"); env.put("encoding", "UTF-8"); try (FileSystem zipfs = FileSystems.newFileSystem(uri, env)) { final Path zipRoot = zipfs.getPath("/"); Files.walkFileTree(zipRoot, new SimpleFileVisitor<Path>() { @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { Path targetPath = Paths.get(toDir.toString(), file.toString()); Files.copy(file, targetPath, StandardCopyOption.REPLACE_EXISTING); return FileVisitResult.CONTINUE; } @Override public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { Path targetPath = Paths.get(toDir.toString(), dir.toString()); Files.createDirectory(targetPath); return FileVisitResult.CONTINUE; } }); }
うーん。SimpleFileVisitorの仕様は好きなんですけど原因分からず、zip4jに逃げようかと...。
Zipフォーマットを理解してからもう一度調べてみよう。
Zipが壊れてて手でも解凍出来ない、ZipFileでも解凍出来ないとかであれば、
良かったんですけど。
下記、大いに参考にさせて頂きました。
JavaSE ZIP圧縮/解凍 Java7 - @//メモ
JAX-RSとDI
JAX-RSの環境でDIを実現をしようとした場合、
JAX-RS2.0を前提として、組み合わせとしては
1.Jersey + CDI
JavaEE環境でそのまま使える。GlassFishとか。
2.Jersey + Spring
JerseyのDocumentにも記述があるので、JAX-RS2.0でも使えそう。
3.Jersey + Guice
jersey-guiceがJersey2.0に対応してない...(GuiceContainerがJersey1.0に依存?)
4.Jerseyのみ
RequestとResponceのインターセプタで代用。(適用箇所がリソースに限定される)
1→Tomcatで動かそうとするも挫折...
2→試さず。Guiceが使いたかった。
3→いい感じだったが、2.0に対応出来ず。
4→割り切ればいいと思ったが、割り切れず。
3に関しては、実現してる方もいるようですが、
ちょっとプロジェクトとして荷が勝ち過ぎる印象を受けました。
それなりにネットを彷徨いましたが、
JAX-RS2.0はリリースされてから、まだ日が浅く情報が少ない(新しい)です。
だもんで、まずは実績の多いJersey1.18+Guice3.0でやってみたいと思います。
Client APIとか1と2で結構違うので、出来れば2が良かったんですが...
Gradle Jetty から Maven Tomcat
Gradle使う時は、手っ取り早いんで
開発サーバとしてはJetty使うのが主流でしょうか。
ただ私の場合は、Jetty使うのを断念しました。
前提がEclipseを開発環境とした場合ですが、
理由として、
gradle jettyRunで起動するJettyが使いづらい
・EclipseからGradleタスクの実行では、デバッグオプションが付加出来ない?
・GradleのEclipseプラグインにはRunDebugがない為、Eclipseでリモートデバッグの構成が必要になる。
Jetty停止→Jetty起動→リモートデバッグ起動(この一手間がそこそこ苦痛)
Jetty と grunt で Java でもサクサク Web 開発 - Qiita
こちらの方のように組み込みJettyを自前で起動してしまえば、
上の問題は解決しそうですが、本番がTomcatなので、
開発と本番のアプリケーションサーバを同じにして、
スムーズに開発したいとの思いが強かったです。
GradleにもTomcatプラグインありますが、使う上での手順はJettyとあまり変わりません(たぶん)
まぁ、とは言え流れはMaven→GradleなのでGradleは使いたい。
という事で、
ビルド=Gradle
開発サーバ=maven-tomcat-plugin
でやるようにしました。
build.gradleを触る回数は限られるので。
yeomanインストール
yeomanインストールしたいんですが、
残念ながら私のPCはWindows7...
どしよかーと調べてたら、あるんですね。こんなのが。
Windowsアプリをコマンドラインからインストールする「Chocolatey」 (1) PowerShell上で動作するNuGet | マイナビニュース
http://decodize.com/css/installing-yeoman-front-end-development-stack-windows/
各パッケージのインストール先
chocolately自体はC直下でもよいのですが、
各パッケージがC直下に入るのは、正直困ります。
ProgramFilesに入れるか別に入れるかは、好みにもよると思いますが。
これは、前もって設定しておいたほうがいいです。
GitHub - chocolatey-archive/chocolatey: [DEPRECATED - https://github.com/chocolatey/choco] Chocolatey NuGet - Like apt-get, but for windows.
Chocolateyのセットアップ - bakemoji |> log
システム環境変数のchocolatey_bin_rootを指定したいフォルダ名にする(ドライブ名入れない)
事で変更出来ましたが、
変更出来るインストール先は、おそらくC直下にしか変更出来ないと思います。
もっと色々試せばよかったのですが、インストール、アンインストールに疲れました...
ただ、この設定でもlibjpeg-turbo64は、C直下にインストールされてしまいました。
ここで1つ、chocolately経由でyeomanインストールすると、
Ruby, Compass, Python, Git, PhantomJS, Node.js
がガーッとインストールされますが、Windowsの場合Nodeだけは
個別にインストールしたほうがいいと思いました。
chocolatelyでインストールされるNodeはV.0.8.?ですが、最新はv0.10.24です。
V.0.8だとひな形を作成するyo webappのコマンドが
Object #
トータルの手順は、
・cinst yeoman
でガーッとインストール。
・環境変数を確認。以下がパスに通っているか。
Ruby, Compass, Python, Git, PhantomJS
・Nodeをアンインストール、v0.10をインストール。
・yeoman initを使わずに、yo, grunt, bowerをnpm経由で個別にインストール。
npm install -g yo
npm install -g bower
npm install -g grunt
npm install -g grunt-cli
これらは、C:\Users\ユーザ名\AppData\Roaming\npm\node_modules
にインストールされるので、C:\Users\nosa\AppData\Roaming\npmをパスに通す。
・generatorをインストール。
npm install -g generator-webapp
・インストールしたgeneratorからひな形作成。
yo webapp
・gruntで確認。
grunt server
でいけました。(途中なんどもやり直してるので、確証はありませんが)
Windowsでyeoman(yo + grunt + bower)を使えるようにするには、
v0.9.6→v1.0.0で大きく変わってる事。そもそもLinuxベースのツールである事。
なので、個人的にはNodeベースのツールであることからも
Nodeをちゃんと使えるようにして、npmで
yo, grunt, bower
をそれぞれインストールしたほうがいいと思います。
JAX-RS
時代はJAX-RSって事で。
最初悩んだのがAPサーバを何にするかでした。
当初は、開発Jetty、本番GlassFishでやろうかと考えてました。
1. web.xml
色々情報があって噛み砕けてませんが、
GlassFish→web.xml不要
Jetty,Tomcat→web.xml必要(不要にも出来るらしい)
開発と本番でベースの設定が異なるのは避けたい。
2. デバッグ
Jettyのデバッグ環境をセットアップしていく中で、
gradle jettyRun
で起動しておき、Eclipseでリモートデバッグ。
これがそこそこ苦痛。これまでmaven-tomcat-pluginで
Eclipse内でTomcatの起動、デバッグがシームレスに行えていたので、
デバッグまでの手順と設定が多い事がネック。
Jetty組み込みも考えたが、シンプルさに欠ける感じ。
3.その他
・Gradleは今後の為にも使っておきたい。
・JAX-RSは是非使いたいが、JavaEEマストではない。
・GlassFishの商用サポートが無くなった。
などなど考えて、
開発Jetty、本番Tomcat
にする事にしました。
開発は、あえてGradleを使う事を優先しました。
これまで通りMaven,Tomcatのほうが設定も少なく、
開発しやすいのは分かっているのですが、
「Gradleを使っておきたい」が大きな理由です。
Gradle使うとなればJettyのほうが情報量が多いのでJetty採用。
デバッグの手間は我慢出来ないレベルではないかなと。後に楽なやり方を見出だせる事かも。
本番は、1の理由とGlassFishである絶対の理由が無いので、Tomcatで。
以上を踏まえて、Eclipse上でGradle、JAX-RSを使って、
Jettyで開発出来る環境を作ります。
・JDK 1.7.0_45
・Eclipse Standard 4.3.1
・Gradle 1.10(binをパスに通す)
それぞれダウンロードとインストール。
・Gradle IDEのプラグイン追加
http://dist.springsource.com/release/TOOLS/update/e4.3
Eclipse Integration for Gradle
EclipseからGradleプロジェクトが作成出来るようになる。
ディレクトリ構成とか手動メンドイので。JavaQuickStartでプロジェクト作成。
・Jettyの起動
EclipseのExternal ToolsでGradleのjettyRunタスクが実行出来ればよかったのですが、
どうにもビルドが途中で止まる(8%から進まない)。Jetty自体は起動している。
jettyStopタスクでも止まらない。他のタスクは動作する。
External Toolsを諦め、jettyRunタスクの起動スクリプトで実行させる事としました。
デバッグ起動する必要があるので、以下参考にデバッグモードで起動させます。
Struts 1.3 + Spring 2.5のサンプルアプリ(ついでにGradle化) - wadahiroの日記
set GRADLE_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=n gradle jettyRun
・起動したJettyにリモートデバッグ
EclipseのDebugからRemoteJavaApplicationで8787にアタッチ。
URLからGET、ブレークポイントが止まる、ホットデプロイ出来る、OK。
・WARデプロイ
gradle war
で作成したWARをTomcatにデプロイ。起動、URLからGET、OK。
・build.gradle
apply plugin: 'java' apply plugin: 'eclipse' apply plugin : 'jetty' apply plugin: 'war' sourceCompatibility = 1.7 version = '1.0' repositories { mavenCentral() } dependencies { compile 'javax.ws.rs:javax.ws.rs-api:2.0' compile 'org.glassfish.jersey.core:jersey-server:2.4' compile 'org.glassfish.jersey.containers:jersey-container-servlet:2.4' testCompile 'junit:junit:4.11' } task wrapper(type: Wrapper) { gradleVersion = '1.10' }
・web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <servlet> <servlet-name>ServletContainer</servlet-name> <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class> <init-param> <param-name>jersey.config.server.provider.packages</param-name> <param-value>com.hoge.resources</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>ServletContainer</servlet-name> <url-pattern>/rest/*</url-pattern> </servlet-mapping> </web-app>
JAX-RS(Jersey)いい。これはいい。ブラウザが近く?に感じます。
Gradleは正直、現時点ではMavenのほうが色々やりやすい印象です。
今後に期待です。