Spring FrameworkでHUGっと!プリキュアを実装する
新春なのでSpring Frameworkの話
協力会社さん
「もぐのさん、今度のJavaの案件。Spring Bootを使ってもいいですか?DB処理とかサーブレットとか簡単にできるんで。」
も
「ああー?何それ?開発効率いいの?そう?まぁええんちゃう!うぇーい!」
協力会社さん
「できました!」
も
「おぅ…いいね!エモいね!ひゅー!!(え…読めない…何この@Autowiredって…)」
って事件が2019に発生。
そこから一年。
も
「Spring Bootぱねぇ!ってかSpring Frameworkがすごい!mikutter並みにすごい!!」
Hey! Everyone!Say!Spring!Spring!Foo!
すっかりSpringに洗脳された自分がいました。
もうこれは布教していかないと人類の損失ではないか!
そうだ!ブログを書こう!年末年始暇だし!!!
と、言う経緯で筆を取った次第です。
さて、皆さんにご説明するにあたり、なんか手頃なモデルが必要です。
抽象クラスが作れる程度の共通項がある何かで、インスタンスがいっぱい作れる奴・・・
と言うわけで、今回はプリキュアを題材にしてSpringのすばらしさをお伝えできればと思います。
プリキュアとはなんだ?(哲学)
とは言ったものの、プリキュアってよく知らないんですよね。僕おジャ魔女世代なので。
しかしながら変身シーンとかはなんとなく印象に残ってて、
- みんなで変身キーワードを叫ぶ
- 画面が4分割か5分割になって各々の変身シーンが流れる。
- 変身が終わったら一人一人にスポットが当たって、一言口上と変身後の名前を名乗る。(みんなのミラクル!キュアみらくるん!みたいな)
って感じだったかと。
この辺をモデル化してみましょうか。
package net.moguno.precure; public abstract class プリキュア { protected String チーム名; protected String 変身前の名前; protected String 変身後の名前; protected String 変身キーワード; protected String 名乗り; public String getチーム名() { return this.チーム名; } public String get変身前の名前() { return this.変身前の名前; } public String get変身後の名前() { return this.変身後の名前; } public String get変身キーワード() { return this.変身キーワード; } public String get名乗り() { return this.名乗り; } }
こんな感じすかね。
さて、モデルができたので次は具体的なプリキュアを実装します。
とは言っても特に当てもないので、このサイトからもぐのの好みの子を選ぶことにしました。
数時間の熟考の末、勝ち残ったのは「キュアエール」ちゃんでした!
チアのポンポンを振り回して戦うみたいです。可愛いです。
このシリーズは元々3人から始まって、後から双子が加入して5人で戦うお話らしいです。
変身のキーワードは全員共通で「ミライクリスタル!ハートキラっと!」。
これはベースクラスを作ってそこに実装した方がいいですね。
と言うわけで「HUGっとプリキュア」クラスと「キュアエール」クラスを作ってみることにします。
package net.moguno.precure; public class HUGっとプリキュア extends プリキュア { public HUGっとプリキュア() { this.チーム名 = "HUGっとプリキュア"; this.変身キーワード = "ミライクリスタル!ハートキラッと!"; } }
package net.moguno.precure; import org.springframework.stereotype.Component; @Component ←←←←←ポイント public class キュアエール extends HUGっとプリキュア { public キュアエール() { this.変身前の名前 = "野乃はな"; this.変身後の名前 = "キュアエール"; this.名乗り = "輝く未来を抱きしめて!みんなを応援!元気のプリキュア!キュアエール!"; } }
ここでのポイントは、クラスに@Componentアノテーションを付けておくことです。
こうしておくと別のクラスで@Componentクラスのフィールドを@Autowired付きで宣言したときに、実行時にSpringが勝手にシングルトンを作って代入しておいてくれます。
@component public class 例 { @Autowired protected キュアエール エールちゃん; ←←←←←← 実行時にキュアエールのインスタンス(シングルトン)が代入される }
いちいちnewする手間を省く便利な機能です。ここではね。ふふふ。
続いて、メイン処理になる変身シーンを実装していきます。
メイン処理はSpring Webを使ってWeb APIにしてみます。
package net.moguno.precure.restcontroller; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import net.moguno.precure.プリキュア; @RestController public class 変身シーンAPI { @Autowired protected List<プリキュア> プリキュアたち; @GetMapping("/metamorphose") public String 変身シーン() { StringBuilder セリフ = new StringBuilder(); Map<String, List<プリキュア>> チーム別 = this.プリキュアたち.stream() .collect(Collectors.groupingBy(プリキュア::getチーム名)); for (List<プリキュア> チームメイトたち : チーム別.values()) { String 変身前の名前 = チームメイトたち.stream() .map(プリキュア::get変身前の名前).collect(Collectors.joining("、")); セリフ.append(String.format("%s「%s」<br>", 変身前の名前, チームメイトたち.get(0).get変身キーワード())); } セリフ.append("<br>"); this.プリキュアたち.stream().map(メンバー -> String.format("%s「%s」<br>", メンバー.get変身後の名前(), メンバー.get名乗り())) .forEach(変身後のセリフ -> セリフ.append(変身後のセリフ)); return セリフ.toString(); } }
サーブレットの煩わしいお決まり処理をアノテーション一つで解決できちゃうのがSpring Bootのいいところですね。
さて、作ったAPIをWebブラウザでたたくと、こんな感じでキュアエールちゃんが変身します。
まだ一人分しかクラスを作ってないので寂しいですね。
まだ仲間が加入する前の第1話ってところでしょうか。
このプログラムを第5話「宙を舞え!フレフレ!キュアエトワール!」に改造する。
HUGっとプリキュアのあらすじを見ると、第2話でキュアアンジュ(青)、第5話でキュアエトワール(黄色)が加入するようです。
www.toei-anim.co.jp
www.toei-anim.co.jp
では、2人のクラスを定義して第5話の変身シーンを再現してみましょう。
package net.moguno.precure; import org.springframework.stereotype.Component; @Component public class キュアアンジュ extends HUGっとプリキュア { public キュアアンジュ() { this.変身前の名前 = "薬師寺さあや"; this.変身後の名前 = "キュアアンジュ"; this.名乗り = "みんなを癒す!知恵のプリキュア!キュアアンジュ!"; } }
package net.moguno.precure; import org.springframework.stereotype.Component; @Component public class キュアエトワール extends HUGっとプリキュア { public キュアエトワール() { this.変身前の名前 = "輝木ほまれ"; this.変身後の名前 = "キュアエトワール"; this.名乗り = "みんな輝け!力のプリキュア!キュアエトワール!"; } }
今回の改造個所はこの2人分のプリキュアクラスの追加のみ。
メイン処理には手を付けていません。
なぜなら、List<プリキュア>なフィールドに@Autowiredを付けると、クラスパスにあるプリキュアの派生クラスをすべて探してインスタンス化してくれるんです!!
なので、メイン処理をポリモフィズムやインターフェースを使った抽象化前提の設計にしておけば、後はクラスを足すだけでどんどんアプリを拡張していけるんです!
これがこのブログで伝えたいポイントです!(お前ここまで何文字使ったよ)
論より証拠と言うことで実行結果がこちら。
ちゃんとみんなで叫んで、個人が順番に口上を述べてますね。
Springの@Autowired機構の実力はこんなもんじゃありません。
もっとすごいことができるんです。
さぁ次に行くのです!
さらにこれを第22話「ふたりの愛の歌!届け!ツインラブギター!」に改造する。
あらすじを読み進めてみると、なんと第22話で初代「ふたりはプリキュア」のキュアブラックとキュアホワイトがゲストで登場するらしいです。過去作参戦は熱いですね!
ここではシリーズ間の壁をjarファイルで表現して、Springのヤバさを体感してもらおうと思います。
ふたりはプリキュア.jarにキュアブラック・ホワイトを定義して、それを今まで作って来たHUGっとプリキュア.warの世界に呼んで来ようという企画です。
まずは、HUGっとプリキュアと同じ要領で「ふたりはプリキュア」クラスと「キュアブラック」、「キュアホワイト」クラスを作ります。
package net.moguno.precure; public class ふたりはプリキュア extends プリキュア { public ふたりはプリキュア() { this.チーム名 = "ふたりはプリキュア"; this.変身キーワード = "デュアルオーロラウェーブ!"; } }
package net.moguno.precure; import org.springframework.stereotype.Component; @Component public class キュアブラック extends ふたりはプリキュア { public キュアブラック() { this.変身前の名前 = "美墨なぎさ"; this.変身後の名前 = "キュアブラック"; this.名乗り = "光の使者!キュアブラック!"; } }
package net.moguno.precure; import org.springframework.stereotype.Component; @Component public class キュアホワイト extends ふたりはプリキュア { public キュアホワイト() { this.変身前の名前 = "雪城ほのか"; this.変身後の名前 = "キュアホワイト"; this.名乗り = "光の使者!キュアホワイト!"; } }
あとは、HUGっとプリキュア.warのcontext.xmlに、ふたりはプリキュア.jarを読みこむように設定すれば準備完了です。
<Context> <Resources> <PostResources base="C:\Users\mogun\ふたりはプリキュア.jar" className="org.apache.catalina.webresources.JarResourceSet" webAppMount="/WEB-INF/classes"/> </Resources> </Context>
実行結果はこちら。
HUGっとプリキュアとキュアブラック・キュアホワイトとの夢の共闘が実現です!
(別途キュアマシェリとキュアアムールも実装してます。)
・・・って胸を熱くするのはそこではなくて。
Springの@Componentと@Autowiredを使えば、もはや本体のwarをいじることなく機能拡張が出来てしまいます。
これはもうプラグイン機構と言っても差支えがないのではないでしょうか。
これをSpring Bootと組み合わせると、さっきWebAPIを作るときに使った@RestControllerを別jarに置いて、プラグインでWebAPIを後から生やすことも可能です。
逆に本体の@Repositoryを@AutowiredしてプラグインからDBアクセスをしたりもできます。
自由です。ヤバいです。楽しいです!!Fuuuuuuu!!!
鬼長文になりましたがすこしでも伝わりましたでしょうか。Springのすごさ。
最後に、これを作ってて作りたくなったのを作って終わりにします。