はじめに
前回と同様に日記形式で進めます。
仕事の空いている時間に学習した内容も併せて記載。
作成中の日記が長すぎるため、分割。
内容
前記事の公式ドキュメント参照
"clientInboundChannel"
for messages from WebSocket clients."clientOutboundChannel"
for messages to WebSocket clients."brokerChannel"
for messages to the broker from within the application.
OutboundChannelとInboundChannelのスレッドが増え続ける事については、ハートビートのPING、PONG毎にスレッドが実行中のままである事が原因だった。
状況:チャット画面を表示した時点でInboundChannelが3つ、OutboundChannelが1つ、MessageBrokerが複数実行される。
スレッドは定期的に削除されている可能性が...仕組みがわからない。
力不足を感じる。ひとまず、機能実装後に考える。
-------------------------------------------------------------------------------------------------
画像送受信について、調べると下記のような情報があった。
javascript - Sending images/files over Sockjs + Spring Websocket + Stomp - Stack Overflow
流れとしては、クライアント側で画像をエンコードして、Spring Boot側でデコードし保存という流れだろうか。
MySQLの場合はBLOB型で保存という事なので、試してみる。
①HTMLに設置された画像をJavaScriptでBase64に変換して、STOMP.jsでContentTypeを指定して送信
第二引数でヘッダーの作成ができる。デフォルトはjson/applicationのため変換する。
拡張子について調べると、IPhoneやアンドロイドの画像はjpegとの事で、jpgかjpegで登録できるようにする。heifやheicにも対応できた方が良いとの事なので、上記4つの拡張子に対応することを考える。
heifやheic変換のJsライブラリ
Heic2any: Client-side conversion of HEIC/HEIF image files to JPEG, PNG, or GIF in the browser.
heic2any/getting-started.md at master · alexcorvi/heic2any · GitHub
ダウンロードでjsファイルが開かれるので保存。
圧縮はひとまず置いておいて、1.HTMLで画像を受け取る 2.Heic2anyで画像を変換し、ContentTypeを指定。 3.STOMP.jsにてContentType指定、画像を送信し、ChannelInterceptorで受信内容の確認。
※JavaScriptの基礎と混ぜて進めていく。
まず、HTMLに画像をセットした後に拡張子がheicやheifの場合は、拡張子をjpegやjpgにして、誰でも利用できるようにしたい。
そのため、拡張子のみをJavaScriptで取得。
var fileExtension = document.getElementById("sendImage").value.split(".").pop();
if(fileExtension == "jpeg" || fileExtension == "png" || fileExtension == "jpg" ){
}
if(fileExtension == "heic" || fileExtension == "heif"){
fetch(document.getElementcById("sendImage"))
.then*1
.then((blob) =>
heic2any({
blob,
toType: "image/jpeg",
quality: 0.5,
})
)
.then((conversionResult) => {
sendImage(conversionResult)
})
}
ひとまず、jpg、jpegの部分とsendImage()手前でBase64への変換が必要になる。
encodeURIComponent() - JavaScript | MDN
最後は、STOMP.jsにて、ヘッダーをセットし送信処理を行う。
Error: The file given is not an instance of Blob or File
at index.js:84:24
at new Promise (<anonymous>)
at imageCompression (web-worker.js:1:1)
at addjustmentImage (app.js:60:33)
at HTMLButtonElement.<anonymous> (app.js:111:37)
at HTMLButtonElement.dispatch (jquery.min.js:2:43090)
at v.handle (jquery.min.js:2:41074)
typeof(document.getElementById("sendImage").value)
'string'
.value→.files[0]にすると、
ReferenceError: image is not defined
STOMP.js内でheaderの値がおかしくなっていた。
"Content-Type":"image/jpeg"に設定
>>> SEND
Content-Type:image/jpeg
destination:/app/room/498894c2-a9e4-4b62-aaf0-4869e2f6b02d
content-length:90{"message":"JTVCb2JqZWN0JTIwQmxvYiU1RA==","roomId":"498894c2-a9e4-4b62-aaf0-4869e2f6b02d"}
いや、これ中身画像じゃない...
Fileでは受け取れている。
Promise付けたらと試すも同じ。(JavaScriptちゃんと勉強しないと...)
あくまでデータをJavascriptでアクセスできるようにするもの
明示的に選択したファイルの内容にのみアクセスすることができます
...
指定された
Blob
の内容の読み込みを開始し、終了すると、result
属性にはファイルからの生のバイナリーデータが文字列として格納されます。
うまくいきました。
※FileReaderのonload()について、非同期処理のためonload()外に値を持ち込む事はできない。関数の外で呼び出そうとすると空が返ってくる
index.js:84 Uncaught (in promise) Error: The file given is not an instance of Blob or File
at index.js:84:24
at new Promise (<anonymous>)
at imageCompression (web-worker.js:1:1)
at reader.onload (app.js:67:30)
const compressedFile = imageCompression(imageFile, options)
imageFileはFileかBlobでないとだめのため元のFileオブジェクトに修正。
2000ほど圧縮されました。
Spring Bootにて
Cannot deserialize value of type `java.lang.String` from Object value (token `JsonToken.START_OBJECT`)
at [Source: (byte[])"{"message":{},"roomId":"498894c2-a9e4-4b62-aaf0-4869e2f6b02d"}"; line: 1, column: 12] (through reference chain: com.example.demo.model.discussion.ChatMessage["message"])
空になっている。
Base64に変換後の値がまだPromiseになっていた。
呼び出される順番を記載すると...
変換後の処理→変換のためのonload()と逆になっている。
つまり、onload()が非同期処理のため、変換後の処理は並行して行われてしまうが、まだ値自体が渡されていないため、空になるという事だ。
よって、変換処理をPromise内に置き、onload()内でresolveし、次のthenに渡すことで解決した。
org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]
…
com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Data too long for column 'message' at row 1
原因は、宛先がメッセージと同じであったため。
また、クライアント側でも...
>>> SEND
Content-Type:image/jpeg
destination:/app/room/498894c2-a9e4-4b62-aaf0-4869e2f6b02d
content-length:54330(以下、変換後の文字列)
...
remaining = 38057
stomp.min.js:8 remaining = 21673
stomp.min.js:8 remaining = 5289
実装予定
送信方法の指定
コントローラーでのBLOB変換
感想
Promiseや非同期処理について、程よく学べたのではないかと思います。
また、AtCoderでは、式変形やDPを社内の方々から教えてもらいました。
幸いな事に、仕事は暇なので、EffectiveJavaやDZone、MDNのJavaScriptの項あたりを読みつつ、PG職になるために備えたいと思います。
*1:res) => res.blob(