yuusuke-roughの日記

Java,SpringBoot,趣味等

Spring Bootアプリケーションのデプロイ with AWS

はじめに

この度、公開するアプリケーションはWebSocketを使用します。

ついては、使用した事のないRoute53、AWS Shield、 ELBは今回の記事では扱いません。

今回の目標は、デプロイをし、ローカル環境と同様、正常に動作する事の確認のみ行います。

 

構成

予算は、130$ / 月なので、AWS Budgetsでアラートを設定します。

デフォルトは85%で通知のため、今回は、110$を超えると設定したアドレスに通知が届きます。

 

使用するEC2インスタンスは予算の都合上もあり、t3.nanoとします。

What is Amazon EC2? - Amazon Elastic Compute Cloud

インスタンスタイプ - Amazon EC2 | AWS

最大 3.1 GHz のインテル Xeon スケーラブルプロセッサ (Skylake 8175M または Cascade Lake 8259CL)

バーストパフォーマンスインスタンスに関する主要な概念と定義 - Amazon Elastic Compute Cloud

 

VPCは、一昨年あたりに無料利用期間枠で作成したものを流用します。

What is Amazon VPC? - Amazon Virtual Private Cloud

 

セキュリティグループでは、私からしSSH接続はしないので、ソースを「自分のIP」にします。

ストレージでは、Amazon EBSのgp2を使用します。

ハイパフォーマンスブロックストレージの料金 – Amazon EBS の料金 – Amazon Web Services

料金がわかりにくかったので調べました。

「料金設定が月単位」「課金が秒単位」のAWS EBSの料金計算 - Qiita

 

 

下記は、私がEBSを知らないため、備忘録として残します。

Amazon Elastic Block Store (Amazon EBS) - Amazon Elastic Compute Cloud

インスタンスの有効期間とは無関係に存続するストレージボリュームとして公開されます。これらのボリューム上にファイルシステムを構築できます。または、これらのボリュームをブロックデバイス (ハードドライブなど) を使用する場合と同じ方法で使用できます。インスタンスにアタッチされているボリュームの設定は動的に変更できます。

 

デフォルトでは、Amazon Linux 2 ベースの Amazon ECS に最適化された AMI(Amazon ECS に最適化された Amazon Linux 2 AMI、Amazon ECS に最適化された Amazon Linux 2 (arm64) AMI、および Amazon ECS GPU に最適化された AMI)には、1 つの 30 GiB のルートボリュームが付属しています。30 GiB ルートボリュームのサイズを起動時に変更して、コンテナインスタンスで使用可能なストレージを増やすことができます。このストレージは、オペレーティングシステム用と Docker イメージおよびメタデータ用に使用されます。

ストレージ側に設定をする容量は、そこまで大量に使用しない予定なので、デフォルトの8GBにします。

 

EC2インスタンス作成後

SSH接続のため、teratermをインストールします。

2023/9/4、現在、OSDNが不安定との事でGithubからダウンロードできるようです。

Releases · TeraTermProject/osdn-download · GitHub

後は、パブリックIPアドレスを使用して、鍵は発行したキーペアを使用します。

【SSH】公開鍵認証とEC2について - Qiita

 

AWS EC2 AmazonLinux2 MySQLをインストールする - Qiita

MariaDB用のパッケージがあるそうなので、こちらの記事に倣います。

MySQL :: MySQL 8.0 リファレンスマニュアル :: 2.5.1 MySQL Yum リポジトリを使用して MySQL を Linux にインストールする

 

Amazon Linux2 はRedHat7がベースだそうです。

MySQL :: Download MySQL Yum Repository

現在は、mysql80-community-release-el7-10.noarch.rpm

 

初期パスワードは、sudo grep 'temporary password' /var/log/mysqld.logで確認が取れます。

ログインできず、下記エラーが発生しました。

Job for mysqld.service failed because a fatal signal was delivered to the control process. See "systemctl status mysqld.service" and "journalctl -xe" for details.

 

ep 04 11:13:00 ip-何々.internal systemd[1]: mysqld.service failed.
Sep 04 11:13:00 ip-何々.us-east-2.compute.internal systemd[1]: mysqld.service holdoff time over, scheduling restart.
-- Subject: Unit mysqld.service has finished shutting down
-- Unit mysqld.service has finished shutting down.
-- Subject: Unit mysqld.service has begun start-up
-- Unit mysqld.service has begun starting up.
Sep 04 11:13:05 ip-何々.us-east-2.compute.internal kernel: [   7528]    27  7528   271536    85325  1069056        0             0 mysqld
Sep 04 11:13:05 ip-何々.us-east-2.compute.internal kernel: oom-kill:constraint=CONSTRAINT_NONE,nodemask=(null),cpuset=/,mems_allowed=0,global_oom,task_memcg=/,task=mysqld,pid=7528,uid=27
Sep 04 11:13:05 ip-何々.us-east-2.compute.internal kernel: Out of memory: Killed process 7528 (mysqld) total-vm:1086144kB, anon-rss:341300kB, file-rss:0kB, shmem-rss:0kB, UID:27 pgtables:1044kB oom_score_adj:0
Sep 04 11:13:05 ip-何々.us-east-2.compute.internal systemd[1]: mysqld.service: main process exited, code=killed, status=9/KILL
-- Subject: Unit mysqld.service has failed
-- Unit mysqld.service has failed.
Sep 04 11:13:05 ip-何々.us-east-2.compute.internal systemd[1]: Unit mysqld.service entered failed state.
Sep 04 11:13:05 ip-何々.us-east-2.compute.internal systemd[1]: mysqld.service failed.
Sep 04 11:13:06 ip-何々.us-east-2.compute.internal systemd[1]: mysqld.service holdoff time over, scheduling restart.
-- Subject: Unit mysqld.service has finished shutting down
-- Unit mysqld.service has finished shutting down.
-- Subject: Unit mysqld.service has begun start-up
-- Unit mysqld.service has begun starting up.

 

Sep 04 11:13:05 ip-何々.us-east-2.compute.internal kernel: Out of memory: Killed process 7528 (mysqld) total-vm:1086144kB, anon-rss:341300kB, file-rss:0kB, shmem-rss:0kB, UID:27 pgtables:1044kB oom_score_adj:0

 

【out of memory kill process】OOM Killerさんに殺されたくない - Qiita

スワップ領域の作成で不足分を補います。

Linuxでスワップ領域を作成する方法 - Qiita

 

…次回はJDKのインストールから行います。

 

設定の見直しはこちらを参考にしたいと思います。

【2022年版】Amazon EC2 ベストプラクティス - Qiita

感想

CPUの性能はサーバーというのもありますが、いまいち、ピンと来ません。

また、Out Of memoryで具体的に消されてしまったプロセスについては、後日、詳細を調べたいと思います。

 

chess.comでパズルレートが前アカウントの2000に戻りました。

また、リーグがエリートに上がりました。

 

AtCoderでのコーディング力強化と基本情報技術者試験対策は順調です。

後者はいつでもできるので、デプロイを第一優先とします。

 

旧前田侯爵邸に行ってきました。

チューダー様式の素晴らしい内観と外観は、包み込むような壮大な空間で落ち着きました。また、暖房が地下から温風を送る構造であったり、地下とを結ぶエレベーターが存在しているようです。

昭和五年といいますと、1930年、私の母方の祖父が生まれる一年前か同じ歳です。

歴史を感じます。

 

 

備忘録:Bucket4Jによるレートリミット

目的

ログイン、登録画面にレートリミットを導入します。

ログイン試行や登録処理の大量送信を避けるためです。

(他には、アカウント毎の試行回数制限(クライアントへ上限突破で通知等)、Webアプリケーション全体で適用するAWS ShieldとAWS WAFは検討中です。お財布に優しい範囲で...)

 

実装の前に

今回、使用する資料です。

Bucket4j 8.3.0 Reference

トークンバケット - Wikipedia(バースト等の用語理解にも...)

 

流れとしては、

バケツにトークンが入っていて、リクエスト毎に消費していく。

トークンは設定に基づいて補充される。

空になると429を返す。

 

具体的には...

Bucketインターフェース:最大容量のトークバケットを返す。

BandWidthクラス:バケットの制限を定義する。帯域幅を使用してバケットの容量と補充速度を設定する。

Refillクラス:トークンがバケットに追加される固定レート(一定時間内に追加されるトークン数)を定義する

スロットラー(Throttler):特定のリソースやサービスに対するリクエストやアクションの頻度を制限するための仕組みやツールを指す

 

Refillでは三種類の補充方法がある。

①Greedy:トークンが利用可能になり次第、頻繁に補充する。

②Interval:間隔を空けて補充する。例だと、補充してから一分後に100トークン。

③IntervallyAligned:特定の時間に補充する実装ができる。

 

感想

SpringSecurityから始まったセキュリティを考えた実装ですが、アプリが完成していくにつれて、力を入れるべき点だと思います。

もちろん、アプリケーション側の実装でもWebSocketを使用しているので、エスケープ処理や認可処理、改ざん対策等を考えています。

今後の方向性としましては、現状のまま進めて、何かしらのツールから脆弱性の診断を行う&セキュリティの学習を継続して改善していく...でしょうか。

 

余談

朝から晩までプログラミングをしています。

Bootstrapは使用してきましたが、操作により、要素を無くしたり、隠したり...動的に追加した要素にデザインを加えるのが、時間のロスに繋がったと思います。
JavaScriptの基礎はまだですが、調べ調べで望む実装にはできたと思います。

また、MDN Docsには、セキュリティで懸念する事項の記載があるので、そのまま勉強になります。

Element: insertAdjacentHTML() メソッド - Web API | MDN

Element: innerHTML プロパティ - Web API | MDN

等です。

 

なかなか記事を書く時間がないのが、心苦しいところです。

AWS基本情報技術者試験の学習、機械学習等を念頭に置いた数学の学習、コーディング力向上のため競プロ...後者になるにつれて、時間が取れない傾向にありますが、成果を出せる人になりたいので、可能な限り、続けます。

備忘録 + 日記

はじめに

 

外部APIからデータを取得し登録を行う処理の実装、リファクタリングと仕様変更を終えました。作業が膨大なため、なかなか記事を書けず。

後は、bucket4jによるリクエスト制限と最後の機能実装+αが控えているため、スケジュールはかなり詰め詰めですが、今年中のリリースはできそうです。

 

備忘録

2023-08-06T13:25:40.044+09:00[0;39m [33m WARN[0;39m [35m14244[0;39m [2m---[0;39m [2m[nio-8080-exec-9][0;39m [36m.w.s.m.s.DefaultHandlerExceptionResolver[0;39m [2m:[0;39m Resolved [org.springframework.beans.TypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'com.example.demo.model.book.Memo'; Failed to convert from type [java.lang.String] to type [java.lang.Long] for value '私は彼のように才気ある頭脳と覚悟を持ちたかった。']

パスとボディでパラメーター名が被っていた。

自戒を込めて...400なのでクライアント側?と思うが、バインドしているのはサーバーサイドなので、ログには気を付ける事。WARNの見落としに注意。

 

画像送受信について、Base64だと使用される文字が限定されるのでバリデーションは可能だが、クライアント側でデコードした時が気になる。

サーバーサイドでbyte[]に戻し、問題が起きないかチェックする方法を模索中。

画像表示+雑記

はじめに

前半にコーディング問題(AtCoder等)・後半に開発をしました。

まずは、前半のコーディング問題の記事を記載します。

普段あまり使用しないクラスや実装の考え方を備忘録としてピックアップしてまとめます。

画像表示はチャット機能の実装に無駄が多かったため修正にかなりの時間がかかりました。自戒を込めてまとめます。

 

内容

まず、組み合わせ。

threeWayPermutationって命名は失敗だったなぁ...。

順列の内、三つの値の順列を取得する。

この順列には{1,2,3}{1,3,2}{2,1,3}{2,3,1}...のように3!通りの重複を含む。

三つの値から構成される順列から重複を取り除いて終わり。

樹形図の考え方で落とし込む事ができた。

public static int combination(int n) {
        int duplication = 3 * 2 * 1;
        int threeWayPermutation =  1;
        for(int i=0; i < n - (n-3); i++) {
            threeWayPermutation = threeWayPermutation * (n-i);
        }
        
        int combination = threeWayPermutation / duplication;
        return combination;
    }

 

曜日のみの取り扱いのメモ

DayOfWeek (Java Platform SE 8)

int型で曜日を扱えるので便利。

Submission #43493719 - NEC Programming Contest 2022 (AtCoder Beginner Contest 267)

 

開発

従来は画像の受信・保存のみ実装。

STOMP over WebSocketは基本的に文字列でのデータ送受信となるので、base64で文字列に変換されたデータを送信し、サーバー側でbyteに変換し保存。(byteのメリットとしては、今後追加で行うモバイルアプリ開発ではRestAPIの実装を考えているため。)

 

この画像をリアルタイムで受信・後ほどアクセス時に表示・履歴取得ボタン押下で表示の3パターンの実装に追加した。

無駄は、サーバー側がロジック層で上記3パターンの処理を実装しているため冗長という点だ。本来はロジック層で既読管理とログ取得を一括で実装するべきだが、3パターン個別で実装してきたのとコントローラーで既読管理をしているというダメな実装をしていたので、優先度は低いが今後リファクタリングの対象となる。

後は、純粋に初めての実装だったのでフロント側に冗長なコードが多い。

全て削った。

 

Thymeleafで、いつもひっかかる部分を忘れずに書く。

変数式を含める際は、ただの結合だけで動作する。もう忘れない。

<img th:src = "'data:image/jpeg;base64,' + ${log.message}">

 

履歴取得については、「ログ取得ボタン押下」から「画面最上部で履歴を取得する」に変更。

トリガを「0pxの際にスクロールする事」とした。

また、履歴取得の際は、insertAdjustmentHTMLで要素を加えるだけなので、新しい履歴が覆いかぶさる問題が発生。

これは、履歴を加える際にダミーの要素を生成し、履歴を加えた後にscrollIntoView()でダミーの要素に戻る実装で対処。戻った後はダミーの要素を削除。

 

 

雑記

試合一週間前となりました。

仕事している期間も業務外の学習がひと段落している時期は二時間ほど練習してましたが、最近は密度が増えました。縄跳・サンドバッグ・ミット打ち・サンドバッグ打ち込み(か補強トレーニング)・スパーリングのメニューをしているので、準備運動含めて二時間ほどかかります。あっという間で楽しいです。

あと、先生のコーチングがかなりハイレベルだと思ってます。

前回の練習での私の課題点をつぶすように教えてくださいます。

また、説明が列挙ではなく、動作の要所で必要な指摘をピンポイントでくださるのですごく技術の習得が早くなります。

例えば、突然、押し合い状態で打撃を打つ技術を教わった際の話です。

先生が「押し返す。押し返す。」といいつつ、黙ってフックを打ちます。すると、私は押している状況なので、肘をあげる事でしかガードできません。次に先生がミットをボディに構えて「膝。」といいます。膝蹴りを打つと、押している状況なので体勢を維持しつつ攻撃します。

これが、「ガードして」って言われた場合は、片手を側頭部に置いたガードになってしまっていたでしょう。それをあえて言語化しない事で、私はこの技術の意味を理解できたわけです。

所感 2023/07/08~10

はじめに

今回は、近況と今後に分けて記載します。

 

近況

6月30日に会社を退職しました。

きっかけとなった案件については伏せます。

 

端的に書きますと、面接の頃からお伝えしていた「Javaの開発(テスト工程も含む)に行きたい。」という私の主張が、「開発と行ってもコードをいきなり書けるケースは少ない。なら、言語関係ないから、どの言語でもいいよね。」という社長の認識と終始合う事がなかった事が理由となります。

 

退職に至るまでに尽力した事は下記の通りです。

①待期期間を無くすため、入社後即、銀行端末の入れ替えと運用の業務となる旨を了承。勤怠管理怠らず。

②入社後、積極的に社内の競技プログラミング勉強会に参加。

③業務後、毎日二時間プログラミングに時間を割く(はてブロ投稿済みの開発内容・競技プログラミング・リファレンス読み込み等)。

④当初から主張している「Javaの開発(テスト工程も含む)へ行きたい」旨をしっかり伝え続ける。

⑤同じ未経験から先に入社した方を誘い、二人で勉強会を行う。(この方もテスト業務すら通らず、半年ほどで退職済)

 

Javaの開発案件にいくのが厳しい理由としてお話頂いた内容は下記の通りです。

①私のスキルシートでは現場経験がないとみなされるため。(個人開発は基本現場経験と見なされないとの事)

②先輩との抱き合わせで現場に入るといった交渉が不可のため。

 

と、営業の方も厳しい状況にも関わらず、私の希望に対して善処くださいました。

私も私で、早く開発に行くためにできる限りの事をしました。

様々な疑問は残りますが、SESとして一人で開発現場にいけるだけの実績がないためにこのような状況になったと考え辞める事を決意しました。

 

今後

一応、最後の1カ月はローコードで開発を設計書の修正と処理の実装、動作確認と広く浅く触れられたので、仕事選びでは下記をしっかり聞く事にします。

①担当させていただける工程はもちろん、その工程の次のステップへ行くために必要な判断指標を伺う。

②言語はJavaか、他言語の場合はチームでの参画か伺う。

③現場かリモートか伺う。

 

①は必須、②③は放置された経験があるので、コミュニケーションが取りやすい環境か確認する予定です。

 

次にプライベートの話。

まず、開発中のアプリは本日より再開します。

また、コーディング力においてはPaizaのAやAtCoderの難しめのCが解ける事を目安に再開します。

ムエタイは月に2回試合に出る予定です。

いずれも思う通りに行かない事が多いでしょう。ただ、そこで得たフェードバックから日々修正していけるよう前向きに取り組みます。

 

今回の上京では、生活費・引っ越しの費用諸々で100万円以上の痛手でしたが、現実を知るという意味では、このうえなく価値のある時間だったと思います。

転職活動をしてダメだった場合は、もう無理に職としてプログラマーを目指す必要はないと思います。その時は、個人開発の継続と他業種のバイトなりして最低限度の生活を維持しつつ、ムエタイをしっかり学び、戦歴を重ねて、思い残す事なく実家に帰ります。

 

-------------------------------------------------------------------------------------------

追記

7月9日はムエタイの試合でした。

結果は判定負け。課題点は、蹴りを含めたコンビネーション、スタミナ、首相撲です。

また、モーションが大きく、力んでしまうのを止めたいので場慣れも大きな壁となります。積極的にスパーリングに参加し、対策していきたいです。

10日はPaizaのスキルチェックと履歴書・職務経歴書の作成・ポートフォリオリポジトリに公開するといった作業となりました。

8日がプロジェクト全体の仮実装で残しておいたコードの現時点での要否を仕分ける作業をしていた状況なので、11日からアプリ開発の本格的な再開となります。

所感 2023/05/27

2023年3月より、ずっと既存機器入れ替えの運用でした。

毎日、帰宅後は今まで開発していたWebアプリの製作と単体テスト等、社内勉強会で皆さまが参加している競技プログラミングの勉強を二時間ほどしていました。

先月の今頃に開発案件を探していただけることになり、今日に至ります。

結果としては、決まらないようです。

 

会社の方々も現在の現場の方も、前職の方々も皆様良い人たちで、環境には恵まれていたと思います。

 

ただ、私はPGになりたくてIT業界に入りました。

その事をいつも伝えてきました。

経歴的に無理だと理解し、全然関係のない故障受付業務をしていた数年前から、報われず、ネガティブになる状況でも何とか気持ちを前向きに維持して進めてきました。

いつか素人みたいな環境から抜け出して、ちゃんとした技術者の環境に身を置いて、今開発しているWebアプリを立派な製品にしてやりたいと思い続けてきたからです。

 

でも、半年以上の実務経験が必要な案件でも、Java触れている人ならOKな案件でも面談にすらたどり着けません。

 

自身の才能の無さに呆れました。

よくTwitterで偉い方々の間で論じられる「市場価値が無いから」の一点に尽きるにしても、とんと入ってしまう人はいるわけで...ここまで無意味な遠回りをしている私はお呼びでないわけです。

 

昔、カジュアル面談をしてくださった面接官の方々は「良いPGになれる」と言ってくださったりしましたが、上辺の話だったのでしょう。

もう永遠に未経験でいるのが嫌になって、ずっと参加していたJavaのオープンチャットも退会し、一週間コードを書かない日を経験しました。

 

疲れました。

人生を変えられる人もいるのでしょうが、変えられない人も山のようにいるわけで、私は変えられると信じて善戦したと思います。

結果は結果です。

ここからどうするかは、今のアプリ開発を続けながら、ゆっくり決めます。

 

バリデーション in STOMP over WebSocket、画像保存 in Spring Boot 2日目(もっとかかってる)

ヘッダーの値によって変換処理を行い、DBに格納する

java - Reading HTTP headers in a Spring REST controller - Stack Overflow

RequestHeader (Spring Framework API) - Javadoc

 

 @RequestHeader(name="Content-Type") String contentType

で、ヘッダーにアクセスしようとすると...

Content-Typeは:{"message":"テスト","roomId":"498894c2-a9e4-4b62-aaf0-4869e2f6b02d"}

なぜかメッセージの中身が現れた

 

MessageでのHeaderへのアクセスは下記。

Header (Spring Framework API) - Javadoc

Content-Typeは:application/json

※日記記事以外でまとめる予定

 

実装前に...

画像を送信すると下記エラーがでた。

org.springframework.messaging.simp.stomp.StompConversionException: STOMP 'content-length' header value 142026  exceeds configured buffer size limit 65536

 

25. WebSocket Support

25.4.15

WebSocketMessageBrokerConfigurer (Spring Framework API) - Javadoc

configureWebSocketTransport(WebSocketTransportRegistration registry)を使用して設定。2MB以下なら数秒で送受信できた。

 

続いて、画像はbyte型に変換し、BLOB型のテーブルに保存する。

その前に...Lineで桜の写真を送信したのだが、これが5.5MBであった。これをLine側で保存すると、あまり画質を損なわずに843KBになっていた。

実際に送った写真をこちらに送り、imageフォルダーに書き込む。

String path = "src/main/resources/static/image/test.jpeg";        
            File file = new File(path);
            FileOutputStream outputStream = new FileOutputStream(file);
            outputStream.write(imageData);
            outputStream.close();

結果は、843,684 バイト。

image-compressionで指定した1MB以下はちゃんと適用されている。

 

JPAでのMySQLへの保存は下記

Springboot+JPAでbyte配列をMYSQLに登録したい

詳細

Column (Jakarta EE 仕様 API) - Javadoc

 

Data truncation: Data too long for column 'image' at row 1

 

MySQL側を確認すると...tinyblobになっていた。

mysql> show columns from chat_message where Field='image';
+-------+----------+------+-----+---------+-------+
| Field | Type     | Null | Key | Default | Extra |
+-------+----------+------+-----+---------+-------+
| image | tinyblob | YES  |     | NULL    |       |
+-------+----------+------+-----+---------+-------+
1 row in set (0.00 sec)

 

DDLを生成する時に使用されるとあるので、DBをリセットして動かすとMediumBlobになった。

(ただのSELECTだけで見ようとすると大変な事になる...SQL勉強しないと...。)

 

フロントで受け取った画像を表示する

①SUBSCRIBEした画像を表示する

②DBから受け取った画像をメッセージの受け取り時刻と揃えて表示する

続いて、受信したmessageはデコードしてbyteで渡してあげる。

 

document.getElementById('contributor' + nowLow).value = chatLogs[i].id;
document.getElementById('MessageLog' + nowLow).value = chatLogs[i].message;

(かな~り前のコードだったから忘れていた...)

レスポンス自体には、メッセージと画像を別々に持たせているので、送る事さえできれば問題ない。

 

過去ログ取得と新規ログ取得をわける。

問題は、「URL毎の認可処理が完了しているユーザーにだけアクセス時に既読管理の時間を更新する」という実装。

既読管理の更新時間は①入室②退出orブラウザバックの2点のみ。

 

以上、今回の実装は、入室時点での既読管理更新をURL認可時点で行う

URL認可のところに追記で終わり(前作成した構成とつけていた変数のせいですごく冗長にせざるをえなかった...)

if(alreadyReadTimeRepository.findByAlreadyReadUserAndTargetRoom(participatingUser, room) != null) {
                    AlreadyReadTime alreadyReadTime = alreadyReadTimeRepository.findByAlreadyReadUserAndTargetRoom(participatingUser, room);
                    alreadyReadTime.setAlreadyReadTime(LocalDateTime.now());
                    alreadyReadTimeRepository.save(alreadyReadTime);
                }else {
                    AlreadyReadTime alreadyReadTime = new AlreadyReadTime();
                    alreadyReadTime.setAlreadyReadTime(LocalDateTime.now());
                    alreadyReadTime.setAlreadyReadUser(participatingUser);
                    alreadyReadTime.setTargetRoom(room);
                    alreadyReadTimeRepository.save(alreadyReadTime);
                }

 

次にブラウザバックだが、これは再入室で自動で更新されるから問題はない。

次に退出。SessionDisconnectEventでいいしょう。

25. WebSocket Support

25.4.12

RoomのURLはヘッダーで管理していたので、接続が切れた場合の処理ができない。

SessionDisconnectEvent時点でわかる情報は「セッションが切れたユーザーのAuthenticationToken」のみ。→ログイン状態を管理する実装等のついでに付けたい。現状は不要の判断で。

 

※次回以降

画像を表示する

続いて、メッセージの仕分けと通信サイズを調べ、異常があれば弾く実装をする。

 

 

-------------------------------------------------------------------------------------------

 

他のエラー

VM352:161 crbug/1173575, non-JS module files deprecated

+

Started ReaDiscussion20220605Application in 184.562 seconds (process running for 186.209)

何だこれ...

eclipse デバッグ 遅い - Google 検索

全てのブレークポイントを削除したら直りました。なんだこれ...

 

------------------------------------------------------------------------------------------------

 

 

------------------------------------------------------------------------------------------------

STOMP over WebSocketでのバリデーション

base64だと、使用される文字が限定されるので、バリデーションを行いたい。

しかし、公式のドキュメントでは、SUBSCRIBEはあるが、SENDに関わるイベントはない。(追記:その下にInterceptorについて記載がありました...)

Spring websocket: how intercept the send event through the AbstractSubProtocolEvent hierarchy? - Stack Overflow

 

BrokerやInboundChannelといったWebSocketで使用するクラスでは実装できない...?

そして、このSTOMP over WebSocketはSpring frameworkのMessageを使用して作られているとの事。

Spring Integration メッセージ - リファレンス

 

現在は、ChannelInterceptorとの事。

ChannelInterceptor (Spring Framework 5.2.16.RELEASE API) - Javadoc

 

まず、Messageが呼ばれる事だけ確認する。

GenericMessage (Spring Framework API) - Javadoc

 

となると、Interceptorの登録のみ。

 

WebSocketMessageBrokerConfigurer (Spring Framework API) - Javadoc

後はBeanで登録したChannelInterceptorの実現したクラスを加えて...

 

ChannelInterceptorのpostSend()を試すと...

postSend()
{simpMessageType=HEARTBEAT, simpUser=UsernamePasswordAuthenticationToken [Principal=org.springframework.security.core.userdetails.User [Username=秘密, Password=[PROTECTED], Enabled=true, AccountNonExpired=true, credentialsNonExpired=true, AccountNonLocked=true, Granted Authorities=], Credentials=[PROTECTED], Authenticated=true, Details=CustomWebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=5CEB1CB9B3702CC5FCC3BFB1056C232E], Granted Authorities=], simpSessionId=2ijplqoo}
[B@6343ff1e

 

ヘッダーがちゃんと取れました。(あ、Roleの登録処理が抜けていた...単体テストやり直し...)

25. WebSocket Support

 

 

あとはpayloadです。

payloadはbyte型で格納されています。

String str = new String*1;
        System.out.println(str);

とすると、結果は...

{"content":"メッセージを送ります。"}

取得できました。

 

処理順はPreSend()→Controller→afterSendCompletion()。

PreSend()で行う予定

・受け取ったMessageのheaderからContentType等を調べる

・payloadに不正な入力がないか

Injection Flaws | OWASP Foundation

 

OWASP Secure Coding Practices-Quick Reference Guide | OWASP Foundation

 

A04 安全が確認されない不安な設計 - OWASP Top 10:2021

HTTP Request Smuggling を理解する - Qiita

 

DOS

Denial of Service | OWASP Foundation

 

コンテントタイプなどをホワイトリスト式に

バリデーション

bucket4jなどによるリクエスト等の制限

-------------------------------------------------------------------------------------------------

HashSetは2分岐構造なので、データの削除だと速い。

Listは配列なので、データを消す時に時間がかかるケースもある。

 

--------------------------------------------------------------------------------------------------

感想

この記事はかなり前のものだったと思います。

他の記事を投稿しつつ、消さずに追記追記で今日にいたりました。

所詮日記です。技術者への道は遠い...

ちなみに、AOPや例外処理の記事も書いていましたが、没になりました。

 

さて、一旦仕切り直してより良いアウトプットができるように頑張ります。

また、ムエタイ始めました。もう夏から試合参加してもいいかもと言って頂いたので、まだ確定ではないですが、Bクラスで参加想定して頑張ります。

あと、MMAも始める予定です。

理想の一週間としては、平日が仕事終わりにムエタイとMMA、帰宅後はよりコンピューターサイエンスに近いJavaの学習と周辺知識の学習。土日が基礎トレと開発、その他。

 

心に余裕がなくなってきて、少し気持ちめげかけましたが、社内の方々や交流会の方々とお話していく中で、初心を思い出しました。松下幸之助の道の考え方に近いです。別の方の言葉だったと思いますが、一言で言うと「人事を尽くして天命を待つ」。この精神で生きていきたいと思います。

スピード落ちましたが上げていきます。

*1:byte[])message.getPayload(