GoogleMapAPI JavaScriptコンソールで技術情報を...
困ったこと
Google Map APIを使って開発をしていたところ、家では正常にGoogle Mapが表示できるのに、外で表示しようとしたらこのようなエラーがでた。
JavaScriptコンソールで技術情報を見たいけど、、、スマホで開発者ツールとか開けるんだっけ?
やったこと
こちらを参考にして、スマホにKiwi Browserをインストール
Kiwi Browserでエラーとなっている該当のページを開き、開発者ツールでコンソールログを見てみる。
原因
RefererNotAllowedMapError
とでていた。
そ、そういえばGoogle Map APIの設定画面でそのような項目があったような。。。
原因は、自宅WifiのみのIPアドレス範囲に限定していたことでした。
対応
IPアドレスでの制限ではなく、HTTPリファラーでの設定にしました。
今回の件でKiwi Browserを知ったけど、PCの時と同じ感覚で開発者ツールをみることができてよかった。
(デバッグとかその他諸々の機能は全然使っていないけど)
ymlファイルを読み込みでハマったこと
事象
- application.ymlファイルを、秘匿したい情報と公開してもよい情報で分けて管理しようと考えた。
- application.ymlファイルと、application-security.ymlファイルで分けて作成した。
- application.ymlファイル内に、spring:profiles:active:securityを追加した。
→ 全く読み込まれない。
試したこと
- application.ymlファイルに戻せば、正常に動作する。
- 別に作っておいた、application-local.yml等のファイルに記載すれば、正常に動作する。
原因
- 改行コード原因のようだった。
- エラーでずっと読み込まれなかったのは、CRLF
- 成功していたのは、LFのみ
まとめ
文字コード系や改行コード等、見た目ではわからなくて普段意識しない領域に自分はハマりやすい傾向がある。。。
エラー備忘録 NoClassDefFoundError
個人的に別のツールにまとめている除法を整理している中で、少し印象に残っていたエラーがあったので、ご紹介。
ただ、あまり詳しく書きすぎるとあれなので、少し抽象化した形で記載します。
NoClassDefFoundErrorとは
以下公式ドキュメントより
通常のメソッド呼び出し、あるいはnew式を使った新しいインスタンスの生成で、Java仮想マシンまたはClassLoaderインスタンスがクラス定義をロードしようとしたが、クラス定義が見からない場合にスローされます。 検索されるクラス定義は、現在実行中のクラスをコンパイルする時点では存在していましたが、その後見つからなくなっています。
NoClassDefFoundError (Java SE 17 & JDK 17)
直接的な原因は別の UnsatisfiedLinkError
当時対応していた時は、ひたすらNoClassDefFoundError
に関する情報を収集していたが、実は潜在的な問題が別にあり、このエラーは直接的なエラーではないことがわかった。
直接的なエラーは、UnsatisfiedLinkError
というもの。
このエラーがでてしまった場合、JVMがそのエラーがでたクラスを記憶し、再度そのクラスにアクセスしようとすると、NoClassDefFoundError
がでるという事象だった。
そのため、このエラーは初回起動してから初回クラスアクセス時にはコンソールに出力されるが、その後は何回処理を実行しても、でてこなくなる。
UnsatisfiedLinkErrorとは
Java仮想マシンが、nativeと宣言されたメソッドの適切なネイティブ言語の定義を見つけることができない場合にスローされます。
UnsatisfiedLinkError (Java SE 17 & JDK 17)
結局のところの原因
結局のところは、必要なDLLなどのモジュールが配置されている箇所へのパスが通っていないことが原因でした。
わかった時は、そんな凡ミスか、、、と嘆いたのはいい思い出ですが、、、
長く時間を費やしても解決できないようなエラーって、経験上こういう凡ミスやそもそもの前提の認識が誤っていたとか往々にしてあると思います。
ついでに ClassNotFoundException との違いは?
当時調査している中で調べてみたので、ついでに。
大きな違いは、ClassNotFoundException
は、コンパイルすらできるかわからない状況であるということ。
NoClassDefFoundError
の場合は、公式にも記載されている通り、コンパイル時点では存在していたはずのクラスということ。
もう少し具体的になると、ClassNotFoundException
は以下のパターンで発生する。
- クラス Class の forName メソッド。
- クラス ClassLoader の findSystemClass メソッド。
- クラス ClassLoader の loadClass メソッド。
ClassNotFoundException (Java SE 17 & JDK 17)
補足
ここで記載しているエラーは、あくまで一例なので、NoClassDefFoundError
やUnsatisfiedLinkError
が発生する原因は、他の場合も多々あります。
特にNoClassDefFoundError
なんかは、ClassLoaderの読み込み優先順位や参照権限の問題なども取り上げられており、頭が混乱していました。
もし同じようなことでお困りの方の助けになれば。。。
JavaScriptで2次元配列を宣言する方法
JavaScriptで単一の配列は作成することはあったが、2次元配列は意外と少なかった。
今回2次元配列を使おうと思った時に、意外と詰まってしまったので備忘録。
NG例①
最初は以下のように記載していた。
var test = []; for(let i = 0; i < icnt; i++){ for(let j = 0; j < jcnt; j++){ test[i][j] = "hogehoge"; } }
ダメだった。どうやらtest[i]に対して、j番目の配列というのがundefined
として認識されているらしい。
ということは2次元配列として宣言してあげればいけるのか?
と思い試してみたのが以下。
NG例②
var test = [][]; for(let i = 0; i < icnt; i++){ for(let j = 0; j < jcnt; j++){ test[i][j] = "hogehoge"; } }
今度は構文エラーになる。だめらしい。
調べてみると、以下のようにする必要があるらしい。
OK例
var test = []; for(let i = 0; i < icnt; i++){ for(let j = 0; j < jcnt; j++){ test[i]=[]; test[i][j] = "hogehoge"; } }
なんとなく冗長がするのと、宣言時に2次元配列であることがわからないので若干もやもやするが、、、
でもこれはおそらくJavaに慣れすぎているせいで、JavaScriptに慣れていれば、動的型付けゆえの仕様ということで納得できるか?
ちなみに、宣言部分はnew Arrayでも置き換えできる。
参考リンク
docker runとdocker-composeでのportの違い
コンテナ技術の勉強として、DockerでアプリとDBをつないでみた。
その時にポートの設定で少し詰まったところと、検証してみてわかったことがあったので、備忘録。
イメージ
それぞれの違い
docker run
で立ち上げた場合、コンテナ間の通信には、外部アクセス用のポートが使用される。
docker-compose up
で立ち上げた場合は、コンテナ間の通信はその内部のポートが使用される。
docker run で構築する場合の手順
※アプリ・DBそれぞれ単体で立ち上げて動作することは確認済みの前提。
1. ネットワークを作成する
アプリとDBをつなぐためのネットワークを作成する。
docker network create hoge_network
2. アプリ側のコンテナを作成する
※ここでは、Tomcatに対してSpringBootで作成したアプリケーションを構築したものを想定する。
2-1. アプリケーション定義ファイルの作成
作成するアプリ側の定義ファイルは、以下の通り。
spring: datasource: url: jdbc:postgresql://db:5433/hogedb username: postgres password: postgres driver-class-name: org.postgresql.Driver jpa: database-platform: org.hibernate.dialect.PostgreSQLDialect show-sql: true hibernate: ddl-auto: none
ここで、url
に指定するホスト名には、docker run
する時に指定するネットワークのエイリアス名。ポート番号は、外部から接続するためのポート番号を指定する。
2-2. Dockerfileの作成
イメージを作成するために、Dockerfile
を作成する。
# Dockerfile FROM tomcat:9.0.64 ENV CATALINA_HOME /usr/local/tomcat ENV PATH $CATALINA_HOME/bin:$PATH ENV WAR_FILE target/*.war WORKDIR $CATALINA_HOME COPY ${WAR_FILE} webapps/hoge.war
2-3. イメージの作成
ビルド用のコマンドを実行する。
docker build -t hoge_user/hoge .
2-4. コンテナの立ち上げ
イメージができたら、docker run
を実行する。
docker run -dp 8888:8080 --name hoge_container --network hoge_network --network-alias app hoge_user/hoge
少し日本語訳すると、
- 先ほどビルドして作成した[ hoge_user/hoge ]というイメージを使って、コンテナを作成・起動する。
- コンテナの名前は、[ hoge_container ]として作成する。
- コンテナ外からのアクセスは8888ポートで受け付け、コンテナ内の8080ポートとしてポートフォワードする。
- ネットワークは、[ hoge_network ]に入り、ホスト名を[ app ]とする。
3. DB側のコンテナを作成する
※DB側コンテナのベースとなるイメージはpullしている前提。
3-1. DB側のコンテナの立ち上げ
postgres:14.0のイメージを使用して、コンテナを作成・起動する。
docker run -it -d ` --network hoge_network --network-alias db ` --name hoge_postgres ` -e POSTGRES_PASSWORD=postgres ` -e POSTGRES_DB=hogedb ` -e POSTGRES_USER=postgres ` -p 5433:5432 ` postgres:14.0
アプリ側と同じように、コンテナの名前とポートフォワーディング、ホスト名の設定を行う。
docker-compose で構築する場合の手順
この場合は、docker-compose.yml
ファイルさえ作成すれば準備は完了する。
1. docker-compose.ymlの作成
version: '3.6' services: app: container_name: hoge_container image: hoge_name/hoge ports: - 8888:8080 depends_on: - db db: container_name: hoge_postgres image: postgres:14.0 environment: POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres POSTGRES_DB: hogedb ports: - 5433:5432
2. コンテナの立ち上げ
下記のコマンドを実行する。-f
オプションで指定しているのは、1で作成したdocker-compose.yml
のファイルパス。
docker-compose -f docker-compose.yml up -d
まとめ
今の自分にはdocker-compose
を使った方が楽に感じる。
でもたぶんどこかでdocker run
で構築しないといけないような場面もでてくる気がする。
【Java】Struts + EJBについて整理してみる - 2
本記事の目的
本題
全体像
開発の流れ
- war用のプロジェクトと、EJBjar用のプロジェクトで開発
- build.xmlでearファイルを作成するように定義
- ビルド
- 動作させたい環境にデプロイ
※ どこかのタイミングで、デプロイ用の定義ファイルを作成する必要があります。
処理の流れ
- クライアントからリクエストを発行する
- WEBサーバーがリクエストを受け付け、WEBコンテナへリダイレクトする
- WEBコンテナ側での処理を実行
- 必要があれば JNDI を利用して、EJBコンテナ側と連携する
- EJBコンテナ側で処理を実行
- 必要であれば JNDI を利用して、DBへのアクセスを実行
- 各処理結果をまとめて、JSPのコンパイル処理を実行
(※設定によっては事前にコンパイルされているケースもある) - レスポンスを返却する
Strutsの動き
※整理していて、自分自身も詳しく理解できていないところがあると気づいたので、また整理できたら追記していこうと思います。
- ActionServletがリクエストを受け付ける
- web.xmlとstruts-config.xmlの定義に基づいて、URIからActionFormを生成し、Actionのexecuteメソッドを実行する。
- 必要があれば、Action内でEJBの処理を呼び出す
- JNDIのlookup経由でHomeインターフェースを呼び出し、createメソッドを実行し、Remoteインターフェースを取得
- Remoteインターフェースから、任意のメソッドを実行
- 処理結果をまとめて、ActionForwardを返す。(Actionクラスの戻り値)
- JSPのコンパイルを実施し、HTMLにしてレスポンスを返却
EJB(とiBatis)の動き
- ActionからJNDI経由でBeanクラスを生成(ステートレスセッションBeanの場合は、プーリング領域から取得)
- 要求された処理を実行
- 必要があれば、DaoManagerを利用してデータソースへのアクセスを実行し、任意のクエリを発行する
- 処理結果を返す
ここまでの補足事項としては、EJBについては、ローカルBean用の仕組みを使えば、JNDI経由で呼び出さずとも、クライアントのサーバー内で解決ができるようです。(初めて知った。。。)
また、自分でも結構曖昧だと感じた部分が多かったので、誤りもあるかもしれません。
次から整理する内容は、より実装ベースの話に入ろうかとも思ったのですが、調べると結構実装例はたくさんあるので、やめておきます。(環境構築がめんd...)
ただ、最近勉強しているコンテナを使って、J2EEベースのStruts+EJB+iBatisのイメージを作ってみるのは、面白そうかな?と思いました。
気づき
- Strutsの詳しい処理について、よくわかっていない
- EJBの呼び出し周りについて、よくわかっていない
- DAOの詳しい処理について、よくわかっていない
→ ある意味、わかっていなくても色々連携ができるという意味では、フレームワークとしての役割を果たしてもらっている。
(ちゃんと時間があるときに調べてみます。)
参考リンク
J2EE・EJB関連
EJBの参考
iBatisの参考
【Java】Struts + EJBについて整理してみる
背景
WEBエンジニアとして働き始め早4年。
現場で扱っている技術について、棚卸もかねて整理しようと思い立ちました。
目次
Strutsとは?
概要
- Apacheが開発した、JavaのWeb開発フレームワーク
- 一時期はJavaのWeb開発フレームワークのデファクトスタンダードとなるぐらい普及した
- でも脆弱性や開発効率などの欠点なども指摘されるようになり、サポートは既に終了している
ポイント
Strutsを触り始めた当初、下記サイトには大変お世話になりました。 www.javaroad.jp
EJBとは
概要
- Enterprise Java Beansの略であり、業務システムを意識した、コンテナ/コンポーネント技術。
- J2EEと密接に関係している(むしろJ2EEがないとできない)
- 周りの環境に左右されず、ビジネスロジックに専念できるようにするために考えられた。← !!重要!!
ポイント
一旦ここまで。
補足事項としては、初期のStrutsやEJBの仕様は、XMLベースでの設定であったため、保守のしにくさや複雑さ等がありました。
そこから改良を重ねて、アノテーションベースや、契約による設計を取り入れてきたようです。(自分は触ったことないですが)
気づき
- プログラミングする領域を、MVCモデルとして境界を意識させることで、(できるだけ) 神クラスが生まれないようにしようとした。
- ドメイン領域(ビジネスロジックの領域)については、クライアントやインフラ等の環境に左右されないように設計するという理念については、今も昔も変わっていない。
- アノテーションベースや契約による設計の目的は、他ファイルで設定値を定義することによる保守性の低さを解決するため。
(= アノテーションベースや契約による設計でむしろ保守性が下がる場合は、別の手段も検討すべき?そんな場面は滅多にないと思うけど、、、)
次は、StrutsやEJB、J2EEの関係を、もう少し具体的なイメージに落とし込んでみたいと思います。
用語説明
- MVCモデル:サーバー側の処理を、Model, View, Controllerの3つの役割に分けることで、プログラミングで意識する領域を限定させる、アプリケーション設計の1つ。
- 神クラス:1つのクラスに色んな機能が詰め込まれたクラス。代表的なものは、Utilクラス。「何か特定領域のUtilクラス」は個人的に許容できる範囲だと思うが、「何でも屋Utilクラス」が存在すると、神クラス化しやすい。