- 投稿日:2021-01-24T23:18:54+09:00
【Java】Date型の日時を計算する方法
プログラミング勉強日記
2021年1月24日
JavaでDate型の日時を計算する方法を示す。Date型とは
Javaで日時の処理をするために定義されたデータ型で、日時情報は1970年1月1日0時からの経過時間をミリ秒で表したものである。
Date型を使った日付の取得// 2021年1月24日日曜日 22時56分12秒 Sun Jan 18 22:55:12 JST 2021Calendarクラスとは
CalendarクラスはDate型と同様日時を扱うデータ型で、Date型よりも細かい日時演算ができる。Date型の演算を行う場合はCalendar型に変換して、演算処理を行う。
Date型をCalendar型に変換する方法Calendar Calendar型オブジェクト名 = Calendar.getInstance(); Calendar型オブジェクト名.setTime(Date);Calendar型からDate型を取得する方法Date型オブジェクト名 = Calendar型オブジェクト名.getTime();Date型の日時を加減算する方法
Date型ので日時を加減算するためにはCalendar型のaddメソッドを使う。加算する場合は、第二引数で正の整数を指定する。減算する場合は第2引数に負の整数を指定する。
日付を加算する方法Calendar型.add(年月日時間などを指定, 値); // 第1引数で渡すもの Calendar.YEAR // 年 Calendar.MONTH // 月 Calendar.DAY_OF_MONTH // 日 Calendar.HOUR_OF_DAY // 時間 Calendar.MINUTE // 分// 1日先の日付を取得したいとき Calendar型.add(Calendar.DAY_OF_MONTH, 1); // 2ヵ月前の日付を取得したいとき Calendar型.add(Calendar.MONTH, -2);サンプルプログラム
import java.util.Date; import java.util.Calendar; class Sample{ public static void main(String args[]){ // Date型で現在時刻を取得する Date date = new Date(); Calendar calendar = Calendar.getInstance(); calendar.setTime(date); //Date型の持つ日時を表示 System.out.println(date); //Date型の持つ日時の4年後を表示(日時の加算) calendar.add(Calendar.YEAR, 4); date = calendar.getTime(); System.out.println(date); //Date型の持つ日時の3日前を表示(日時の減算) calendar.add(Calendar.DAY_OF_MONTH, -3); date = calendar.getTime(); System.out.println(date); } }実行結果Sun Jan 24 23:18:33 JST 2021 Fri Jan 24 23:18:33 JST 2025 Tue Jan 21 23:18:33 JST 2025参考文献
- 投稿日:2021-01-24T22:56:16+09:00
【JSP/サーブレット】 JSPファイルを使ってブラウザに「Hello World」を表示させてみた!
前回の続きになります
※動的プロジェクトの作成などは、前の記事で紹介しています
1,JSPファイルの作成
2,保存場所とソースコード
3,サーバーを起動
サーバー起動(Tomcat)
ブラウザ表示(Google Chrome)
4,振り返り
JSPファイルをブラウザ表示させることができました
JSPファイルはMVCモデルの中で、V(view)として活躍します
URLとリクエストメソッドにも注目すると、
URL ⇨ localhost:8080/JSP_Servlet/view/index.jsp
Request Method ⇨ GET
となっています.
サーブレットクラスを起動させた場合とURLに少し違いがあると思います。
URLにも注意しながら学習を進めて下さい
5,次のステップ
次回は、フォワード(forward)を扱います!
要するに、サーブレットクラスからJSPファイルに画面遷移する方法です!キーワード : RequestDispatcher
- 投稿日:2021-01-24T20:20:19+09:00
AWS_WEB3層環境構築③
前回の記事
https://qiita.com/shinichi_yoshioka/items/e358f57a3ecb7735c091
前々回(初回)の記事
https://qiita.com/shinichi_yoshioka/items/7226b9ebaad06c569c80
構成図
前回の続きをやっていく。
VSCodeすら使ったことなかったが、VSCodeの拡張機能にdrawioというものがあって、
カッコ良いアイコンなどが使えるのを教えてもらった。
さっそく使ってみたが、色のセンスはお察しだ。初回記事ではDBの切り替えをしたいと書いたが、まずは正常な状態を作りたい。
WEBサーバにはリバースプロキシの設定(To:APサーバ)をし、APサーバでJSPを使って、
DBを参照できることを正常な状態とすることにした。◆リバースプロキシの設定
対象:WEBサーバ
/etc/nginx/conf.d 配下にserver.confというファイルを作る。cd /etc/nginx/conf.d vi server.confserver.confの中身は、APサーバのプライベートアドレス:ポート番号(8080)を指定した。
#server.conf server{ location / { proxy_pass http://172.16.3.246:8080/; } }nginxのサービスを再起動(systemctl restart nginx)して、ブラウザにWEBサーバのパブリックアドレスを入力し、
APサーバのtomcatのページが表示されることを確認した。
[自宅PC]-[Internet]-[WEBサーバ]-[APサーバ] ←ここまでのイメージ
◆JDBC for MySQLのインストール
対象:APサーバ
APサーバにJDBCドライバーをインストールしようと思ったのだが、AmazonLinux用がなかった^^;;;
ということで、前回作ったAPサーバはぶっ壊して、再度RedHatで作りなおして、Tomcatのインストールまでは済んだとこ。
これがクラウドの良いところである。(オンプレでOS選定ミスってたら、首飛んでた)
EIPを使っていたので、記事の不整合もない!
OSやJavaのバージョン、Tomcatの状態はこんな感じ。
MySQLコミュニティサーバからJDBCドライバーのRPM(RHEL用)をダウンロードしインストールしようとしたが、
依存関係でopenjdk-headlessが必要と言われた。
yumでopenjdk-headlessをインストール後に、mysql-connector-javaをRPMコマンドでインストールした。wget https://dev.mysql.com/get/Downloads/Connector-J/mysql-connector-java-8.0.23-1.el8.noarch.rpm yum install java-1.8.0-openjdk-headless -y rpm -ivh mysql-connector-java-8.0.23-1.el8.noarch.rpm rpm -qa | grep mysql◆サンプルデータベースの用意
対象:DBサーバ
参照するためのDBを用意するため、以下からworld databaseをインポートすることにした。
https://dev.mysql.com/doc/index-other.html
まずはDBサーバにssh接続し、wgetコマンドにてダウンロードした。
gz形式だったため、gunzipコマンドにて解凍した。wget https://downloads.mysql.com/docs/world.sql.gz gunzip world.sql.gz次にMySQLにログインし、SOURCEコマンドにて、world.sqlをインポートした。
mysql> SOURCE root/world.sql;/rデータベースに"world"がインポートされた。
mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | TEST | | auth | | mysql | | performance_schema | | sys | | world | +--------------------+データベースをworldに切り替え、テーブルが存在することを確認した。
mysql> use world; mysql> show tables; +-----------------+ | Tables_in_world | +-----------------+ | city | | country | | countrylanguage | +-----------------+ 3 rows in set (0.00 sec)MySQLはデフォルトで、外部からのアクセスを許可されていないため、
以下の権限追加をした。
権限追加後は、FLUSHにて権限を再読み込みした。
※*(すべてのデータベース).*(すべてのテーブル)を認識できるようにユーザ名@接続元IPアドレス(APサーバ)へ権限を与えるmysql> GRANT all ON *.* TO root@'172.16.3.246' IDENTIFIED BY 'MySQLのパスワード'; mysql> FLUSH PRIVILEGES; ←権限関係の再読み込み◆JDBCドライバの配置とサンプルJSPの作成
対象:APサーバ
JDBCドライバーは/lib配下に配置しないとダメらしく、初期配置から移動させた。mv /usr/share/java/mysql-connector-java.jar /opt/tomcat/lib/
JSPについては初心者でggりまくった結果、JSPも配置が重要らしく、
/opt/tomcat/webapps配下にjspディレクトリを作成し、パーミッションを750にし、所有者はtomcatに変更した。cd /opt/tomcat/webapps mkdir jsp chown tomcat:tomcat jsp chmod 750 jsp/opt/tomcat/webapps/jsp配下には、test.jspを作成したが、
JSPの知識がなさすぎて、以下URLを参考にさせていただいた。
https://michael-e29.hatenadiary.org/entry/20111107/1320630444jdbc:mysql://172.16.3.6:3306/world
↑DBサーバのアドレス:ポート番号/データベース名
※worldはデータベース名。
※ID,Name,CountryCode,District,Populationはデータベースのカラム名###test.jspの中身### <%@ page contentType="text/html; charset=utf-8" import="java.sql.*" %> <html> <head> <title>DB参照テスト</title> </head> <body> <h1>DB参照テスト</h1> <tr> <td>ID</td> <td>Name</td> <td>CountryCode</td> <td>District</td> <td>Population</td> </tr> <% Class.forName("com.mysql.jdbc.Driver"); Connection conn=DriverManager.getConnection("jdbc:mysql://172.16.3.6:3306/world?" + "user=root&password=MySQL@001&useUnicode=true&characterEncoding=utf-8"); Statement st=conn.createStatement(); ResultSet res = st.executeQuery("select * from city;"); while(res.next()){ out.println("<tr>"); out.println("<td>" + res.getString("ID") + "</td>"); out.println("<td>" + res.getString("Name") + "</td>"); out.println("<td>" + res.getString("CountryCode") + "</td>"); out.println("<td>" + res.getString("District") + "</td>"); out.println("<td>" + res.getString("Population") + "</td>"); out.println("</tr>"); } st.close(); conn.close(); %> </table> </body> </html>APサーバとDBサーバの連携の準備ができたので、APサーバのTomcatサービスを再起動。
あとDBサーバのmysqldサービスを再起動し、ブラウザにJSPのパスを入力する。
ちなみにJSPファイルを置いたパスは /opt/tomcat/webapps/jsp/test.jsp だが、
ブラウザでは/webapps/配下を入力する。
http://WEBサーバのパブリックアドレス/jsp/test.jsp
ぐちゃぐちゃだけど、一応DB参照できたので
一応WEB3層構成はできた・・・。
めちゃ時間かかったけど、つまづきながらハマりながら色々覚えれたので良かったです。
次回はNATゲートウェイの作成と、AnsibleでJSP内の文字列を置換することで
参照するDBを切り替えようと思います。つづく
- 投稿日:2021-01-24T09:46:12+09:00
java.net.http.HttpClient でJSONレスポンスを受信するとスレッドがフリーズした
事象に遭遇したのは AdoptOpenJDK jdk-11.0.9.1+1。
事象発生コード
数年ぶりにJavaで開発を行うことになり、外部APIをHTTPリクエストで呼び出してレスポンスのJSONを受信する必要が出てきた。
最後にJavaで開発した時はJDK 8でHTTPリクエストを行う標準ライブラリは
java.net.HttpURLConnection
くらいしかなかったが、
JDK 11からはjava.net.http.HttpClient
が正式に標準ライブラリ入りしていたらしいので使用することにした。JSONからのデシリアライズはJacksonを使おうと考えたが、
HttpClient
はレスポンスボディをreactive-streamsで処理しているらしい。最も簡単な取り扱い方だと
HttpResponse.BodyHandlers#ofString()
で一度レスポンスボディをString
にしてからパースする方法だが、
せっかくのreactive-streamsなのでいい感じにデータ受信完了後にJSONを処理できる方法が無いか調べると
java.net.http.HttpResponse.BodySubscribers#mapping(HttpResponse.BodySubscriber<T>, Function<? super T,? extends U>)
のjavadocが見つかった。javadocの中でJacksonを利用してレスポンスボディを直接デシリアライズしてJavaオブジェクトを返すサンプルコードが書かれていたので、
そこで紹介されているコードをほぼそのまま流用させてもらうことにした。実装は大体以下のようなコードになった。
public static <T> BodySubscriber<T> jsonSubscriber( ObjectMapper objectMapper, Class<T> klazz) { Objects.requireNonNull(objectMapper); Objects.requireNonNull(klazz); return BodySubscribers.mapping( BodySubscribers.ofInputStream(), (InputStream bodyStream) -> { try (bodyStream) { return objectMapper.readValue(bodyStream, klazz); } catch (IOException e) { throw new UncheckedIOException(e); } }); }上記のメソッドで生成したサブスクライバを
java.net.http.HttpResponse.BodyHandler<T>
の実装クラスで返すことで
HttpClient
でレスポンスを受信した時にデシリアライズが実施されるようにしていた。public class FooResponseHandler implements HttpResponse.BodyHandler<Foo> { private final HttpResponse.BodySubscriber<Foo> subscriber; public FooResponseHandler(ObjectMapper objectMapper) { this.subscriber = jsonSubscriber(objectMapper, Foo.class); } @Override public HttpResponse.BodySubscriber<Foo> apply(HttpResponse.ResponseInfo responseInfo) { if (responseInfo.statusCode() == 200) { return this.subscriber; } throw new RuntimeException("Unknown response"); } }発生した問題
HttpClient
の動作確認のために外部APIを呼び出しすると、なぜか数十秒経過後にタイムアウトが発生する。TCPダンプを見るとAPIからのレスポンスは1秒かからず返ってきており、レスポンスボディも想定された内容だった。
しかし、
HttpClient
はタイムアウトが発生する。デバッガーで原因個所を特定していくと、
BodySubscribers.mapping()
の第2引数に渡された
マッピング関数が実行された後でスレッドがフリーズしているらしいことが分かった。このあたりでJDKの不具合を疑い調べてみるとStack Overflowなどに情報をまとめてくれている方たちがいた。
- https://stackoverflow.com/questions/57629401/deserializing-json-using-java-11-httpclient-and-custom-bodyhandler-with-jackson
- https://bugs.openjdk.java.net/browse/JDK-8217264
- https://bugs.openjdk.java.net/browse/JDK-8217627
HttpClient
は内部でI/O操作のためのExecutor
でCompletableFuture
を実行しているが、
HTTPレスポンスボディを処理する中でブロッキングAPIが呼び出しされるとExecutor
のスレッドが枯渇してしまうことがあるらしい。具体的にどこでスレッドが枯渇しているのかは追いかけていないが、
InputStream
からの読み取りでフリーズしているように見えたので、
レスポンスボディのバイト列をInputStream
に追加する処理と
InputStream
から読み取ってJSONデシリアライズする処理で競合のような状態が発生したと予想している。対処方法は、紹介されているとおり
BodySubscriber<T>
をBodySubscriber<Supplier<T>>
に変更するしかないと思われる。
HttpClient
内部処理が完了した後でレスポンスボディにアクセスする様になるため、スレッドの問題が回避できる。ただ、この方法だとHTTPレスポンスボディのデータが全て
InputStream
にバッファリングされていそうなので、
JSONデシリアライズみたいな目的の時はHttpResponse.BodyHandlers#ofString()
を使用するのとメモリ効率などがあまり変わらない気がするのが気になる。この不具合はJDK 13で修正されているようだが、同時にjavadocも更新されており
BodySubscriber
ないぶでレスポンスボディのInputStream
などにアクセスする場合は
BodySubscriber<Supplier<T>>
を使用する方法が推奨されるようになったようだ。
- 投稿日:2021-01-24T09:46:12+09:00
java.net.http.HttpClient でHTTPレスポンスを受信するとリクエストがタイムアウトした
事象に遭遇したのは AdoptOpenJDK jdk-11.0.9.1+1。
事象発生コード
数年ぶりにJavaで開発を行うことになり、外部APIをHTTPリクエストで呼び出してレスポンスのJSONを受信する必要が出てきた。
最後にJavaで開発した時はJDK 8でHTTPリクエストを行う標準ライブラリは
java.net.HttpURLConnection
くらいしかなかったが、
JDK 11からはjava.net.http.HttpClient
が正式に標準ライブラリ入りしていたらしいので使用することにした。JSONからのデシリアライズはJacksonを使おうと考えたが、
HttpClient
はレスポンスボディをreactive-streamsで処理しているらしい。最も簡単な取り扱い方だと
HttpResponse.BodyHandlers#ofString()
で一度レスポンスボディをString
にしてからパースする方法だが、
せっかくのreactive-streamsなのでいい感じにデータ受信完了後にJSONを処理できる方法が無いか調べると
java.net.http.HttpResponse.BodySubscribers#mapping(HttpResponse.BodySubscriber<T>, Function<? super T,? extends U>)
のjavadocが見つかった。javadocの中でJacksonを利用してレスポンスボディを直接デシリアライズしてJavaオブジェクトを返すサンプルコードが書かれていたので、
そこで紹介されているコードをほぼそのまま流用させてもらうことにした。実装は大体以下のようなコードになった。
public static <T> BodySubscriber<T> jsonSubscriber( ObjectMapper objectMapper, Class<T> klazz) { Objects.requireNonNull(objectMapper); Objects.requireNonNull(klazz); return BodySubscribers.mapping( BodySubscribers.ofInputStream(), (InputStream bodyStream) -> { try (bodyStream) { return objectMapper.readValue(bodyStream, klazz); } catch (IOException e) { throw new UncheckedIOException(e); } }); }上記のメソッドで生成したサブスクライバを
java.net.http.HttpResponse.BodyHandler<T>
の実装クラスで返すことで
HttpClient
でレスポンスを受信した時にデシリアライズが実施されるようにしていた。public class FooResponseHandler implements HttpResponse.BodyHandler<Foo> { private final HttpResponse.BodySubscriber<Foo> subscriber; public FooResponseHandler(ObjectMapper objectMapper) { this.subscriber = jsonSubscriber(objectMapper, Foo.class); } @Override public HttpResponse.BodySubscriber<Foo> apply(HttpResponse.ResponseInfo responseInfo) { if (responseInfo.statusCode() == 200) { return this.subscriber; } throw new RuntimeException("Unknown response"); } }発生した問題
HttpClient
の動作確認のために外部APIを呼び出しすると、なぜか数十秒経過後にタイムアウトが発生する。TCPダンプを見るとAPIからのレスポンスは1秒かからず返ってきており、レスポンスボディも想定された内容だった。
しかし、
HttpClient
はタイムアウトが発生する。デバッガーで原因個所を特定していくと、
BodySubscribers.mapping()
の第2引数に渡された
マッピング関数が実行された後でスレッドがフリーズしているらしいことが分かった。スレッドはフリーズしていたが、HTTPリクエストタイムアウトを発生させるスレッドは動いていたようで、
そのスレッドから例外が通知されるまでの数十秒間が待ち時間になっていたようだ。原因と対処
このあたりでJDKの不具合を疑い調べてみるとStack Overflowなどに情報をまとめてくれている方たちがいた。
- https://stackoverflow.com/questions/57629401/deserializing-json-using-java-11-httpclient-and-custom-bodyhandler-with-jackson
- https://bugs.openjdk.java.net/browse/JDK-8217264
- https://bugs.openjdk.java.net/browse/JDK-8217627
HttpClient
は内部でI/O操作のためのExecutor
でCompletableFuture
を実行しているが、
HTTPレスポンスボディを処理する中でブロッキングAPIが呼び出しされるとExecutor
のスレッドが枯渇してしまうことがあるらしい。具体的にどこでスレッドが枯渇しているのかは追いかけていないが、
InputStream
からの読み取りでフリーズしているように見えたので、
レスポンスボディのバイト列をInputStream
に追加する処理と
InputStream
から読み取ってJSONデシリアライズする処理で競合のような状態が発生したと予想している。対処方法は、紹介されているとおり
BodySubscriber<T>
をBodySubscriber<Supplier<T>>
に変更するしかないと思われる。
HttpClient
内部処理が完了した後でレスポンスボディにアクセスする様になるため、スレッドの問題が回避できる。ただ、この方法だとHTTPレスポンスボディのデータが全て
InputStream
にバッファリングされていそうなので、
JSONデシリアライズみたいな目的の時はHttpResponse.BodyHandlers#ofString()
を使用するのとメモリ効率などがあまり変わらない気がするのが気になる。この不具合はJDK 13で修正されているようだが、同時にjavadocも更新されており
BodySubscriber
ないぶでレスポンスボディのInputStream
などにアクセスする場合は
BodySubscriber<Supplier<T>>
を使用する方法が推奨されるようになったようだ。
- 投稿日:2021-01-24T02:11:28+09:00
【JSP/サーブレット】 サーブレットクラスを使ってブラウザに「Hello World」を表示させてみた!
1,環境設定
Eclipse2020 Full Edition
Java11
Tomcat92,動的プロジェクト作成:
3,サーブレットクラスの作成場所
4、ディレクトリ構造とソースコード
5、ブラウザをGoogle Chromeに設定
6、サーバーの起動とブラウザ表示
サーバー起動(Tomcat)
ブラウザ表示(Google Chrome)
表示することができました!!
URLとリクエストメソッドにも注目すると、
URL ⇨ localhot:8080/JSP_Servlet/HelloServlet
Request Method : GET
となっています.7、次のステップ
次回は、JSPファイルからブラウザ表示をさせてみたいと思います!
- 投稿日:2021-01-24T02:11:28+09:00
Java JSP/サーブレット サーブレットクラスを使ってブラウザに「Hello World」を表示させてみた!
1,環境設定
Eclipse2020 Full Edition
Java11
Tomcat92,動的プロジェクト作成:
3,サーブレットクラスの作成場所
4、ディレクトリ構造とソースコード
4、ブラウザをGoogle Chromeに設定
5、サーバーの起動とブラウザ表示
サーバー起動(Tomcat)
ブラウザ表示(Google Chrome)
表示することができました!!
URLとリクエストメソッドにも注目すると、
URL ⇨ localhot:8080/JSP_Servlet/HelloServlet
Request Method : GET
となっています.6、次のステップ
次回は、JSPからブラウザ表示をさせてみたいと思います!
- 投稿日:2021-01-24T00:12:43+09:00
【Java】AtcorderのABC-189に参加しました。
こんばんは。
2021/1/23に、AtcorderのABC-189に参加しました。
レートは以下の通りとなっています。https://atcoder.jp/users/ishikawaryou
C問題は処理時間でエラーになり、良いロジックを思いつけず負けました・・。
まだまだですね。
ともあれレートを13→51に更新!
A問題は5分以内、B問題15分以内で安定して解けるようになってきました。
半年前に始めたときはA問題ですら会社の昼休み中(1時間-お弁当の時間)に解けなかった事を思うと、着実な進歩です。A問題
入力した3文字が全部同じか、そうでないかチェックするというもの。
String型で入力した文字列を、char型にして同じかチェックしました。import java.util.Scanner; import java.util.HashSet; import java.util.Set; public class Main{ public static void main(String args[]){ Scanner sc = new Scanner(System.in); String c = sc.next(); if((c.charAt(0)==c.charAt(1))&&(c.charAt(1)==c.charAt(2))){ System.out.println("Won"); }else{ System.out.println("Lost"); } } }B問題
飲んだアルコール飲料の容量(v)と、アルコール度数(p)から、摂取したアルコール量(al)を求め、アルコール許容量(x)を超えて酔っぱらうかどうかを調べます。
整数型での答えを求められていましたが、int型は小数点以下を切り捨ててしまうので、思い切って数字を100倍して、アルコール度数10.5%→1050と算出させるようにしました。
もっとスマートなやり方があると思うんですけどね・・。import java.util.Scanner; import java.util.HashSet; import java.util.Set; public class Main{ public static void main(String args[]){ Scanner sc = new Scanner(System.in); int n = sc.nextInt(); int x = sc.nextInt(); int v[] = new int[n]; int p[] = new int[n]; int al = 1; char flg = '0'; for(int i=0;i<n;i++){ v[i] = sc.nextInt(); p[i] = sc.nextInt(); if(i==0){ al = v[i]*p[i]; } else { al = al+(v[i]*p[i]); } if(al>x*100){ System.out.println(i+1); flg = '1'; i=n; } //System.out.println("al/100 " + al/100); } if(flg=='0'){ System.out.println(-1); } } }C問題
*不正解のためソースは割愛します。
ロジック自体は正解に近づいていたようですが、処理時間がかかりTLEとなりました。
(21ケースAC、12ケースでTLE)。やはり2重ループはだめでしたね。
感想
週末にちょっとした(失礼?)戦いがあるのは、いい刺激になります。
僕はこれでも高校時代は数学が好きで得意科目だったので、少し高校時代の数学の楽しさを思い出してきて楽しいです。これなら継続できそうな気がします。これからもコツコツ取り組んで、茶色を目指したいと思います!
同じく灰色レベルで頑張っている方、お互い頑張りましょう!