LINE API × Spring Bootで“今日はご飯作りません”を通知するアプリをAIと開発してみた
こんにちは
突然ですが、皆さんには「あ〜、今日どうしてもご飯作りたくないな…」って日、ありませんか?私はあります。頻繁に。
そんな無気力な私の気持ちを、ワンボタンで夫のLINEにだけそっと(でも確実に)伝えたい。そんな欲望から、全ては始まりました。
今回は、この超個人的な野望を叶えるWebアプリケーションを、AIペアプログラミングツールと一緒に開発した激闘の記録をお届けします。
フェーズ1:構想と爆誕(所要時間:約30分)
最初のアイデアは至ってシンプル。
- ローカルで動くWebページにアクセスする
- 「通知」ボタンをポチッと押す
- 夫のLINEに「今日は料理をいたしません!」と通知が飛ぶ
これだけ。なんて簡単なんでしょう。
開発環境はJavaのSpring Boot。まずはpom.xml
にLINE Messaging APIのSDKを追加します。
<dependency>
<groupId>com.linecorp.bot</groupId>
<artifactId>line-bot-spring-boot-webmvc</artifactId>
<version>9.8.0</version>
</dependency>
次に、API呼び出しのためのLineService
と、Webからのリクエストを受け付けるNotificationController
をサクッと作成。フロントエンドは、とりあえずボタンが一つあるだけのシンプルなindex.html
を用意しました。
フェーズ2:立ちはだかる壁とデバッグの嵐
順調に見えた開発ですが、LINE APIを使う上で避けては通れない壁にぶつかります。そう、通知先(夫)のユーザーIDがわからない問題です。
ここからが、なかなかの長丁場でした。
-
WebhookでのID取得作戦:
ngrok
でローカル環境を一時的に外部公開し、LINEからのWebhookイベントを受け取るための/callback
エンドポイントを実装。夫にテストメッセージを送ってもらい、コンソールに表示されたユーザーIDを無事ゲット! -
謎のコンパイルエラー地獄: ユーザーIDをセットして、いざ本番の通知機能を実装!…と思いきや、ライブラリのバージョン互換性が原因でコンパイルエラーが多発。AIが光の速さで
import
文を修正したり、メソッドの呼び出し方を調整したりしてくれました。 -
Ambiguous Mappingの罠: 依存関係を整理する中で、
line-bot-spring-boot-handler
という便利なライブラリを追加したところ、今度は/callback
エンドポイントが重複しているというエラーが。自動でエンドポイントを作ってくれる機能が、自前の実装とコンフリクトしてしまったようです。結局このライブラリは削除することに。 -
恐怖の500エラー: Webhookがなぜかサーバー内部エラーに。原因は、リクエストボディの受け取り方。Springがよしなにやってくれるだろうと
InputStream
で待ち受けていたのが間違いでした。正しくはbyte[]
で受け取る必要があったのです。
このデバッグ作業、一人でやっていたら心が折れていたかもしれません。AIと「ああでもない、こうでもない」と対話しながら解決していく過程は、まさにペアプログラミングの醍醐味でした。
フェーズ3:機能は進化するよ、どこまでも
当初の目的は達成しましたが、人間の欲望は尽きません。
「通知のバリエーションが欲しいな…」
この一言で、機能は一気に拡張されます。
①ランダム通知機能
まずLineService
にメッセージの候補をリストで持たせ、送信時にランダムで選ぶように変更。
// LineService.java
private final List<String> messages = List.of(
"今日は料理をいたしません!",
"外で美味しいもの食べない?",
"疲れたからご飯作れませーん!",
"Uberしよ!",
"あなたの手料理が食べたいな(はぁと)"
);
public void sendRandomMessage() {
String message = messages.get(new Random().nextInt(messages.size()));
// (送信処理)
}
これでボタンを押すたびに違うメッセージが届く、ガチャ要素が加わりました。
②選択式通知機能
さらに、「ランダムじゃなくて、気分でメッセージを選びたい!」という要望に応え、フロントに選択ボタンを複数配置する方式に。
- 「外食な気分」
- 「Uberがいい」
- 「手料理作って欲しい」
- 「買ってきて欲しい」
ボタンごとにtype
をパラメータとして渡し、LineService
ではMap
を使ってtype
に応じたメッセージを送信するようにしました。
// LineService.java
private final Map<String, String> messages = Map.of(
"eat_out", "外で美味しいもの食べない?",
"uber", "Uberしよ!",
"cook_for_me", "あなたの手料理が食べたいな(はぁと)",
"buy_and_bring", "何か美味しいもの買ってきて!"
);
public void sendMessageByType(String type) {
String message = messages.getOrDefault(type, "今日も一日お疲れ様!");
// (送信処理)
}
これで、より詳細な「今日の私」を伝えられるようになりました。
フェーズ4:UIデザインの旅 〜平成からインターネット黎明期、そして再び平成へ〜
機能が完成したら、次は見た目です。ここからの展開が、我ながら一番面白かった。
① 第一次平成レトロ化
「なんかこう、気分が上がる感じにしたい。平成中期みたいなキラキラしたやつ!」
この無茶振りをAIに投げた結果、ドット文字フォントや動くヘッダーを備えた、まさにドンピシャなUIが爆誕しました。しかし、人間の欲望は尽きません。
② なぜか阿部寛リスペクトへ
平成レトロに満足したのも束の間、「やっぱり、阿部寛のホームページは外せない」という謎の使命感に駆られます。AIは寸分の狂いもなく、テーブルレイアウトと最小限のCSSで「あの」雰囲気を完全再現。さらに「背景に『SAORI-MUKIRYOKU』って透かし文字を斜めに入れたい」という画竜点睛なリクエストにも応え、唯一無二のページが完成しました。
③ 最終形態:帰ってきた平成レトロ(全部のせ)
ブログ用に「やっぱり平成風のスクショが欲しい!」と思い立った私。
「どうせなら、もっとすごいやつを!」という天啓のもと、平成ホームページの三種の神器をすべて詰め込むことを決意しました。
-
左右に動くヘッダー: これぞ
<marquee>
タグの真骨頂!ヘッダーが画面の端で跳ね返ります。 - アクセスカウンター: あなたが何人目の訪問者かをお知らせ。
- キリ番ゲット機能: 100番ごと、そして伝説の777番を踏んだ人には祝福のメッセージが!
<!-- index.html の一部 -->
<header>
<marquee behavior="alternate" scrollamount="8"><h1>.:*☆今日の気分☆*:.</h1></marquee>
</header>
<div class="container">
<!-- ... コンテンツ ... -->
<footer>
<p>アクセスカウンター: <span id="access-counter">0</span></p>
<p>(⊃´。・ω・。`)⊃━☆゚.*・。</p>
</footer>
</div>
<script>
// アクセスカウンターとキリ番機能
window.addEventListener('load', function() {
let count = localStorage.getItem('accessCounter');
count = count ? parseInt(count) + 1 : 1;
localStorage.setItem('accessCounter', count);
document.getElementById('access-counter').textContent = count;
if (count === 777 || count % 100 === 0) {
alert(`☆゚・*:.。.☆† キリ番GET †☆.。.:*・゚☆\\n\\nあなたは【${count}】人目の訪問者です!`);
}
});
</script>
こうして、実用性とネタ要素、そして私たちの青春時代のインターネットが完璧に融合した、世界に一つだけのアプリケーションが完成したのです。
まとめ
たった一つの「めんどくさい」から始まったこのプロジェクト。振り返ってみれば、LINE APIとの連携、壮絶なデバッグ、そしてWebデザインの歴史を巡る旅と、非常に中身の濃い開発体験となりました。
AIとのペアプログラミングは、アイデアを即座に形にし、エラーの解決を高速化し、そして何より「ちょっとアホなこと」に全力で付き合ってくれる最高の相棒でした。
この「夫への連絡網」アプリが、我が家の平和に貢献してくれることを祈って。
皆さんも、日常の小さな「めんどくさい」を、アプリ開発のネタにしてみてはいかがでしょうか?
あとがき
最後までお読みいただきありがとうございました。
改めまして、HacobuでQAエンジニアをしております、さおりんごと申します。実はこの「あとがき」以外の章のブログ内容は、すべてCursor(gemini-2.5)が書いています。
「こんな機能作りたいな~」「あれもほしいかも」と話しながら気づいたら完成。「ここまでチャットでやってきたことをブログにしたい。Markdown記法で書いて」と言ったら、このブログが出力されました。暇つぶしで始めた思いつきでしたが、とても面白い経験になりました。AIも述べている通り、デバッグの嵐は一人では心が折れていたことでしょう。また気が向いたら、Cursorとともに新たな「無駄アプリ」を生み出そうと思います。
ちなみに検証中、夫に届いたLINE履歴が大変なことになっていました(申し訳ない)。
Discussion