20210411のJavaに関する記事は15件です。

【Java】AtCoderのABC-198に参加しました(レート:220→278)。

こんばんは。 2021/4/11に、AtCoderのABC-198に参加しました。 レートは以下の通りとなっています。 ひさびさなのでA、B問題に少し時間がかかってしまいました。 C問題は1ミスしましたが、何とか1時間程度で解けました。自分としては上出来です。 レートは221→278に更新!順位は3461/7993でした。 こないだマイナスになった分を取り返し、最高レートを更新です。 返り咲きおめ! \(^-^)/ A問題 N個のお菓子を、A君とB君で分ける組み合わせを求める。互いに1個以上あるのが前提。 色々考えて以下のプログラムにしましたが、お菓子の数-1を出力すればよいだけではないかと思われます。 例えばn=5(お菓子5個)の場合、A:4個、B:1個・・・A:1個、B4個、という順序で組み合わせを考えていくと、A君で見れば、4(n-1)~1 の4通りになる。という法則があるためです。 あれ?言葉で説明すると難しいな・・。 import java.util.Scanner; public class Main{ public static void main(String args[]){ Scanner sc = new Scanner(System.in); int n = sc.nextInt(); int na = 1; int nb = n-na; int cnt = 0; if(nb>0){ cnt++; } while(nb>0){ na++; nb = n - na; if(nb>0){ cnt++; } } System.out.println(cnt); } } B問題 整数Nに、0個以上の0を付与して回文にできるか? 例えば、1210であれば、1個の0を付与すれば、01210で、回文になります。 (しかし、よくこういう問題思いつくなあ・・) <実装> ①まずは末尾のゼロの個数を数える(回文にするなら、付与するゼロの数と末尾のゼロの数は同じと断定)。 ②末尾のゼロの個数と同じだけ、ゼロを付与した文字列を作成。 ③③を逆転させた文字列を作成 ④②③を比較 import java.util.Scanner; public class Main{ public static void main(String args[]){ Scanner sc = new Scanner(System.in); String n = sc.next(); String ng = n; String nh[] = new String[n.length()]; int zcnt = 0; String zer = ""; // 0 no kazu check for(int i=n.length()-1;i>=0;i--){ //System.out.println("n.charAt(i) = " + n.charAt(i)); if(n.charAt(i)=='0'){ zcnt++; zer = zer + "0"; }else{ break; } } ng = zer + ng; //System.out.println(ng); String nkai = ""; for(int i=ng.length()-1;i>=0;i--){ nkai = nkai + String.valueOf(ng.charAt(i)); } //System.out.println(nkai); if(ng.equals(nkai)){ System.out.println("Yes"); }else{ System.out.println("No"); } } } C問題 2次元平面上の原点(0,0)がスタート。1歩で進む距離はr。 座標(x,y)に行くには、最低何歩か? <実装> ①原点から(x,y)への距離は、問題文の解説に従えば、  √x^2 + y^2  となる。まずこれを求める。 ②1歩の進む距離(r)と、②を使って計算。 「②/r」の計算をすることに。 例えば距離が5だとして、rが2だったら、2.5歩だが、歩数は整数でないといけない。その場合は冗長な進み方(↓こんなやつ)をする事で整数の歩数で到達できる。 「②/r(小数点切り上げ)」を求める事で正解にたどり着けるのでは。 →これで提出したら3問エラーになる。いい線だが、まだ何か例外の考慮ができていないと考え悩む。 ③「rが過剰な場合」の考慮ができていない事に気付く。 例えば、r=5で、行きたい座標が(1,1)のとき、②の計算では1になるが、1歩では座標を飛び越えてしまう。この場合は、1歩目と2歩目で距離を10にしつつ座標(1,1)に到達できるように調整する事ができると断定。この場合は必ず2歩で到達できる。 ・・やっぱり文章にすると難しいけれど、以下のようなイメージ。 import java.util.Scanner; public class Main{ public static void main(String args[]){ Scanner sc = new Scanner(System.in); double r = sc.nextDouble(); double x = sc.nextDouble(); double y = sc.nextDouble(); double xy = (x*x)+(y*y); //System.out.println((Math.sqrt(xy))); double hosu = ((Math.sqrt(xy)))/r; double hosuk = Math.ceil(hosu); //System.out.println(hosu); //System.out.println(hosuk); if(hosu>=1){ System.out.println((int)hosuk); }else{ System.out.println(2); } } } 感想 ・今回はC問題が終わって残り40分あったため、D問題に取り組んでみたのですがやはり難しい。早くDに進めるレベルになりたいと思います。 ・次は300を目指して頑張ります。他の方の記事を読むと、300以降が伸び悩むことも多いようです。心して取り組みたいと思います。 茶色を目指している方、お互い頑張りましょう!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Android】画面スクロール設定をする

簡単だけど知らなかったのでメモ。 レイアウトの要素を下記で囲むだけでスクロールできる。 <androidx.core.widget.NestedScrollView> </androidx.core.widget.NestedScrollView> 例 activity_main.xml <?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <androidx.core.widget.NestedScrollView android:layout_width="0dp" android:layout_height="0dp" android:scrollbars="none" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" > <TextView android:id="@+id/name_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Android アプリは Kotlin や Java、C++ 言語を使用して記述できます。Android SDK ツールは、コードをデータやリソース ファイルと一緒に APK(Android パッケージ)にコンパイルします。これは、.apk という接尾語の付いたアーカイブ ファイルです。1 つの APK ファイルに Android アプリのすべてのコンテンツが含まれており、Android 端末はアプリをインストールする際にこのファイルを使用します。 各 Android アプリはそれぞれのセキュリティ サンドボックス内で動作し、以下の Android のセキュリティ機能により保護されています。 Android オペレーティング システムはマルチユーザーの Linux システムであり、各アプリがそれぞれ異なるユーザーになります。 デフォルトで、各アプリに一意の Linux ユーザー ID が割り当てられます(ID はシステムのみで使用され、アプリは ID を関知しません)。アプリに割り当てられたユーザー ID のみがアプリ内のすべてのファイルにアクセスできるよう、パーミッションが設定されます。 各プロセスにはそれぞれ独自の仮想マシン(VM)があるため、アプリのコードは他のアプリとは分離して実行されます。 デフォルトで、すべてのアプリは独自の Linux プロセスで実行されます。Android システムはアプリのコンポーネントのいずれかを実行する必要があるときにプロセスを開始し、それが必要なくなったときや、システムが他のアプリ用にメモリを回復させる必要があるときにプロセスをシャットダウンします。 Android システムには「最小権限の原則」が適用されています。つまり、デフォルトでは各アプリにコンポーネントの動作に必要な分だけのアクセス権が与えられます。これにより、パーミッションの与えられていないシステムの部分にアプリはアクセスできないという非常に安全性の高い環境が作り出されます。ただし、次のように、アプリが他のアプリとデータを共有したり、システムのサービスにアクセスしたりするための方法はあります。 2 つのアプリで同一の Linux ユーザー ID を共有して、お互いのファイルにアクセスできるようにすることが可能です。また、システム リソースを節約するため、同じユーザー ID を持つアプリを同じ Linux プロセスで実行し、同じ VM を共有するよう設定することもできます。この場合、これらのアプリは同じ証明書で署名される必要があります。 アプリから、ユーザーの連絡先などの端末データ、SMS メッセージ、マウント可能なストレージ(SD カード)、カメラ、Bluetooth にアクセスするためのパーミッションをリクエストできます。ユーザーはこれらのパーミッションを明示的に付与する必要があります。詳細については、システム パーミッションの使用をご覧ください。 続いて、このドキュメントでは次のコンセプトについて説明します。 アプリを定義するコア フレームワーク コンポーネント。 コンポーネントと、アプリに必要な端末の機能を宣言するマニフェスト ファイル。 さまざまな端末構成に合わせてアプリの動作を最適化するための、アプリコードから分離されたリソース。アクティビティは、ユーザーとやり取りするためのエントリ ポイントです。これは、1 つのユーザー インターフェースを持つ 1 つの画面で表されます。たとえば、メールアプリには、新着メールの一覧を表示するアクティビティ、メールを作成するアクティビティ、そしてメールを閲覧するアクティビティがあります。メールアプリでは、これらの複数のアクティビティが一体となって 1 つのユーザー エクスペリエンスを形成しますが、それぞれのアクティビティは他のものから独立しています。したがって、これらのアクティビティのいずれかを、別のアプリから開始することができます(メールアプリが許可している場合)。たとえば、カメラアプリからメールアプリの新規メールを作成するアクティビティを開始できます。そのようにして、ユーザーが写真をメールで共有できるようにします。アクティビティは、システムとアプリ間における次の重要なインタラクションを行えるようにします。 アクティビティをホストしているプロセスを継続的に実行するために、ユーザーの現在の操作内容(画面の表示)を追跡。 以前に使用されたプロセス(停止されたアクティビティ)のうち、ユーザーが再度アクセスする可能性があるものを検知し、それらの優先順位を上げてプロセスを維持。 アプリがプロセスを強制終了した場合に、ユーザーが以前の状態を復元したアクティビティに戻れるように支援。 アプリ間でのユーザーフローをアプリが実装する手段と、システムがそれらのフローを連携させるための手段を提供(ここでは最も一般的な例を説明します)。 アクティビティは Activity クラスのサブクラスとして実装します。Activity クラスの詳細については、デベロッパー ガイドのアクティビティをご覧ください。" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.core.widget.NestedScrollView> </androidx.constraintlayout.widget.ConstraintLayout>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWSでWebアプリをデプロイする方法(Java)⑩

参考サイト:https://qiita.com/hiren/items/2a4f1b55c99ebfb3fd08 制作物のデプロイ 制作物を特定のディレクトリに配置し、アクセスできるようにします 利用環境 OS:MacOS ブラウザ:Chrome Java:11.0.2 Tomcat:9.0.44 前提条件 Apacheがインストールできている状態 まだ、Apacheがインストールできていない方はこちら Javaがインストールできている状態 まだ、Javaがインストールできていない方はこちら Tomcatがインストールできている状態 まだ、Tomcatがインストールできていない方はこちら WARファイルを作成する Eclipseを起動し、プロジェクトを右クリックし、[エクスポート]→[WARファイル]を選択、宛先を[デスクトップ]にして[完了]を選択 WARファイルを配置する まずは、ローカルにあるWARファイルをリモートのディレクトリに移動します ※直接デプロイ先に移動することもできますが、その場合権限変更を行わなければいけないため以下の手順で実行します ローカル→リモート(tmpディレクトリ)→rootアカウントでのログイン→リモート(デプロイ先) ローカル→リモート(tmpディレクトリ) scp -i "/Users/koyamatakumi/Documents/Development/practice/aws/myserverkey.pem" /Users/koyamatakumi/Desktop/sukkiriShop.war ec2-user@13.115.141.44:/tmp リモートに接続 ssh -i "/Users/koyamatakumi/Documents/Development/practice/aws/myserverkey.pem" ec2-user@13.115.141.44 rootアカウントでのログイン sudo -i リモート(tmpディレクトリ→デプロイ先) mv /tmp/sukkiriShop.war /opt/apache-tomcat/webapps ブラウザから確認 URLに[ http://13.115.141.44:8080/sukkiriShop-mvc-java.war/WelcomeServlet ]を入力し、Enter 下記画面が表示できれば成功 AWSでWebアプリをデプロイする方法⑪ RDSのDBインスタンスを作成する
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScriptとJavaくらべてみました

JavaScriptとJavaをちょいちょい比較しつつJavaScriptの特徴をまとめていきます JavaScriptとJavaは関係しているの? 結論、JavaScriptとJavaは全く別物です! JavaScriptとは 最大の特徴はWebブラウザ上で動作する  例えばクライアントの画面(HTMLやCSS)やブラウザの機能(ポップアップや戻るボタン)を自由に操ることができ、動きのあるWebページが作成可能 Webブラウザ上で動作し、サーバとの通信が発生しない  ページ内で完結する動作を組むとき JavaScript  ページを跨ぐ動作を組むとき Java  というイメージを持つとよいでしょう! scriptタグを使ってHTMLに埋め込む  scriptタグはheadタグ直下かbodyタグ直下に記述(※どちらでもOK、どちらにもメリットデメリットがある)  HTML同様JavaScript処理も同様に1行ずつ上から順に読み込み&実行していく  この1行ずつ読み込んで実行していく実行方式をインタプリンタという  Javaはインタプリンタ方式ではありません、Javaはファイルごとコンパイルして実行していく  なのでJavaScriptとJavaは処理の方式が違う。 JavaScriptの文法 変数(プリミティブ) 変数の扱いはJavaとはかなり違います! JavaScriptは動的型付け言語という変数に型を持たない言語です ※変数というデータを入れるための箱はあるが、数値型でも文字型でも論理型でもどんな型でも入れることができる不思議な箱ですね 変数宣言方法 var 変数名 ・・・ 通常の変数宣言 let 変数名 ・・・ ローカル変数(スコープ内のみ有効)の宣言 const 変数名・・・ 読み取り専用定数の宣言(※finalとおなじ) 変数(オブジェクト) 基本的にオブジェクトはJavaとおなじイメージでOK→複数の変数と複数のメソッドをまとめて置ける JavaScriptでは変数はプロパティと呼ばれる(※Javaではフィールド) データ型 ※変数にはなんでも入る箱ですが、データ自体についはちゃんと型が用意されています ※typeof演算子を用いると変数内のデータ型を確認できる Number型 ・・・ 整数、小数点、Infinity(無限)etc String型  ・・・ 文字列 Boolean型 ・・・ true/false Null型   ・・・ null Undefined型・・・ undefined(変数宣言時、とりあえず設定される初期値) Symbol型 ・・・ 識別子 文字リテラル 文字列の囲いは「’ ’」「” ”」どちらでも可 ※Javaでは「" "」 コメント JavaScriptのコメントはJavaとおなじで「//」「/* */」を用いる スコープ JavaScriptのスコープは  ・グローバルスコープ ・・・ 関数の外(scriptタグ直下)  ・ローカルスコープ  ・・・ 関数の中  ※JavaScriptでもifやforなどの制御構文はあるがスコープとしてみなされない Javaは  ・ifの後の{ }、forの後の{ }などの制御構文内 デバック ブラウザ上で動作する言語であり、挙動のチェックもブラウザ上 デバックもブラウザで提供されているデバックツールを用いることが一般的 例)Google Chromeのディベロッパーツール 関数(function) JavaにおけるメソッドはJavaScriptでは関数(function)と呼ばれます   function関数名( 引数 ) { まとめたい処理 } Javaと違い戻り値に関する定義がありませんが、処理中にreturn文を書けば戻り値が返る ※返すデータが何でも入る箱に入るので型を指定する意味が無いため型を指定しないだけ ※定義された関数は、HTML全体の解析時に先に読み込まれているため定義されている行より上の処理からでも利用できる 関数オブジェクトと無名関数 JavaScriptでは関数をオブジェクトとして扱うことが可能(関数オブジェクト)、つまり変数に入れることができる   var 関数名 = function( 引数 ) { まとめたい処理 };   ※関数の実行時は、関数名(引数)というように引数情報が必要 この右辺で作成されたオブジェクト(関数名なしの関数を右辺で作成している)を名前がない関数、無名関数と言います //注意// 関数定義されたものは、事前に読み込まれているので初めからあるものとして扱えるが、無名関数は定義された行で生成されるため、この行より上の処理からは利用できません! JavaScriptにおけるオブジェクトとは Javaでは変数とメソッドがあるが、 JavaScriptにおけるオブジェクトは全て変数になる。 ・変数の中身が問題で、中身が関数オブジェクトであればメソッドとして扱う ・中身が関数オブジェクト以外(データ等)であればプロパティとして扱う(Javaで言うフィールド) オブジェクトの直下は変数しかない。 そして変数の中身が関数オブジェクトかそれ以外で扱いが変わる DOM(Document Object model) DOM/DOMツリー ・HTMLやXMLといったWebページを構成する文書情報をアプリケーションから操作するために用意されたAPIをDOMと言う ※JSというプログラムからHTMLという画面情報をいじくるための橋渡しとなるツール、DOMを介して画面情報をいじくれる DOMツリー・・・HTMLの情報をオブジェクトとして表現したもの       ツリーと言うのは階層構造をもった樹形図のようなもの       一つ一つの要素をNode(ノード)と呼ぶ       Nodeの中でも文書内のタグ情報と連動しているものはElement(エレメント)といい、       JavaScriptから操作することになるのは基本的にElement(エレメント)になります ※Elementの階層構造は文書のタグ構成と一致しており、htmlを頂点としてその下にheadとbody、headの下にはtitleなど、bodyの下にh1やformなどで構成されます ・ブラウザ全ての機能と情報をアプリケーションから操作可能とするオブジェクトをブラウザオブジェクトと言う  DOMツリーはその中でも画面表示情報を管理するdocumentオブジェクトの直下に構築されていく ブラウザオブジェクトとDOMツリー プログラムで操作できるようブラウザの全ての情報をオブジェクト化したものを ブラウザオブジェクトと言う 具体的にどうやっ使っていくかというと・・・ 例えばalertメソッドを使ってアプリケーションからダイアログの表示をさせたい場合はwindow.alert()と書きます 「window.」は省略可能のため、 alert() だけでも大丈夫です Windowオブジェクトの直下にはブラウザの機能ごとに複数のオブジェクトが存在します 例) history(履歴)/location(URL)/document(表示情報)/ screen(モニタのサイズ)/navigator(利用状況) point DOMツリーはブラウザオブジェクトであるdocumentオブジェクトの直下に構築されている DOMの操作 Elementは文書内のタグの情報をプロパティとして持つオブジェクトです  このプロパティの値を書き換えるとブラウザ上の情報に即時反映される  例えばinputタグのプロパティ「value」は入力値を管理する変数ですが、このプロパティに文字列を代入する処理を書いておくと実行時にテキストボックスへと入力される Elementのプロパティを書き換えるためにはまずElementにアクセスする必要がある  アクセスする方法はいくつかありますが、まず覚えていただきたいのがid属性を用いたアクセス法です  id属性はElementを一意に特定するための目印のようなもので、 DOMツリー全体で重複して設定することが許されていません 以下のようにgetElementByIdメソッドで取得したいElementの id属性を指定すると該当のElementオブジェクトを取得できる javaScript.js document.getElementById( "取得したいElementのid属性" ) ※このオブジェクトは参照型変数なので、取得したオブジェクト内の プロパティを書き換える=大元のDOMツリーの内容を書き換えるということになります ※他では例えばname属性を用いたアクセス法などもありますが、 name属性はフォームによるサーバーとの通信で用いるもの、HTML操作はそれ以外の要素(特に初心者はid属性)で行う方がベターと思っておくと混乱せずに 済むかもしれません。 〜コード例〜 HTML.html <p>ユーザーID: <input type="text" name="USER_NAME" maxlength="20" id="USER_ID"> </p> <p>パスワード:  <input type="password" name="PASSWORD" maxlength="20" id="PASSWORD_ID"> </p> JavaScript.js var elmSubmit = document.getElementById("ID_SUBMIT"); elmSubmit.onclick = function(){ var elmUserId = document.getElementById("USER_ID"); var elmPassword = document.getElementById("PASSWORD_ID"); var canSubmit = true; if(elmUserId.value == "" || elmPassword.value == ""){ alert("入力漏れの項目があります。"); canSubmit = false; } return canSubmit; } イベントハンドラ ブラウザ上では以下のような様々な出来事が起きます ・ページの読み込みが完了した ・フォームを送信しようとした ・ユーザーがボタンの上にマウスを乗せた ・ユーザーがウィンドウを閉じた ・エラーが発生した etc... こうした出来事のことをイベントと言い、イベントを検知した際に 実行される処理のことをイベントハンドラと言います イベントハンドラは以下のようなイベントに対応したプロパティが用意されており、これを検知した後に実行させたい関数オブジェクトを仕込むことで設定完了となる ・ページの読み込みが完了した → onLoad ・フォームが送信された → onSubmit ・ユーザーがボタンの上にマウスを乗せた → onMouseOver ・ユーザーがウィンドウを閉じた → onUnload ・エラーが発生した → onError JavaScriptの外部ファイル化 JavaScript、HTMLのファイルを分けて作成する 分離することで様々なメリットがあります! ・HTML部隊とJavaScript部隊で並行して開発することができる ・JavaScript処理実行中にエラーが起きた場合JavaScriptファイルだけ確認すれば良い ・管理の意味でもメンテの意味でも開発効率の意味でもいろんな意味でいいことがある
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

STSでJUnit5を動かす

概要 STSでJUnit5を使ってみます。 主に自分用備忘録。 JUnit5とは、Javaテスト用フレームワークJUnitの最新バージョンです。 STSについては後述で紹介記事へリンクを貼ります。 開発環境は次の通りです。 OS : Windows 7 Home Edition 64bit Java : JavaSE 15 STS : 4.10.0 STSのセットアップ こちらからダウンロード、4.10.0 - WINDOWS 64-BITを使用しました。 4.10.0はjar形式で提供されていて、 解凍はダブルクリックで、sts-4.10.0-RELEASEフォルダが作成されます。 その後のセットアップは自分の備忘録を参考にしました。 「STSって何?」という方もよろしければご覧ください。 この記事ではSTSのフォルダをc:\sts-4.10.0にしています。 プロジェクトの作成 STSを起動して、下記のCreate new Spring Starter Projectをクリックします。 プロジェクトの設定をします。 デフォルト(初期値)から変更した箇所はJava Versionのみです。 Spring Bootのライブラリ参照を設定します。 デフォルトからSpring Bootのバージョンを2.4.4にしています。 注意点:JUnit5をこの段階でライブラリ参照設定できません。 site infoを設定、変更無しです。 プロジェクトができました。 ! Unit5を参照する方法 まず、参照するライブラリとして追加します。参考記事はこちら。 Maven Repositoryを検索して、2021/4/11時点で最新バージョン5.7.1を pom.xmlに以下を追記します。 pom.xml(JUnit5のみ) <!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter --> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter</artifactId> <version>5.7.1</version> <scope>test</scope> </dependency> 追記する箇所ですが、pom.xmlの<dependencies>タグ内です。 pom.xmlはSTSでプロジェクト作成した際に自動生成されています。 追記するとこうなります。 pom.xml(参照を追記した後) <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.4.4</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>demo</artifactId> <version>0.0.1-SNAPSHOT</version> <name>demo</name> <description>Demo project for Spring Boot</description> <properties> <java.version>15</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!-- ここから追記 --> <!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter --> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter</artifactId> <version>5.7.1</version> <scope>test</scope> </dependency> <!-- ここまで追記 --> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project> 参照ライブラリをダウンロードします。 プロジェクトルートを選択、右クリック->Maven->Update projectをクリック OKボタンをクリック、アップデートを開始します。 JUnit5参照ができましたが、参照しているJREがJavaSE-15になっているため、修正します。 2021/4/11時点ではSTSにJavaSE 16がバンドル(同梱)されていないためです。 STSにバンドルされていないJREを指定する方法 ※下記の方法はSTSのworkspaceのJREを指定する方法です。 手順をご存知の方は読み飛ばして、次の段落からご覧ください。 JRE System Libraryを右クリック->Build Path->Configure Build Path...を選択します。 JRE System Libraryをクリック、Editボタンをクリックします。 Installed JREsボタンをクリックします。 Addボタンをクリックします。 Standard VMをクリック、Nextボタンをクリックします。 JRE home:のDirectoryボタンをクリックします。 JavaSE 16のインストールディレクトリ (デフォルトだとC:\Program Files\Java\jdk-16)を選択します。 ライブラリが表示されたら、Finishボタンをクリックします。 jdkの方をチェックして、Apply and Closeボタンをクリックします。 ラジオボタンでAlternative JREを選択、 ドロップダウンからjdk-16を選択、 Finishボタンをクリックします。 参照するJREを変更できました。 詰まっている箇所 JRE参照ライブラリを切り替えてからMavenのUpdate Projectを実行したところ、 JavaSE 15にリセットされました。 色々調べた結果、spring-boot-maven-pluginの本家を確認しましたが、 記事初版投稿時点(2021/4/11)ではJavaSE 15で試しています。 他にもmaven-compiler-plugin関連ではありますが、 こちらとか、こちらも拝見しました。 Lombokをインストールする ボイラープレートを書かないようにするため、 Lombok本家セットアップ手順を見ながら、 Lombokをインストールします。 テスト対象を作る テスト対象はシンプルで確実な答えがあるものにしたかったので、 フィボナッチ数を指定した数だけ計算、配列として保持するクラスを用意しました。 FibonacciNumberCreator.java package com.example.demo; import lombok.Data; /** * フィボナッチ数を作成するクラス * * @author harayoshi */ @Data public class FibonacciNumberCreator { private final int[] atFirstArray = {0, 1}; private final String messateTemplate = "F%s = %s\r\n"; /** フィボナッチ数のリスト */ private int[] fibonacciNumbers; /** * コンストラクタ(フィボナッチ数のリスト作成) * * @param size */ public FibonacciNumberCreator(int size) { // サイズが負の数の場合、リストの最小デフォルト値を設定 if (size < 0) { size = atFirstArray.length; } // 1,2番目をリストに格納 fibonacciNumbers = new int[size]; for (int i = 0; i < atFirstArray.length; i++) { fibonacciNumbers[i] = atFirstArray[i]; } // 3番目以降を計算、リストに格納 for (int i = 2; i < size; i++) { int next = fibonacciNumbers[i - 2] + fibonacciNumbers[i - 1]; fibonacciNumbers[i] = next; } } /** * インスタンスが持つリストをテンプレートを使って文字列化 */ @Override public String toString() { String message = ""; // 要素ごとにメッセージを追記 for (int i = 0; i < this.getFibonacciNumbers().length; i++) { message += String.format(messateTemplate, String.valueOf(i), String.valueOf(this.getFibonacciNumbers()[i])); } return message; } } このクラスに対してJUnit5のテストケースを作成します。 テスト対象クラスを右クリック->New->JUnit Test Case Which method stubs would you like to create?は全てチェック有りにして、 Nextボタンをクリックします。 ちなみに、JUnitのバージョンはデフォルトで選択状態でした。 テスト対象メソッドを選択して、Finishボタンをクリックします。 クラスが作成されました。 FibonacciNumberCreatorTest.java package com.example.demo; import static org.junit.jupiter.api.Assertions.*; import java.util.Arrays; import java.util.List; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; class FibonacciNumberCreatorTest { private FibonacciNumberCreator creator; @BeforeAll static void setUpBeforeClass() throws Exception { } @AfterAll static void tearDownAfterClass() throws Exception { } @BeforeEach void setUp() throws Exception { } @AfterEach void tearDown() throws Exception { } @Test void testToString() { fail("Not yet implemented"); } } クラスを作成する前に正解となるフィボナッチ数列をこちら確認しました。 クラスは次の通りに書き換えました。 FibonacciNumberCreatorTest.java package com.example.demo; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; class FibonacciNumberCreatorTest { private FibonacciNumberCreator creator; @BeforeAll static void setUpBeforeClass() throws Exception { // no implements } @AfterAll static void tearDownAfterClass() throws Exception { // no implements } @BeforeEach void setUp() throws Exception { // no implements } @AfterEach void tearDown() throws Exception { creator = null; } @Test void testToString() { int size = 4; creator = new FibonacciNumberCreator(size); int[] expected = {0, 1, 1, 2}; int[] actual = creator.getFibonacciNumbers(); Assertions.assertArrayEquals(expected, actual); } } テスト実行時はテストクラスを右クリック->Run As->JUnit Testをクリックします。 テスト元クラスを確認するダイアログが表示されますが、 そのままOKボタンをクリックします。 テストできました。 結論 簡単なプログラム、テストのみでの確認ですが、今回分かったのは STSは「JUnitのバージョンに合わせて、JUnit5でもこれまでと同じ手順でテスト実行できる」 ということです。 最後まで読んでいただき、ありがとうございました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Android Studioでアプリ開発

自身のPCの性能が悪いのもあるのですが、設定に苦労したのでメモを残して起きたいと思います。 Android Studio自体はダウンロードするのに何の問題もなかったのですが、SDKダウンロードする際に何故かエラーメッセージが出力。 それは保存している場所のフォルダに日本語を使っていたからいけないとのことでした。 そしてSDKはダウンロードできたが次にエミュレーターで実行の段階になり、またエラーメッセージ。 The emulator process for AVD Picel 3a_API 30 x86 was killed. 質問サイトを駆使したところ、どうやら容量の問題らしく、この解決に3段階ぐらいの解決法試しました。 Android StudioでHello worldアプリ作成 https://akira-watson.com/android/helloworld.html#1 このエミュレーター実行の際にエラー文章出る様でたので、 HAMXを設定 それでも通らなかったので ↓ BIOSの設定やHyper-vなど確認 https://akeyfn.xyz/osusumesoft/haxm-win10-vt-x-androidstudio/ それでも通らなかったので ↓ Android StudioからNox Playerを利用してアプリケーションを起動する https://qiita.com/shin1007/items/e1a151c5f99435f3ca5c といった風にエラーを回避しました。他の方が同じ轍を踏まないように。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Javaバッファタイプとネイティブ配列:どちらが速いですか?

Cでプログラミングする場合、メモリを手動で割り当てたり、割り当てを解除したりする必要があります。これはエラーが発生しやすいプロセスです。対照的に、Java のような新しい言語は、多くの場合、メモリを自動的に管理します。Javaはガベージコレクションに依存しています。事実上、メモリはプログラマが必要に応じて割り当てられ、Javaはデータの一部が不要になったと判断し、対応するメモリを取得します。ガベージコレクションプロセスは高速で安全ですが、無料ではありません。何十年にもわたる最適化にもかかわらず、開発者にとって大きな頭痛の種となる可能性があります。 Javaにはネイティブ配列(たとえば、int []型)があります。これらの配列は通常、「Javaヒープ」に割り当てられます。つまり、それらはJavaによって動的データとして割り当てられ、管理され、ガベージコレクションの対象となります。 Javaには、IntBufferなどのバッファタイプもあります。これらは、ネイティブJava配列だけでなく、Javaヒープの外部にあるデータを含む他のデータソースによってもサポートできる高レベルの抽象化です。したがって、バッファタイプを使用して、Javaヒープにあまり依存しないようにすることができます。 しかし、私の経験では、ネイティブアレイと比較してパフォーマンスが低下します。バッファが遅いとは言えません。実際、バッファとストリーム(DataInputStream)のどちらかを選択する場合は、バッファタイプを強く優先する必要があります。ただし、私の経験では、ネイティブアレイほど高速ではありません。 「newint [50000]」または「IntBuffer.allocate(50000)」のいずれかを使用して、50,000個の整数の配列を作成できます。後者は基本的に(Javaヒープ上に)配列を作成する必要がありますが、IntBuffer「インターフェース」でラップします。 考えられる直感は、高レベルのインターフェイスで配列をラップすることは自由であるべきだということです。高レベルの抽象化にはパフォーマンスの低下(場合によってはパフォーマンスの向上)がないことは事実ですが、そうするかどうかは経験的な問題です。抽象化が無料で行われると思い込んではいけません。 私は経験的な声明を出しているので、想像できる最も簡単なテストでそれを経験的にテストしてみましょう。array / IntBufferのすべての要素に1を加算します。 for(int k = 0; k < s.array.length; k++) { s.array[k] += 1; } for(int k = 0; k < s.buffer.limit(); k++) { s.buffer.put(k, s.buffer.get(k) + 1); } デスクトップ(OpenJDK 14、4.2 GHz Intelプロセッサ)で次の結果が得られます。        タイプ               タイム        int [] 2.5 mus IntBuffer 12 mus つまり、このテストでは、配列はIntBuffersよりも4倍以上高速です。 必要に応じて、ベンチマークを自分で実行できます。 https://github.com/lemire/Code-used-on-Daniel-Lemire-s-blog/tree/master/2020/11/30 私の期待は、Javaが配列に適用する多くの最適化がバッファー型に適用されないことです。 もちろん、これは、Javaヒープの外部から値をマップするためにバッファーが使用されたときに何が起こるかについてはほとんど教えてくれません。私の経験では、事態はさらに悪化する可能性があることが示唆されています。 少なくともパフォーマンスに関する限り、バッファタイプによってネイティブ配列が廃止されることはありません。 英語原稿: https://lemire.me/blog/2020/11/30/java-buffer-types-versus-native-arrays-which-is-faster/
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【メモ】JSON 応用「@JsonProperty」を使用してI/Fの名称揺れを吸収する。

使用したライブラリ import com.fasterxml.jackson.annotation.JsonProperty; 使用したシチュエーション 複数の外部I/Fがあり新規のもののはずだが、A側は項目名がスネークケース、B側は項目名がキャメルケース、C側はどちらにも当てはまらないず単語単位で大文字になっているなどいろいろあり、外部設計は終わったことになっているが、あとから項目名が変わりそうな雰囲気を出していた。 項目名が変わってとgetterとsetterの呼び出し口が変更差分で出てくると、たまに変更ソースの一覧だけ見て影響範囲を心配しだす人がいたりするので、項目を定義してるオブジェクトのみの修正で済ませたかった。 あとJavaだと基本的にはキャメルケースで記述するので、項目のオブジェクトだけを見ると通常から外れているように見えるので、うっかりスネークケースをキャメルケースに修正する可能性が考えられるので防ぎたかった。 使用例 /** * JSONマッピング用のオブジェクト。 * * @author start */ public class JsonSampleBean { /** ID */ @Getter @Setter @JsonProperty("ID") // 名称が変わる場合はアノテーションの引数部分だけ修正する。 private String id; /** 名称 */ @Getter @Setter @JsonProperty("name_kana") // 名称が変わる場合はアノテーションの引数部分だけ修正する。 private String name; }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Doma2で前方一致検索をしたい場合は@prefixを活用する。

自分がかかわっているシステム開発プロジェクトで、他のチームがこのことでえらく盛り上がっていたので、自分なりに調べた結果を残しておきたいと思います(´・ω・`) 前提 商品在庫を管理するシステム(Java + Doma2)を構築するにあたって、ユーザ入力値をもとに商品名を前方一致で検索したいという要件があったとします。 この要件を実現するため、とある開発者が実施したことは、まず以下のような2-way SQL (findLikeName.sql)を用意することでした。 findLikeName.sql SELECT * FROM product WHERE name LIKE /* name */'みかん%' これを以下のような形で呼び出すわけですね。 String name = "りんご"; // ユーザの入力した値 name += "%"; List<Product> products = productDao.findLikeName(name); doSomething(products); この場合、以下のようなクエリが発行されるので、要件が実現できているように見えます。 SELECT * FROM product WHERE name LIKE 'りんご%' 問題点 たとえばユーザ入力値が%だったとします。 String name = "%"; // ユーザの入力した値 name += "%"; List<Product> products = productDao.findLikeName(name); doSomething(products); この場合、以下のようなSQLが実行されます。 SELECT * FROM product WHERE name LIKE '%%' このクエリはnameがnull以外の行にヒットしてしまいます。これでは%で商品名を前方一致検索したいという要件にこたえられていないだけでなく、セキュリティ上の問題を発生させる可能性すらあります。 修正方法 この解決策としてはExpression languageの@prefixを利用することです。 今回の場合はまずfindLikeName.sqlを以下の通りに修正します。 findLikeName.sql SELECT * FROM product WHERE name LIKE /* @prefix(name) */'みかん%' その後呼び出し方を以下のように修正します。 String name = "りんご"; // ユーザの入力した値 List<Product> products = productDao.findLikeName(name); doSomething(products); @prefixは入力パラメタを前方一致検索用の文字列に変換してくれるだけでなく、%や_のような特別な意味を持つ文字をエスケープしてくれる関数です。そのため、パラメタとして%が渡されたとしても安心ということですね。 環境情報 (pom.xmlから抜粋) pom.xml <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.seasar.doma.boot</groupId> <artifactId>doma-spring-boot-starter</artifactId> <version>1.5.0</version> </dependency> <dependency> <groupId>org.seasar.doma</groupId> <artifactId>doma-processor</artifactId> <version>2.30.0</version> <scope>provided</scope> </dependency>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Spring Bootで試験用シミュレータを作ってみる

様々なシステムと連携する業務用Webアプリを開発するお仕事をしています。 連携先のシステムとの連動が開発工程の後期になることが多いため、それまでの期間中に使用する他システムシミュレータをちゃちゃっと準備したいと思い、今回はSpring Bootで作成してみます。 環境 macOS Big Sur Visual Studio Code 1.53.1 要件 HTTP REST API IN/OUTの形式はJSON レスポンスのコード、本文をソース修正なく変更できるようにしたい 準備 Javaはインストール済み。 Mavenが入っていないのでbrewでインストールする。 % mvn -v zsh: command not found: mvn % brew install maven ... % mvn -v Apache Maven 3.8.1 (05c21c65bdfed0f71a2f2ada8b84da59348c4c5d) Maven home: /usr/local/Cellar/maven/3.8.1/libexec Java version: 15.0.2, vendor: N/A, runtime: /usr/local/Cellar/openjdk/15.0.2/libexec/openjdk.jdk/Contents/Home Default locale: ja_JP, platform encoding: UTF-8 OS name: "mac os x", version: "11.2.1", arch: "x86_64", family: "mac" 作成 4. 初めての Spring Boot アプリケーションの開発 の通りに進めていく。 POMの作成 任意のフォルダにpom.xmlを作成する。 pom.xml <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>myproject</artifactId> <version>0.0.1-SNAPSHOT</version> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.4.4</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> <description/> <developers> <developer/> </developers> <licenses> <license/> </licenses> <scm> <url/> </scm> <url/> <!-- Additional lines to be added here... --> </project> ターミナルでpom.xmlがある場所に移動しmvn packageを実行すると、target配下にmyproject-0.0.1-SNAPSHOT.jarが作成される。 初回はライブラリをMaven Central Repositoryからダウンロードするため、時間がかかる。 サンプルコントローラの作成 ソース用のディレクトリsrc/main/java/を作成し、配下にExample.javaを作成する。 Example.java import org.springframework.boot.*; import org.springframework.boot.autoconfigure.*; import org.springframework.web.bind.annotation.*; @RestController @EnableAutoConfiguration public class Example { @RequestMapping("/") String home() { return "Hello World!"; } public static void main(String[] args) { SpringApplication.run(Example.class, args); } } ターミナルでmvn spring-boot:runを実行すると、アプリケーションが起動される。 % mvn spring-boot:run ..... . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.4.4) ..... 2021-04-11 09:53:43.339 INFO 33707 --- [ main] Example : Started Example in 1.892 seconds (JVM running for 2.311) ブラウザで http://localhost:8080 にアクセスすると、Hello World!が出力されることを確認できる。 実装 mainメソッドはコントローラから切り出しておく。 また、適当にパッケージを切っておく。 ※上で作成したExample.javaは削除 Application.java package mamfrog; import org.springframework.boot.*; import org.springframework.boot.autoconfigure.*; @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } リクエストパラメータでレスポンスコードを指定 RestTestController.java package mamfrog.controller; import java.util.HashMap; import java.util.Map; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @RestController @RequestMapping("/rest") public class RestTestController { @RequestMapping("/") public ResponseEntity<Map<String, Object>> home( @RequestParam(value = "code", required = false, defaultValue = "200") String code) { Map<String, Object> map = new HashMap<>(); map.put("code", code); return new ResponseEntity<Map<String, Object>>(map, HttpStatus.resolve(Integer.parseInt(code))); } } GETパラメータcodeで指定した数値をレスポンスコードに設定するコントローラ。 呼び出し例)http://localhost:8080/rest/?code=201 不正な値を指定された場合の考慮はしていない。 レスポンスボディはリクエストのcodeをそのまま返却する。 レスポンスを任意のJSONにする TODO 補足 Rest APIの動作確認はGoogle Chromeの拡張機能「Talend API Tester」が便利。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Java]インクリメント・デクリメントについて

Javaのインクリメント・デクリメントについて オペランド(演算の対象になる式のこと。以下iで示す。)を加算または減算するときに用いる。 インクリメント オペランドを1加算すること。 i++または++iのように記述する。意味としては、i += 1と同じ。 i++と++iの違いは、記述された部分の処理の前に加算するか、処理の後に加算するかの違い。 デクリメント オペランドを1減算すること。 i--または--iのように記述する。意味としては、i -= 1と同じ。 i--と--iの違いは、記述された部分の処理の前に減算するか、処理の後に減算するかの違い。 記述例 //sample_code1 int i = 8; System.out.println("インクリメントについて\n"); System.out.println("後置のインクリメント:" + i++); //8と表示される。表示後、+1される。 System.out.println("前置のインクリメント:" + ++i); //10と表示される。表示前に+1される。 System.out.println("i += 1の場合:" + (i += 1)); //11と表示される。 System.out.println("\n以下デクリメントについて\n"); System.out.println("後置のデクリメント:" + i--); //10と表示される。 System.out.println("前置のデクリメント:" + --i); //8と表示される。 System.out.println("i -= 1の場合:" + (i -= 1)); //8と表示される。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Object-oriented programming(日本人は「オブジェクト指向」を勘違いしてるのかもしれない)

受験英語では、"Object"は、「物」とか「目的」のような意味であると学んだ。 プログラムにおける「オブジェクト指向」を学んだときは、クラスとかインスタンスとか継承などの概念を学んだ。 「オブジェクト指向」を学んだとき、私の頭の中には"Object"=「物」という考えしかなかった。 当時は、「目的」という意味を失念していたけど、英語を話す人々が、"Object-oriented programming (OOP)"と聞いた時、「目的意識を持ったプログラミング」「目的指向のプログラミング」のような概念が頭の片隅に浮かんでいるのだろうか。 オブジェクト指向プログラミングの裏には、 -「目的意識を持ったプログラミング」 -「目的指向のプログラミング」 -「Goalを意識したプログラミング」 -「効率を意識したプログラミング」 という概念が隠れているのだろうか。 :-) もしそうだどすると、日本人は「オブジェクト指向」を勘違いしてるのかもしれない。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWSでWebアプリをデプロイする方法(Java)⑨

参考サイト:https://qiita.com/hiren/items/2a4f1b55c99ebfb3fd08 Tomcatのインストール TomcatをインストールすることでJavaサーブレットを動かせる環境を整えます 利用環境 OS:MacOS ブラウザ:Chrome 前提条件 Apacheがインストールできている状態 まだ、Apacheがインストールできていない方はこちら Tomcatをインストールする 接続する 下記のsshコマンドを入力して接続します ※キーペアのファイルのパスと、ec2-user@以降は、変更して使用してください ssh -i "/Users/koyamatakumi/Documents/Development/practice/aws/myserverkey.pem" ec2-user@13.115.141.44 接続確認 下記のように表示されていれば、接続完了です SSHでの操作とrootユーザーへの切り替え rootユーザーのサインイン ソフトウェアのインストールはrootユーザーで行います 下記コマンドを入力し、rootユーザーへサインインします sudo -i Tomcatをインストールするためのユーザーを追加する useradd -s /sbin/nologin tomcat Tomcatのダウンロード ディレクトリを移動、curlコマンドでURLを入力し、コンソールからURLにリクエストを送り、ダウンロード cd /usr/local/src/ wget https://downloads.apache.org/tomcat/tomcat-9/v9.0.44/bin/apache-tomcat-9.0.44.tar.gz ダウンロードしたファイルを解凍して配置 ファイルを解凍、配置、所有者変更 tar -xzvf ~/apache-tomcat-9.0.44.tar.gz mv ~/apache-tomcat-9.0.44 /opt chown -R tomcat:tomcat /opt/apache-tomcat-9.0.44 省略可 Tomcatのシンボリックリンク作成 yumを用いたインストールを行っていない為、将来手動でTomcatバージョンを変更する際にも設定に影響が少なくなるようにシンボリックリンクを作成します。 ln -s /opt/apache-tomcat-9.0.44 /opt/apache-tomcat chown -h tomcat:tomcat /opt/apache-tomcat Tomcatログシンボリックリンク作成 展開したTomcat本体内に生成されるログファイルを他ミドルウェアと同階層のディレクトリ(/var/log 配下)にて参照できるようにシンボリックリンクを生成 ln -s /opt/apache-tomcat/logs /var/log/tomcat chown -h tomcat:tomcat /var/log/tomcat Tomcatの設定 Tomcatコマンドの登録 TomcatをOSにサービスとして登録する為、ルート権限でUnitを作成 vi /usr/lib/systemd/system/tomcat.service [i]キーを押し、下記内容を貼り付け、[esc]キーを押し、「wq」を入力し[Enter] /usr/lib/systemd/system/tomcat.service(新規作成) # Systemd unit file for default tomcat # # To create clones of this service: # DO NOTHING, use tomcat@.service instead. [Unit] Description=Apache Tomcat Web Application Container After=syslog.target network.target [Service] Type=oneshot PIDFile=/opt/apache-tomcat/tomcat.pid RemainAfterExit=yes #EnvironmentFile=/etc/tomcat/tomcat.conf #Environment="NAME=" #EnvironmentFile=-/etc/sysconfig/tomcat ExecStart=/opt/apache-tomcat/bin/startup.sh ExecStop=/opt/apache-tomcat/bin/shutdown.sh ExecReStart=/opt/apache-tomcat/bin/shutdown.sh;/opt/apache-tomcat/bin/startup.sh SuccessExitStatus=143 User=tomcat Group=tomcat [Install] WantedBy=multi-user.target Tomcatの自動起動設定 systemctl enable tomcat.service Tomcat自動起動設定確認 Loadedの(/usr/lib/systemd/system/tomcat.service;の後がenabledであれば自動起動が有効 systemctl status tomcat.service Tomcatを起動する ApacheとTomcatを起動する(先にApacheを起動する) systemctl start httpd.service systemctl start tomcat.service 起動確認 systemctl status tomcat.service ブラウザから確認 セキュリティグループの設定変更 AWSコンソールにアクセスし、EC2インスタンを開く インスタンスを選択し、[セキュリティ]タブを選択 セキュリティグループ名(sg-0dd4fe160059aa368 (my-webserver-sg))を選択する [インバウンドルールを編集]を選択 [ルールを追加]を選択し、タイプを[カスタムTCP]、ポート範囲を[8080]、ソースを[0.0.0.0/0]を選択し、右下のオレンジ色の[ルールを保存]を選択 ブラウザから確認 URLに[ http://13.115.141.44:8080 ]を入力し、Enter 下記画面が表示できれば成功 AWSでWebアプリをデプロイする方法⑩ 制作物のデプロイ
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWSでWebアプリをデプロイする方法(Java)⑧

Javaのインストール JavaをインストールすることでJavaを動かせる環境を整えます 利用環境 OS:MacOS ブラウザ:Chrome 前提条件 Apacheがインストールできている状態 まだ、Apacheがインストールできていない方はこちら Javaをインストールする 接続する 下記のsshコマンドを入力して接続します ※キーペアのファイルのパスと、ec2-user@以降は、変更して使用してください ssh -i "/Users/koyamatakumi/Documents/Development/practice/aws/myserverkey.pem" ec2-user@13.115.141.44 接続確認 下記のように表示されていれば、接続完了です SSHでの操作とrootユーザーへの切り替え rootユーザーのサインイン ソフトウェアのインストールはrootユーザーで行います 下記コマンドを入力し、rootユーザーへサインインします sudo -i ダウンロード wget https://d3pxv6yz143wms.cloudfront.net/11.0.2.9.3/java-11-amazon-corretto-devel-11.0.2.9-3.x86_64.rpm 下記の画面になればダウンロード完了 インストール sudo yum localinstall java-11-amazon-corretto-devel-11.0.2.9-3.x86_64.rpm 確認 java -version 下記の画面になれば成功 AWSでWebアプリをデプロイする方法⑨ Tomcatのインストール
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Java11 HttpClientでステータスコード204が返却されたときにIOExceptionスローされる

Java11から標準APIに追加されたHttpClientクラスを使っているとき、「IOException: unexpected content length header with 204 response」がスローされることがあります。 この原因について調べ、解決方法について少し考えました。解決方法については実装したコードも一部存在します。 概要 Java11から標準APIに追加されたHttpClientクラスでリクエストを送るとIOExceptionがスローされるときがある HTTP/1.1の仕様に従っていないレスポンスを検知したHttpClientクラスがIOExceptionをスローしていることが原因 レスポンスを作成するサーバの修正、Java12以降にバージョンアップする、例外を握りつぶす、OkHttpによって実装する等の解決方法が考えられる 注意点としてJava11でもリビジョン(11.0.7以降?)によっては解消されていること 現象 外部のWeb APIを叩くため、Java11から標準APIに追加されたHttpClientクラスを使ってHTTPリクエストを作成、レスポンスを受け取ったところ、IOExceptionがスローされました。 例外のメッセージによると、「unexpected content length header with 204 response」となっていました。 Web APIを持つサーバ側では処理が完了しており、ステータスコード204のレスポンスを返却していました。 原因 調べてみると、同じ内容の報告がありました。書かれていることには、HttpClientクラスでは、HTTPレスポンスのステータスコードが204のとき、レスポンスのヘッダに「Content-Length」が付与されている場合、IOExceptionをスローするようになっているということです。 [JDK-8218662] Allow 204 responses with Content-Length:0 - Java Bug System [JDK-8214692] HttpClient throws IOException: unexpected content length header with 204 response - Java Bug System なぜ、上述のような仕様になっているのかというと、HTTP/1.1を定義しているRFC 7230に「Content-Length」の仕様に由来しています。 RFC 7230 - Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing RFC 7230によると、 A server MUST NOT send a Content-Length header field in any response with a status code of 1xx (Informational) or 204 (No Content). とあります。 つまり、ステータスコード100番台と204のレスポンスのヘッダには、Content-Lengthをつけてはならないのです。 ステータスコード204のレスポンスはレスポンスボディが存在しません。サーバ側の実装によってはこのようなときにレスポンスヘッダにContent-Length: 0がつけられます。 そのため、Java11のHttpClientクラスはこの仕様に従って、ステータスコード204のレスポンスのヘッダにContent-Lengthが付与されていると例外を発生させます。 通信相手のサーバーからのレスポンスの内容を検査しているさいに例外が発生するため、通信相手のサーバーのAPIを叩いた場合、その処理は完了しています。 Javaの対応 この件は、あまりにも厳格すぎるということでJava12で若干修正されることになりました。 Java12ではContent-Lengthが存在しない、もしくは存在してもその値が0(ゼロ)であれば例外をスローしないというものになっています。変更内容を抜粋しました。 jdk/jdk12: 4ce47bc1fb92 - if (headers.firstValue("Content-length").isPresent()) + if (headers.firstValueAsLong("Content-length").orElse(0L) != 0L) また、Java11でもリビジョン(X.Y.Zのようにバージョンを表示するとき、Zにあたる)によっては修正されています。 記載によれば、11.0.7以降でも上記の修正がされており、例外はスローされません。 自分で確認した限りでは、11.0.9では修正が適用済みでしたが、11.0.4では例外がスローされました。 解消方法 解消方法について少し考えてみました。 レスポンスを返す側で対応できる場合、HTTP/1.1の仕様に従ってステータスコード204のレスポンスヘッダにContent-Lengthを付けないように実装を修正します。 レスポンスを受け取る側で対応するには、以下のようなかんじでしょうか。 Java12以降のバージョンを利用する IOExceptionが発生しても握りつぶす OkHttpを利用する Java12以降のバージョンを利用する Java12以降では例外が発生しないように修正されているため、バージョンアップをおこなうのも1つの手です。 ただし、業務で利用する場合などは他機能のテストが求められることもあるでしょう。また、Java11の次のLTSはJava17(2021年9月リリース予定)のため、2021年4月時点では難しいかもしれません。 IOExceptionが発生しても握りつぶす Java11をそのまま使う場合には、IOExceptionが発生しても握りつぶす処理を実装しなければなりません。 同じJava11でもリビジョンにより例外の発生有無が変わるため、開発環境で発生しなくとも本番環境で発生する可能性があります。IOExceptionが発生したときの処理、発生しないときの処理どちらも実装が必要ようになります。 レスポンスヘッダContent-Lengthが付与されていることで発生したIOExceptionなのかを見分けるには、例外のメッセージを使うしかなさそうです。(他に良い方法があれば教えてください。) メッセージはunexpected content length header with 204 responseです。 OkHttpを利用する HttpClientクラスを使わず、OSSであるOkHttpを利用して実装することでIOExceptionが発生しなくなります。 OkHttpはJava8以上であれば利用でで、Java11で登場する(Java9、10で試験導入されていたが)HttpClientの実装に依存していません。 実際にOkHttpで実装したところ、IOExceptionは発生しませんでした。使ったコードはGitHubに置きました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む