Spring BootとVue.jsを使ったシステムを作ってみた
前にこの記事を読んで、vue.jsを入門してた。
GUIアプリケーションアーキテクチャ総合!みたいなやつ書いてる - 猫型の蓄音機は 1 分間に 45 回にゃあと鳴く
実際にギョームで採用したいなーと思ったけど サーバサイドとの結合がよく分からなかったので、簡単なシステムを作ってみた。
vue.jsで作ったページのボタンをクリックすると、 Spring Bootで作ったHello World WebAPIを呼び出して、 値を画面に表示するっていう簡単なシステム。
出来る限り簡素な作りにしようと思って作った。 READMEに実装の手順を書いてみたので、参考になれば嬉しい。
フロントエンドはvscodeで実装して、 バックエンド(Java)はeclipseで実装するのが一番ラクだった。
ビルド周り凝り始めるとわかりづらくなるので書いてない。
vue.jsはわかり始めるとかなり書きやすいし、 DDD-like Layered Architectureに沿った作りにすると見通しも良くなりそう。
ギョームで使うにはまだ足りない機能が多い
- バリデーション
- ユーザ認証
- Flux的なやつ(vue.js storeでもよさそう)
今日やったリファクタリング - 2 : Enumの値と比較
今日じゃないけど、最近やったリファクタリング。
言語はC#.
enumって列挙型で、定数とかを定義するのに使います。
簡単な例で言うと、曜日とかを列挙したり。
public enum Days { Sat=1, Sun, Mon, Tue, Wed, Thu, Fri }
ただ、このままだと結構使いづらくて、こんなコードを書いてしまう場合もあります。
Before
// todayが火曜であることを確認する処理 string today = "4";//どこかから取得した値 bool b = ((int)Days.Tue).ToString().Equals(today); // 日曜かどうかboolを取りたい場合 bool b = ((int)Days.Sun).ToString().Equals(today);
ひたすらintにcastしてToString().Equals()…!
ダサいので、やめましょう。
After
今回リファクタリングした結果はこんな感じ。
public class Days { private enum _Days { Sat=1, Sun, Mon, Tue, Wed, Thu, Fri } private _Days val; private Days(_Days d) { this.val = d; } public static readonly Days Saturday = new Days(_Days.Sat); public static readonly Days Sunday = new Days(_Days.Sun); public static readonly Days Monday = new Days(_Days.Mon); public static readonly Days Tuesday = new Days(_Days.Tue); public static readonly Days Wednesday = new Days(_Days.Wed); public static readonly Days Thursday = new Days(_Days.Thu); public bool Equals(string value) { return Val().Equals(value); } public string Val() { return ((int)this.val).ToString(); } }
こんな風にenumをwrapするクラスを作りました。
そんで、使うときには、
// todayが火曜であることを確認する処理 string today = "2";//どこかから取得した値 bool b = Days.Tuesday.Equals(today); // 日曜かどうかboolを取りたい場合 bool b = Days.Sunday.Equals(today);
毎回castするよりかは可読性は上がりました。
今回は、C#の場合でしたが、Javaでも同じような書き方が出来ます。
Javaではenumに独自メソッド書けるけど、まぁどっちがいいやろかね。
この記事みた後だと、今回の修正後もダサく感じてきます。
C#ではこのやり方が一番良いかも!
以上。
今日やったリファクタリング - 1 : 連番付きフィールド
あまりの糞コードに遭遇し、怒りのリファクタリングを行った。
ついでに「こんなリファクタリングしたよ」と残しておくとなんか良さそうだなと思い付き、
久しぶりにブログを書き始めた。
今日したのは、言語はC#で、
フィールドに連番の付いたフィールドがあり、そのどれかに値が入っていることを調べる処理のリファクタリング。
モデルクラスは以下、
public class Model { // モデルのフィールドの構造は諸事情により、変更不可とする。 // メソッドなどは追加してOK。 public string Value1 { get; set; } public string Value2 { get; set; } public string Value3 { get; set; } public string Value4 { get; set; } public string Value5 { get; set; } public string Value6 { get; set; } public string Value7 { get; set; } public string Value8 { get; set; } public string Value9 { get; set; } public string Value10 { get; set; } }
このモデルに対し、別の処理でこのどれかに値が入ってくる。 どのValueNに値が入っているか、Nの数値を取得したい。
Before
public class BusinessLogic { public int GetValueIndex(Model model) { if(! string.IsNullOrEmpty(model.Value10)) { return 10; } else if(! string.IsNullOrEmpty(model.Value9)) { return 9; } else if(! string.IsNullOrEmpty(model.Value8)) { return 8; } else if(! string.IsNullOrEmpty(model.Value7)) { return 7; } else if(! string.IsNullOrEmpty(model.Value6)) { return 6; } else if(! string.IsNullOrEmpty(model.Value5)) { return 5; } else if(! string.IsNullOrEmpty(model.Value4)) { return 4; } else if(! string.IsNullOrEmpty(model.Value3)) { return 3; } else if(! string.IsNullOrEmpty(model.Value2)) { return 2; } else if(! string.IsNullOrEmpty(model.Value1)) { return 1; } else { return 0; } } }
あぁ!もう!!!
このIF文乱舞で嫌気が差さない場合は自分を疑ったほうが良い。
私が修正した結果がこちら
After
まず、ModelにValue達をDictionaryで返すメソッドを追加した。
public class Model { // モデルの構造は諸事情により、変更不可とする。 public string Value1 { get; set; } public string Value2 { get; set; } public string Value3 { get; set; } public string Value4 { get; set; } public string Value5 { get; set; } public string Value6 { get; set; } public string Value7 { get; set; } public string Value8 { get; set; } public string Value9 { get; set; } public string Value10 { get; set; } public Dictionary<int, string> GetValues() { return new Dictionary<int, string>() { {1, Value1}, {2, Value2}, {3, Value3}, {4, Value4}, {5, Value5}, {6, Value6}, {7, Value7}, {8, Value8}, {9, Value9}, {10, Value10}, } } }
このメソッドを利用して、BudinessLogicもこう修正した。
public class BusinessLogic { public int GetValueIndex(Model model) { return model.GetValues().Where(v => !string.IsNullOrEmpty(v)).Select(v => v.Key).Max(); } }
だいぶマシになった。
ついでにこの後、メソッド名もGetValueIndexでは意味が違っているので、GetMaxValueIndexに変更した。
リファクタリングはテストコードを書いて、現状のメソッド仕様を把握・テスト出来る状態にしてから取り掛かったほうが良いね。
以上。
Selenium WebDriverの画面キャプチャ 拡張子を変える
Selenium WebDriverでキャプチャを撮って、画像ファイルに保存するときに拡張子をjpeg、giff、pngなど変えるやり方。
普通にキャプチャをファイルに保存するには
public void takeScreenShot(Path outputPath) { System.out.println("= Screen Shot ="); File img = ((TakesScreenshot)this.webDriverInstance).getScreenshotAs(OutputType.FILE); try { FileUtils.copyFile(img, outputPath.toFile()); System.out.println("Name : " + outputPath.toFile().getAbsolutePath()); } catch (IOException e) { e.printStackTrace(); } }
selenium-javaの依存関係にcommons-ioが入っているので、特別追加しなくてもFileUtilsを使える。
画像の拡張子を指定して画像保存する
/** * 起動済みのブラウザでスクリーンショットを撮る。 */ public void takeScreenShot(Path outputPath) { System.out.println("= Screen Shot ="); File img = ((TakesScreenshot)this.webDriverInstance).getScreenshotAs(OutputType.FILE); try { FileUtils.forceMkdirParent(outputPath.toFile()); ImageIO.write(ImageIO.read(img), "jpeg", outputPath.toFile()); System.out.println("Name : " + outputPath.toFile().getAbsolutePath()); } catch (IOException e) { e.printStackTrace(); } }
javax.imageio.ImageIOクラスで以下の拡張子に対応してるらしい。
WriterFormatNames: BMP bmp jpeg wbmp png JPG PNG jpg WBMP JPEG
参考
typesafe/Config ConfigBeanFactoryの良さそうな使い方
設定ファイルを扱いたくて、イマドキどんな形式が良いんだろうなと調べてみたら、 typesafe/ConfigというライブラリでHOCONというファイル形式があるらしい。
紹介記事や簡単な使い方については、以下を参照。
Play Frameworkでも使われているコンフィグライブラリが非常に便利
で、
結論から言うと、 ConfigBeanFactory使うなら、typesafe/Config + lombok が良さそう!
typesafe/Configで、version 1.3から追加されたらしいConfigBeanFactoryクラスを使ってみた。
https://github.com/typesafehub/config#configbeanfactory
自作のjava beanクラス AppConfigを生成させている。
/** * application.confを読み込み、Beanで返す。 * @return AppConfig */ public static AppConfig getConfig() { return ConfigBeanFactory.create(load(), AppConfig.class); }
読み込ませたい設定ファイルは、こんな感じで、
webdriver { chrome=/usr/local/bin/chromedriver ie=/usr/local/bin/iedriver firefox=/usr/local/bin/firefoxdriver } output{ dirpath=. caseid=case image{ extension=jpg } } browser{ width=300 height=300 }
AppConfigクラスはこんな感じで、フィールド名と設定ファイルのkeyが一致している必要がある。
またフィールドに対応するgetter/setterを記述する必要があるが、
そこをlombokで生成(ここでは @Data)してあげることで、
簡易にConfigBeanを実装することが出来ている。
import lombok.Data; @Data public class AppConfig { private WebDriverConf webdriver; private OutputConf output; private BrowserConf browser; }
フィールドの型はこんな風にネストしてBeanを使うことも可能。
import lombok.Data; @Data public class WebDriverConf { private String chrome; private String ie; private String firefox; }
その他のクラスはgithubにおいてあります。
個人的にはConfigBeanを作ることで、設定のkeyを管理しなくて良くなったので嬉しかった。
でも欠点は、ConfigBeanの値を変更して設定ファイルに保存(シリアライズ)したい時に、typesafeのConfigやConfigObjectに再変換するのが大変なこと。 たぶん地道にMapにpushするみたく、withValueメソッドを呼びまくらないといけない。
少し調べてstackoverflowのどこかのページで、「typesafe/Configはimmutableな設定を扱うツールだよ :)」とあり、設定の変更はあんまりやらない思想なのかな?ということで諦めモード。
一応config.root().render()
でシリアライズされた文字列が返るので、それをファイルに保存してやれば良い。
ConfigObjectクラスのrenderメソッド
docpressをつかってみた
https://clashm45.github.io/electron-twitter-client/docpress-configuration.html
docpress Configuration
docpressのサンプルはキレイな色使いがされていますが、デフォルトでは白黒のみです。
docpressの作者よりcssが提供されているので、それを参照するようにしてあげると同じ色使いになります。
docpressの設定はdocpress.jsonに書きます。
docpress.json
{ "css": [ "http://ricostacruz.com/docpress-rsc/style.css", "docs/assets/custom.css" ], "markdown": { "typographer": true, "plugins": { "decorate": {}, "emoji": {} } }, "plugins": { "docpress-core": {}, "docpress-base": {} } }
すこしの手間でキレイにHTML化して見栄えの良いサイトになるので、よさ気ですゼ
plugins
docpressはmarkdownの装飾やコンポーネントの追加に、markdown-itを冠したパッケージを導入できるみたいです。
markdown-it-emojiを導入してみました。
:smile: > Classic markup: :wink: :cry: :laughing: :yum: > > Shortcuts (emoticons): :-) :-( 8-) ;)
twitter client for electronを写経してみた
WEB+DB PRESS vol.94の "作って学ぶElectron Webの技術でデスクトップアプリ!” を実践したコードをgithubで公開しました。
ソースコードはgihyo.jpの記事サポートページに公開されています。
コメントが書かれてないので、記事を読まないと初心者には理解できないと思います。
このプロジェクトもほぼ同じコードとなっていますが、自分なりのコメントを追加しています。
作って学ぶElectron Webの技術でデスクトップアプリ!
Electronを利用すると,JavaScript,HTML,CSSなどWebの技術を利用してデスクトップアプリを作成できます。 GitHubが開発していて,Atomエディタに使われているほか,Visual Studio Codeなどにも利用されています。 本特集では,実際にElectronを使ってアプリを開発しているエンジニアにより,Electronの基礎知識からはじめ,実際にサンプルアプリを作成して主要なAPIの使い方,デバッグ/テスト手法,そしてアプリを配布するための手順まで解説します。
Build
Node.jsと、デスクトップ・アプリケーションを作成できるNode.jsフレームワークElectronを使って作成します。
Electronは、JavaScriptとHTMLで実装します。 HTMLコンポーネントを作成するReactフレームワークも使います。
Dependencies
- "babel-plugin-transform-react-jsx": "^6.8.0",
- "babel-register": "^6.14.0",
- "photon": "git+https://github.com/connors/photon.git",
- "react": "^15.3.1",
- "react-dom": "^15.3.1",
- "twit": "^2.2.4"
パッケージのversionに"^"が入っている場合は、最新にアップデートされるらしいです。
実際に開発して公開などする場合は、固定のバージョンを指定するようにしたほうが良さそうです。
Build command
npmで依存パッケージをDLできます。 docpressも依存に追加しているのでDLされます。
npm i
実行コマンド
package.jsonに記述していますが、npmのscripts設定からelectronを起動しています。
npm run start
Document
ついでにdocpressというMarkdownで書くwebsite generatorが紹介されていたので、ドキュメントに使ってみました。
https://clashm45.github.io/electron-twitter-clientclashm45.github.io
Impressions
ちょうど個人的にElectronを勉強してたところでした。
この記事は、Node.jsとそのパッケージ管理ソフトnpmも、React.jsも実践できるのでいい教材です。
Electronはそう難しくなく、むしろReactの挙動を理解するまでが大変。
以上