- 投稿日:2020-11-30T21:34:01+09:00
JETで始めるJakartaEE
実用的なソフトウェアを簡単に、ササッと作れるツールを持つと、プログラミングが楽しくなります。Java EEは、そのようなツールとして、大ブレイクしましたが、権利関係にからむ大人の事情によって、しばらく足踏みの状態が続いていました。しかし、ようやく前進の時期を迎えたようです。
Jakarta EEって、どうなの
Java EEは、OracleからEclipse財団への移譲にともなう混乱をようやく脱出し、12月8日に本当の出発点として、Jakarta EE9が公開されます。内容はJava EE8(Jakarta EE8)とほとんど変わりませんが、javaxからjakartaへ、パッケージ名を変更することでOracleとの権利関係を完全に清算し、これから始まる変革と発展への準備を完了しました。
おそらく、来年あたりから、Jakarta EEの静かなブームが到来することは間違いありません。プログラミング言語の目利きの皆さんはもちろんですが、これからプログラマを目指すアナタ、始めるなら、今。今が最高によいタイミングです。今から始めるJakarta EE
Java SEの世界から、実務で使われるEnterprise Javaの世界に飛び移るのは大変です。Java SEの知識・技術を習得していることは最低条件で、その上に全く新しい知識を身に付ける必要があるからです。ところが、今、Enterprise Javaの世界でも、クラウドネイティブJavaへ向けて、新たなパラダイムシフトが起きつつあります。特にマイクロサービス化への流れは、大きな潮流になりました。ただ、新しいパラダイムを理解するには、従来のEnterprise Javaをしっかり理解していることが最低条件です。
ですから、今、Jakarta EEを始めれば、このようなパラダイムシフトに対応し、それを楽しむ余裕さえ、できるはずです。というのも、この新しい世界は、まだ「新たなフロンティア」状態で、ここしばらくは革新と統合が続きそうです。もう少し時間がかかるでしょう。そして面白くなるのは、ちょうど、これからなのです。
コ、コ、コロナが・・・
Enterprise Javaの本は、もともと初心者は対象外なので、「取り扱い説明書」のような、ひどく読みにくいものばかりでした。参照資料としては優れていますが、「これじゃあ、使う人は増えないなぁ(特に日本では)」と、そう思ったものでした。それで、以前、入門書(『わかりやすいJava EE』)を出す時、Java SEを学習した普通の人達が、普通に理解できる本にしようと考えました。幸いにも、本は、多くの人たちに支持され、考えが正しかったことを実感したのでした。
今年になってから、ようやく後継の本を出す時期が来たのでは、と考えていましたが、いくつか気がかりな点がありました。NetBeansがまだ安定していないこと(かと言って、Eclipseは使い辛い)、膨大な数の例題をantビルドからMavenでのビルドへ移行しなくてはいけないこと、そしてなりよりJakarta EEの開発スケジュールが遅れ気味であること。
しかし、「夏が過ぎるころには、なんとかなるだろう」と思って準備を始めていたのですが、「コ、コ、コロナが・・・」あっという間に蔓延して、何もかも遅れ始めました。結局、12月8日に、Jakarta EE9(Java 8対応)が正式公開されることで、決着となりました。すぐ後に、Jakarta EE9.1(Java 11対応)もリリースされます。そして、すでにJakarta EE10(楽しみです!)の準備が始まっています。そうだ、JETを作ろう!
前置きが長くなりましたが、春先に、開発ツールを集めたツールキットを作ろうというアイデアが浮かびました。初めての人が対象ですから、困らないように、NetBeans、Payara Server、(Docker上の)MySQLをセットにして、ある程度設定を済ませて配布しようというアイデアです。例題やドライバ、プラグインなどもセットに入れてしまいます。基本的に、ダウンロードして展開すると、すぐにJakarta EEの開発ができる、そういうツールキットですね。
それがJET(Jakarta EE Toolkit)です。Windows環境では(Mac用もあります)、JDKを組み込んでいるので、解凍したら5分以内に使い始められます。また、NetBeansには山本潤一さんの日本語化プラグイン(junichi11.com)を入れて日本語化してあります。データベースも、docker-composeコマンドを実行するだけでMySQLを利用できます。さらに、PayaraにはあらかじめJDBCドライバが登録してあり、JDBCを設定するバッチファイルも同梱しているので、簡単にJDBC関連の設定を完了できます。
JETのインストール、データベース設定はビデオがありますので、よろしければ見てください。これなら初めてでも安心と、納得できるでしょう。
・JETのインストール(Windows)
・JETのインストール(MacOS)
・JETでのデータベース設定(Windows)
・JETでのデータベース設定(MacOS)
プロジェクトの変換、そして・・・
実は、Java EEからJakarta EEへ、引き継ぐ必要のあるプロジェクトがたくさんありました。手で書き直すのはいやだったので、「自動化できないか」と思って、archeTypeの作成方法を調べていました。参考にしたのは、次のブログです。英語ですが、Googleの自動翻訳で十分読める程度です。
Create your own Maven Archetype in 5 simple steps読んでわかったのは、ひな型のプロジェクトを用意しておいて、名前など必要な箇所を書き換えるだけなのだということです。ちょっと、拍子抜けしました。生成に結構時間がかかるので、おそらく、それ以外にいろいろなチェックをするのかもしれませんが、基本はそれだけです。
したがって、変換のためには、適切なMavenプロジェクトのひな型を用意しておいて、antプロジェクトのJavaファイルや設定ファイルをコピーし、artifactIdなどpom.xml上のスケルトン部分を書き換えるだけでよいわけです。やり方が分かったので、半日ほどで、簡単な変換プログラムを(Java SEで)作成できました。しかし、それができたとき、ちょっとしたアイデアが浮かんだのでした・・・
JSFのプロジェクトがない!
実は、NetBeansでwebアプリケーションのMavenプロジェクトを作成すると、RESTful Webサービス用のプロジェクトしかできません。つまり、従来作成していたJSF(Java Server Face)用のプロジェクトはできないのです。これからは、サーバーサイドでは、あらゆるものをサービスとして開発しようというクラウドネイティブな考えの表れでしょうか。
(ちなみに、RESTful WebサービスのUIををJSF+clientAPIで作ると、なかなか便利なのですが・・・)代わりに、任意のarcheTypeを読み込んでプロジェクトを作成するメニュー(「原型からのプロジェクト」)があり、JSF用のプロジェクトも何種類か生成できます。しかし、手順が面倒な割には、生成されるプロジェクトにびったりのものがありません。archeTypeの作成者ごとに、目指すところが違うためです。
そこでarcheTypeを自作するわけですが、今度はarcheTypeからプロジェクトを生成する手順が、面倒なことが気になりました。やってることは、コピーと書き換えだけなのだし、
「ササッとできないかなぁ?
そうだ変換プログラムを作り変えればできるのでは・・・」
そう考えたのでした。プロジェクトビルダーの作成
そこで作ったのが、builderというプログラムです。NetBeansから起動すると次のようなウェブが開きます。これはMavenプロジェクトを生成する簡単なJSFプログラムです。
プロジェクト名だけ入力して作成ボタンを押すと、瞬時に、JSF用プロジェクトができます(コピーと書き換えだけなのですごく速い)。RESTfulウェブサービス用もラジオボタンで選択できます。また、「データベースを使う」にチェックを入れると、完全な設定ファイル(persistence.xml)も生成します。データソース名は、デフォルトでjdbc/mydbとなっていますが、もちろん変更自由です。builderプロジェクトは、JETをダウンロードすると中に入っています。ソースコードやひな型のアーキタイプも見れるので、カスタマイズも簡単ですよ。
builderの使い方は見たままですが、実際に使用する様子がこちらのビデオで見れます。よろしければ、ご覧ください。生成されるMavenプロジェクト
JSF用とREST(旧JAX-RS)用のプロジェクトは、それぞれ次のように生成されます。
また、pom.xmlは、JSFとRESTで同じで、次のようです。現在は、Jakarta EE8を使う設定になっていますが、Jakarta EE9が公開され次第、JETをversion 2 にアップデート(おおむね12月末頃)し、Jakarta EE9を使う設定に変更する予定です(各種設定ファイルもすべてJakarta EE9用に更新します)。pom.xml<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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>jp.wjakarta</groupId> <artifactId>sample01</artifactId> <version>1.0</version> <packaging>war</packaging> <name>sample01</name> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <failOnMissingWebXml>false</failOnMissingWebXml> <jakartaee-api.version>8.0.0</jakartaee-api.version> </properties> <dependencies> <dependency> <groupId>jakarta.platform</groupId> <artifactId>jakarta.jakartaee-api</artifactId> <version>${jakartaee-api.version}</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter</artifactId> <version>5.5.0</version> <scope>test</scope> </dependency> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> <version>2.23.4</version> <scope>test</scope> </dependency> </dependencies> <build> <finalName>${project.artifactId}</finalName> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> <configuration> <source>11</source> <target>11</target> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>3.2.3</version> <configuration> <failOnMissingWebXml>false</failOnMissingWebXml> </configuration> </plugin> </plugins> </build> </project>JETをダウンロード
JETはこちらからダウンロードできます。ダウンロードして解凍すると、次のようなフォルダ構成になっています。130以上の例題プロジェクトも入っていますので、参考にしてください。例題のタイトル一覧表はこちらです。なお、基本からしっかり学習したい場合は、書籍『わかりやすいJakarta EE』をご覧ください。
windows用
MacOS用
- 投稿日:2020-11-30T18:04:31+09:00
【Java】抽象クラス / 抽象メソッド / abstract修飾子
【タイトル】抽象クラス / 抽象メソッド / abstract修飾子
オブジェクト指向 プログラミングで、安全な「継承の材料」を実現するために、「共通の性質を持つクラスをまとめるためのクラス」です。
abstract は「抽象的」、「理論的」、「観念的」という意味を持つ。
【説明】抽象クラス、抽象メソッド、abstract修飾子とは?
「継承の材料」になるクラスを作るとなると以下のような心配事が出てきます。
抽象クラス
、抽象メソッド
はそれらを解決する仕組みといえます。
abstract修飾子
は 「それらを定義するための修飾子」 です。abstract修飾子
【説明】abstract修飾子とは
抽象メソッドを含むクラスは抽象クラスと呼ばれ、
abstract修飾子
を付与しなければいけません。【使用場面】
Javaで
抽象クラス
、抽象メソッド
を作成する時【基本構文】
抽象クラスの定義時、「 abstract修飾子を クラス名とメソッド名の前に記述 」します。
abstract class クラス名{ abstract 戻り値の型 メソッド名(引数の型 引数); }抽象クラスと具象クラス
Javaには
具象クラス
と抽象クラス
の2種類がありこれらの違いを比べてみます。具象クラス
具象クラスとは、具象という単語が意味する通り「具象メソッド(処理を記述したメソッド)の集まり」です。
抽象クラス
抽象クラスとはインターフェースと通常のクラスの中間のようなクラスで、「 抽象メソッド(処理の記述がないメソッド)が1つ以上持つクラス 」のことです。
抽象クラスは自身だけでは意味をもたず、サブクラスに継承されることで初めて機能します。抽象クラスの特徴
特徴についてのまとめは以下です。
- 処理の中身を記述しない
- 多重継承はできない
- 直接インスタンス化して使用できない。
- インスタンス化するには、抽象クラスを継承した具象クラスで全ての抽象メソッドをオーバーライドする必要がある。
- サブクラスでコンストラクタを記述しなければならない
- 抽象クラスの抽象メソッドは宣言のみ
抽象クラスのメリット
一見不便な点が目立つ
抽象クラス
を用いる利点は以下のように「メンテナンス性がとても優れている」ことです。
- コンパイラのチェック機構により、コーディングミスの早期発見が可能
- オーバーライドすべきメソッドが一目で分かるため、ソースの可読性が向上
- 階層化により、プログラムの保守性が高い
- メソッド名の統一とロジックを共通化によって処理を把握しやすい
- 共通の処理を全てのクラスに書き込む必要がなくなる
- 複数人で開発を行う場合に実装レベルのルールを作れる
【使用場面】
- 「絶対的な決まり」を正確に実施させたい場合
- 多重継承させたくない 場合
【基本構文】
以下のようにクラス名、メソッド名の前にabstractキーワードを記述します。
abstract class クラス名{ 抽象メソッド }抽象メソッド
【説明】
抽象メソッドは「 抽象クラス内の abstract が付いたメソッド 」です。
抽象メソッドのメリット
抽象メソッドのオーバーライドによって、
「 コーディングの時点ではどこに挿入するかは決まってないが、いずれ必要となるメソッド 」をあらかじめ宣言しておき、詳細は後のクラスで定義するといったコーディングが可能です。【抽象メソッドの宣言】
抽象メソッド
は、抽象クラス
を継承するクラスでのオーバーライドと中身の処理の実装が必須です。
「派生クラスで抽象メソッドを使うには、抽象クラスを「extends」句で継承する」必要があります。abstract class 抽象クラス名 { abstract 戻り値の型名 メソッド名(引数); } class 派生クラス名 extends 抽象クラス名 { 戻り値の型名 メソッド名(引数) { 処理内容; } }【サンプルコード】 「食べ物」という抽象クラスから「カレー」と「チョコ」という具象クラスを生成
抽象クラス「Foods」と、それを継承する具象クラス2つ(Curry, Chocolate)を作成します。
抽象クラスで実装したメソッドにより、動作が変化することを確認しましょう。
【Mainクラス】Main.java
public class Main { public static void main(String[] args) { Foods curry = new Curry(); // Curryクラスをインスタンス化 curry.foodTaste(); //foodTasteメソッドを呼び出す Foods choco = new Chocolate();// Chocolateクラスをインスタンス化 choco.foodTaste(); //foodTasteメソッドを呼び出す } }【抽象クラス】Foods.java
//抽象クラス (食べ物) //abstract修飾子を付けて「抽象クラス」 abstract class Foods { private String name; public Foods(String name) { this.name = name; } // 食べ物の味を出力。 public void foodTaste() { System.out.println(name + "の味は: " + taste()); } // 「抽象メソッドの呼び出し」ため、abstract修飾子を使用。 // 具象クラスからのみアクセスするため、protected修飾とする abstract protected String taste(); }【具象クラス】Curry.java
// 抽象クラスの「Foods」を継承する public class Curry extends Foods { public Curry() { super("カレー"); } // メソッドを実装する protected String taste() { return "辛い"; } }【具象クラス】Chocolate.java
//抽象クラスの「Foods」を継承する public class Chocolate extends Foods { public Chocolate() { super("チョコレート"); } // メソッドを実装する protected String taste() { return "甘い"; } }【実行結果】
カレーの味は: 辛い チョコレートの味は: 甘いサンプルコード解説
- 抽象クラス Foods を作成し、foodTasteメソッド を 抽象メソッド とします。
- 具象クラスCurryを作成し、Foodsクラス を継承。
- 続いて foodTasteメソッド を実装し、同様に具象クラス Chocolateクラス を作成
- Curryクラス、Chocolateクラス のインスタンスを作成し、
- foodTasteメソッド を呼びます。
- 次に具象メソッドの実装に従い、インスタンスの動作が変化します。
- ただ、Foodsクラス をインスタンス化できないことに注意。
【まとめ】
JavaSilverの範囲でも抽象クラス / 抽象メソッド / abstract修飾子 についてはかならず出るとのことなので、しくみはかくじつにおさえておきたいところです。
参考文献・記事
- 投稿日:2020-11-30T17:03:02+09:00
public変数とprivate変数のアクセス権限について
概要
親の変数はpublicのみアクセス可能、privateはアクセスできない
/* * 親クラス */ public class Magician { public String Skil_rod; // 両手杖 private String Skil_short_sord; //短剣 private String Skil_whip; // ムチ public String Skil_shield; // 盾 private String Skil_magic; // まほう } /* * 子クラス */ public class Pundit extends Magician{ Pundit(String rod,String shield){ this.Skil_rod = rod; // 杖 this.Skil_shield = shield; // 盾 } }概要
概要を書きます
実装内容
作成方法
引用
ここに引用する内容を記載します
*test
+test
-test参考
- 投稿日:2020-11-30T14:26:17+09:00
SOAPのstubファイル作成
近年RESTAPIが増えていますが、
まだまだSOAPもエンタープライズな用途としては使用する機会があると思います。JavaのAxis2でSOAPAPIを構築した際の、wsdlファイルから呼び出し用のStubファイルを作成する手順の備忘録を載せておきます。
環境
Windows10
必要なもの
・SOAPのWSDLファイル(API提供元からもらってください)
・Axis2バイナリ(次項目で取得)
・JDK(事前にJAVA_HOMEを設定してください)手順
1.Axis2バイナリ取得
以下のAxis2ページからDownloadsにアクセス
http://axis.apache.org/axis2/java/core/index.html2.作業フォルダにファイル配置
落としたファイルを下記に解凍
併せてWSDLファイルも配置C:\dev3.環境変数設定
環境変数を起動し、
新規追加でAXIS2_HOMEを設定してください。
今回は以下の値
4.Stubファイル作成
PowerShellを起動して、対象フォルダに移動します。
※事前にJAVA_HOMEは設定しておいてください。
PowerShell起動後に行った場合は、PowerShellを再起動してください。cd C:\dev以下コマンドを実施
C:\dev\axis2-1.7.9\bin\wsdl2java -o TestSvc -uri TestSvc.wsdl-uri は、WSDLへのパスです。WSDLがURLでの提供だった場合は、URLを記述します。
-o は、Stub作成先のフォルダです。実行すると同フォルダに -o で指定したフォルダが作成され、
SOAP実行用のStub.java CallbackHandler.javaのファイルがフォルダ内に作成されているかと思います。
この2つをシステムに組み込み、SOAPを実行してください!
- 投稿日:2020-11-30T14:17:56+09:00
Adroid OpenCVでエラー
bitmapToMat
を利用したら、
エラーcannot access class 'Bitmap'. Check your module classpath for missing or conflicting dependencies
とのこと。該当のソース
opencv/java/src/org/opencv/android/Utils
を見てみると、インポートエラーを発見。なるほど。
解決法
このサイトを参考にして、opencvのbuild.gradleでバージョンをいじったらエラーが消えました。
めでたしめでたし。
よくわからないけど、動いたからヨシ!
- 投稿日:2020-11-30T14:17:56+09:00
Android OpenCVでエラー
bitmapToMat
を利用したら、
エラーcannot access class 'Bitmap'. Check your module classpath for missing or conflicting dependencies
とのこと。該当のソース
opencv/java/src/org/opencv/android/Utils
を見てみると、インポートエラーを発見。なるほど。
解決法
このサイトを参考にして、opencvのbuild.gradleでバージョンをいじったらエラーが消えました。
めでたしめでたし。
よくわからないけど、動いたからヨシ!
- 投稿日:2020-11-30T13:22:19+09:00
MacでEclipseにJavaFXを導入するには
EclipseにJavaFXを導入したい
MacでEclipseを使用してJavaのGUIプログラミングを行っていたのですが,JavaFXを導入しようとした際に何が必要なのか分からなかったためまとめてみました.
(2020.11.30時点)動作環境
macOS Catalina(10.15.5)
Eclipse IDE for Java Developers (includes Incubating components)
Version: 2020-09 (4.17.0)
Build id: 20200910-1200e(fx)clipse(3.6.0)
手順
Help -> Eclipse Marketplace
を選択- 検索バーに「fx」と入力
e(fx)clipseをインストール
https://gluonhq.com/products/javafx/
上記URLのLatest Releaseから対応するSDKをダウンロード
今回はJavaFX Mac OS X SDKダウンロードしたopenjfx-15.0.1_osx-x64_bin-sdk.zipを解凍し,任意の場所に置く
Eclipse -> Preferences
,検索バーに「user」と入力
Java -> Build Path -> User Libraries
を選択右側のNewから任意の名前を入力し,新規作成
Add External JARs...
を選択し,5.でダウンロードしたフォルダのlib内のjarファイルを全て選択ここまででインストール関連の作業は終了
動作確認
新規プロジェクト -> Others
からJavaFX -> JavaFX Project
を選択Project name
を入力し,NextCreate module-info.java file
のチェックを外す -> finish- 作成したプロジェクトを右クリックし,
Bulid Path -> Add Library
User Library
から8.で作成したライブラリーを選択- 実行ボタンのプルダウンからRun Configurationsを開き,VM argumentsに
--module-path SDK-path --add-modules javafx.controls,javafx.fxml
を入力
SDK-path
は5.のフォルダのlibの絶対パス- その下の
Use~~
のチェックを外すこれで白紙のウインドウが表示されたはず
- 投稿日:2020-11-30T13:22:19+09:00
EclipseにJavaFXを導入するには【MacOSX,2020最新版】
はじめに
MacでEclipseを使用してJavaのGUIプログラミングを行っていたのですが,JavaFXを導入しようとした際に手順が分からず,他の記事を参考にしたもののエラーが出て困ったため,いくつかのサイトを見て導入できた方法をまとめました.
(2020.11.30時点)動作環境
macOS Catalina(10.15.5)
Eclipse IDE for Java Developers (includes Incubating components)
Version: 2020-09 (4.17.0)brew cask install eclipse-java
e(fx)clipse(3.6.0)
javaSE 14
導入手順
https://gluonhq.com/products/javafx/
上記URLのLatest Releaseから対応するSDKをダウンロード
今回はJavaFX Mac OS X SDK
ダウンロードしたopenjfx-15.0.1_osx-x64_bin-sdk.zipを解凍し,任意の場所に置く
Eclipse -> Preferences
,検索バーに「user」と入力右側のNewから任意の名前を入力し,新規作成
Add External JARs...
を選択し,5.でダウンロードしたフォルダのlib内のjarファイルを全て選択ここまででインストール関連の作業は終了
動作確認
Project name
を入力し,Next
Create module-info.java file
のチェックを外す -> finish
User Library
から導入手順8.で作成したライブラリーを選択実行ボタンのプルダウンからRun Configurationsを開き,VM argumentsに
--module-path SDK-path --add-modules javafx.controls,javafx.fxml
を入力
SDK-path
は導入手順5.でダウンロードしたフォルダのlibの絶対パスこれで白紙のウインドウが表示されたはず
JavaFXを導入するにあたってこれまでに発生したエラー
- エラー: JavaFXランタイム・コンポーネントが不足しており、このアプリケーションの実行に必要です
-> 動作確認6. が必要- Error occurred during initialization of boot layer
java.lang.module.FindException: Module javafx.controls not found
-> この記事の内容,手順で解決できるはずおわりに
MacにJavaFXの環境構築を行う方法をまとめました.
動作しなかった点などありましたらコメントいただけるとありがたいです.参考にしたサイト
https://qiita.com/tarosa0001/items/05ac653a091b7d1290f9#
https://style.potepan.com/articles/15319.html
https://stackoverflow.com/questions/53795661/javafx-modular-application-java-lang-module-findexception-module-javafx-contro
- 投稿日:2020-11-30T11:26:10+09:00
Javaで書かれたSpring APIをKotlinで書いて比較してみた
前書き
今までSpring Bootを使って
Java
で書いていたAPIを、
Kotlin
ではどう書くのか調べて実装してみたので、その備忘録。記事概要
いわゆる階層構造システムの基本となる、以下の実装について比較してみる。
- Entity
- Controller
- Service
- Repository
環境
- Spring Boot 2.4.0
- JavaコードはLombokを使用する
共通ポイント
Javaと比較した時のKotlinを理解する上での(個人的な)ポイントは、
val/var
の意図(valは読み取り専用、varは読み書き両方可能)- デフォルトの修飾子は
public
- Javaでの
public class
→class
のみで同義に- コンストラクタの書き方
- コンストラクタに関しては色々な固有機能があるみたいなのですが、ここでは実装のための書き方のみ記します
- カプセル化のためのgetter/setterは自動で作ってくれる(Lombokなどの外部ライブラリではなく仕様として)
- 文末に
;
付けないEntity
Java
import lombok.Data; import org.hibernate.annotations.CreationTimestamp; import org.hibernate.annotations.UpdateTimestamp; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; import java.time.LocalDateTime; @Entity @Table(name = "english_word") @Data public class EnglishWordJava { // ID @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; // 単語名 private String word; // 意味 private String meaning; // 作成日時 @CreationTimestamp private LocalDateTime createTime; // 更新日時 @UpdateTimestamp private LocalDateTime updateTime; }Kotlin
import org.hibernate.annotations.CreationTimestamp import org.hibernate.annotations.UpdateTimestamp import java.time.LocalDateTime import javax.persistence.* @Entity @Table(name = "english_word") data class EnglishWord( // ID @Id @GeneratedValue(strategy = GenerationType.IDENTITY) val id: Long = 0, // 単語名 var word: String = "", // 意味 var meaning: String = "", // 作成日時 @CreationTimestamp val createTime: LocalDateTime = LocalDateTime.now(), // 更新日時 @UpdateTimestamp val updateTime: LocalDateTime = LocalDateTime.now() )メモ
- データクラスと言うKotlinにおける仕様を用いている。(
data class ○○
)- 初期値を明示している理由は、インスタンス生成時に引数を入れたくないため。(データクラスでは(色々記述しないと)全メンバを引数にとるコンストラクタのみしか生成されないため)
- なお普通のクラスでも同様の実装は可能なのでお好みで良いかも
- 明示的に
val/var
を分けているがそうする必要があるかはわかっていない。。(おまけ)登録Form
わざわざ記載するほどのものではないですが一応。
Java
import lombok.Data; @Data public class EnglishWordJavaForm { // 単語名 private String word; // 意味 private String meaning; }Kotlin
data class EnglishWordForm( // 単語名 val word: String, // 意味 val meaning: String )Controller
Java
import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; import java.util.List; /* 自作クラスのimportは割愛 */ @RestController @RequestMapping(path = "/api") @RequiredArgsConstructor public class EnglishWordJavaController { private EnglishWordJavaService englishWordJavaService; /** 取得API */ @GetMapping("/word") @ResponseStatus(HttpStatus.OK) public List<EnglishWordJava> getEnglishWord() { return englishWordJavaService.getEnglishWord(); } /** 登録API */ @PostMapping("/word") @ResponseStatus(HttpStatus.CREATED) public void registerEnglishWord(@RequestBody EnglishWordJavaForm englishWordJavaForm) { englishWordJavaService.registerEnglishWord(englishWordJavaForm); } }Kotlin
import org.springframework.http.HttpStatus import org.springframework.web.bind.annotation.* /* 自作クラスのimportは割愛 */ @RestController @RequestMapping(path = ["/api"]) class EnglishWordController(private val englishWord: EnglishWordService) { /** * 取得API */ @GetMapping("/word") @ResponseStatus(HttpStatus.OK) fun getEnglishWord(): List<EnglishWord> { return englishWordService.getEnglishWord() } /** * 登録API */ @PostMapping("/word") @ResponseStatus(HttpStatus.CREATED) fun registerEnglishWord(@RequestBody englishWordForm: EnglishWordForm) { topService.registerEnglishWord(englishWordForm) } }メモ
- サービス呼ぶ処理が簡潔になった
void
を表現するには、型を指定しないだけで良いようService
Java
import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import java.util.List; /* 自作クラスのimportは割愛 */ @Service @RequiredArgsConstructor public class EnglishWordJavaService { private EnglishWordJavaRepository englishWordJavaRepository; /** データを全て取得 */ public List<EnglishWordJava> getEnglishWord() { return englishWordJavaRepository.findAll(); } /** 登録 */ public void registerEnglishWord(EnglishWordJavaForm englishWordJavaForm) { EnglishWordJava englishWordJava = new EnglishWordJava(); englishWordJava.setWord(englishWordJavaForm.getWord()); englishWordJava.setMeaning(englishWordJavaForm.getMeaning()); englishWordJavaRepository.save(englishWordJava); } }Kotlin
import org.springframework.stereotype.Service /* 自作クラスのimportは割愛 */ @Service class EnglishWordService(private val englishWordRepository: EnglishWordRepository) { /** * データを全て取得 */ fun getEnglishWord(): List<EnglishWord> = englishWordRepository.findAll() /** * 登録 */ fun registerEnglishWord(englishWordForm: EnglishWordForm) { val englishWord = EnglishWord() englishWord.word = englishWordForm.word englishWord.meaning = englishWordForm.meaning englishWordRepository.save(englishWord) } }メモ
- 関数を定義する際、処理が1行のみなら波括弧
{}
を省略して書ける- getter/setterの呼び出し方が若干違う
Repository
Java
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; /* 自作クラスのimportは割愛 */ @Repository public interface EnglishWordJavaRepository extends JpaRepository<EnglishWordJava, Long> {}Kotlin
import org.springframework.data.jpa.repository.JpaRepository import org.springframework.stereotype.Repository /* 自作クラスのimportは割愛 */ @Repository interface EnglishWordRepository : JpaRepository<EnglishWord, Long> {}後書き
ざっくりとSpring Bootを使ってKotlinでAPI実装の記述をしてみました。
まだ使って間もないので、Kotlin特有の機能などもっと調べて記事にできたらいいなと思ってます。記述量を大幅に減らせるので、慣れたら大分楽になる印象。
性能面でもいつか比較してみたいな(願望)参考
- 投稿日:2020-11-30T10:28:51+09:00
#1(Java) 整数、小数を代入する際の留意点・強制的な型変換
最初に
初めまして、現在就職活動中兼javaを学習しています。kosukeと申します。
qiitaでは、学習中にアウトプットしておきたい内容を備忘録として残すために投稿させて頂きます。
マークダウン記法もよく理解できていないため、見づらかったらすみません。。。(これから改善していきます。)
また、誤った点がありましたら、コメントにてご指摘いただけると幸いです。目次
・代入する際のルール
・型を無視した場合
・エラーを出さず、強制的に代入させる
・型の大小関係の説明代入する際のルール
javaで変数を宣言する際は、
( 型 ) ( 変数名 ) = ( 値 );
の順番で宣言するルールがあるため、int num = 3;のような記述になります。
始めにアウトプットも兼ねて上記のコードを説明すると、
intというのは整数が代入されるという意味の型を指しています。
そのため、変数numには整数の値が代入されなければいけません。型を無視した場合
例えば、
int num = 5.0;のようなコードはコンパイルエラーになります。
こちらの理由は、int型を指定しているにも関わらず、double型の値を代入しているためです。整数の型と小数の型には大小関係があり、それに従わないとエラーになるのです。
※型の大小関係は下の内容で説明しています。エラーを出さず、強制的に代入させる
上記コードの改善点は、
double型の5.0という値をint型に変換することで解決する事が出来ます。int num = (int)5.0;このように変数名の前に記述されている型を指定する事で、5.0が整数5に変換されnumに代入されます。(強制的な型変換を指示する演算子をキャスト演算子と言います。)
しかし、こちらの変換方法は一見便利なように見えますが、デメリットもあります。
変換して小数5.0が整数5になりましたが、小数点以下が捨てられ情報の欠如が発生します。
これによりデータの欠損にも繋がるため、よほどの理由がない限りキャスト演算子は使用されないようです。型の大小関係の説明
< 大小関係(byte型が最小でdouble型が最大となります) >
1:byte(最小)
2:short
3:int
4:long
5:float
6:double(最大)byte・shortはそれほど利用頻度が高くないみたいなので、整数の値を扱う時はint型を指定するという解釈をしています。
しかし、long型の場合、扱う数値が大きいかつ値の末尾にLやlが付いている特徴があります。float・doubleは小数点の値を代入する際用いられる型になります。
こちらも、小数を扱う場合大体doubleを指定するそうですが、float型の場合は、値の末尾にFかfが付いています。私がこちらの大小関係を理解する際に用いた考え方が、
< 型を箱と考える >
byte型が一番小さい箱で型が大きくなるにつれて箱が大きくなっていくイメージです。
先ほどの誤ったコードを例にすると、int num = 5.0;intという箱にdouble型は大きすぎて入りません。。。
なので、こちらのコードはエラーになるのです。しかしこちらのコードは、
double num = 3;
doubleという大きい箱にint型は入れる事が可能です。
(int型の方がdouble型よりも大小関係が小さいため)
こちらの考え方で学習するとコードのミスを減らす事が出来ました。参考テキスト:スッキリわかるjava入門
終わりに
最後まで読んで頂き有り難うございました。
初めてのqiita投稿という事で、勝手が分からず読みにくいと感じられた方。申し訳ないです。。。
今後も投稿を続けていくので、書き方は都度改善していきます。
- 投稿日:2020-11-30T08:48:45+09:00
【Java・SpringBoot】Spring JDBC でユーザー更新処理(SpringBootアプリケーション実践編13)
ホーム画面からユーザー一覧画面に遷移し、ユーザーの詳細を表示するアプリケーションを作成して、Spring JDBCの使い方について学びます⭐️
前回はユーザー詳細画面を作ったので、今回はユーザー更新処理を実装します^^
構成は前回の記事を参考にしてください⭐️前回の記事
【Java・SpringBoot】Spring JDBC でユーザー詳細画面(SpringBootアプリケーション実践編12)リポジトリークラス修正
- JdbcTemplateのupdateメソッドを使用
- SQL文と、PreparedStatementの値を引数に渡していく
int rowNumber = jdbc.update("UPDATE M_USER" ...+ " WHERE user_id = ?", user.getPassword(),...user.getUserId());
UserDaoJdbcImpl.javapackage com.example.demo.login.domain.repository.jdbc; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; import com.example.demo.login.domain.model.User; import com.example.demo.login.domain.repository.UserDao; @Repository("UserDaoJdbcImpl") public class UserDaoJdbcImpl implements UserDao { @Autowired JdbcTemplate jdbc; // Userテーブルの件数を取得. @Override public int count() throws DataAccessException { //全件取得してカウント int count = jdbc.queryForObject("SELECT COUNT(*) FROM m_user", Integer.class); return count; } // Userテーブルにデータを1件insert. @Override public int insertOne(User user) throws DataAccessException { //1件登録 int rowNumber = jdbc.update("INSERT INTO m_user(user_id," + " password," + " user_name," + " birthday," + " age," + " marriage," + " role)" + " VALUES(?, ?, ?, ?, ?, ?, ?)", user.getUserId(), user.getPassword(), user.getUserName(), user.getBirthday(), user.getAge(), user.isMarriage(), user.getRole()); return rowNumber; } // Userテーブルのデータを1件取得 @Override public User selectOne(String userId) throws DataAccessException { // 1件取得 Map<String, Object> map = jdbc.queryForMap("SELECT * FROM m_user" + " WHERE user_id = ?", userId); // 結果返却用の変数 User user = new User(); // 取得したデータを結果返却用の変数にセットしていく user.setUserId((String) map.get("user_id")); //ユーザーID user.setPassword((String) map.get("password")); //パスワード user.setUserName((String) map.get("user_name")); //ユーザー名 user.setBirthday((Date) map.get("birthday")); //誕生日 user.setAge((Integer) map.get("age")); //年齢 user.setMarriage((Boolean) map.get("marriage")); //結婚ステータス user.setRole((String) map.get("role")); //ロール return user; } // Userテーブルの全データを取得. @Override public List<User> selectMany() throws DataAccessException { // M_USERテーブルのデータを全件取得 List<Map<String, Object>> getList = jdbc.queryForList("SELECT * FROM m_user"); // 結果返却用の変数 List<User> userList = new ArrayList<>(); // 取得したデータを結果返却用のListに格納していく for (Map<String, Object> map : getList) { //Userインスタンスの生成 User user = new User(); // Userインスタンスに取得したデータをセットする user.setUserId((String) map.get("user_id")); //ユーザーID user.setPassword((String) map.get("password")); //パスワード user.setUserName((String) map.get("user_name")); //ユーザー名 user.setBirthday((Date) map.get("birthday")); //誕生日 user.setAge((Integer) map.get("age")); //年齢 user.setMarriage((Boolean) map.get("marriage")); //結婚ステータス user.setRole((String) map.get("role")); //ロール //結果返却用のListに追加 userList.add(user); } return userList; } // Userテーブルを1件更新. @Override public int updateOne(User user) throws DataAccessException { //1件更新 int rowNumber = jdbc.update("UPDATE M_USER" + " SET" + " password = ?," + " user_name = ?," + " birthday = ?," + " age = ?," + " marriage = ?" + " WHERE user_id = ?", user.getPassword(), user.getUserName(), user.getBirthday(), user.getAge(), user.isMarriage(), user.getUserId()); return rowNumber; } // Userテーブルを1件削除. @Override public int deleteOne(String userId) throws DataAccessException { return 0; } @Override public void userCsvOut() throws DataAccessException { } }サービスクラスを修正
- 0より大きい値が返ってきたらupdate成功と判断
UserService.javapackage com.example.demo.login.domain.service; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.example.demo.login.domain.model.User; import com.example.demo.login.domain.repository.UserDao; @Service public class UserService { @Autowired UserDao dao; public boolean insert(User user) { // insert実行 int rowNumber = dao.insertOne(user); // 判定用変数 boolean result = false; if (rowNumber > 0) { // insert成功 result = true; } return result; } public int count() { return dao.count(); } public List<User> selectMany() { // 全件取得 return dao.selectMany(); } public User selectOne(String userId) { // selectOne実行 return dao.selectOne(userId); } /** * 1件更新用メソッド. */ public boolean updateOne(User user) { // 判定用変数 boolean result = false; // 1件更新 int rowNumber = dao.updateOne(user); if (rowNumber > 0) { // update成功 result = true; } return result; } }コントローラークラスを修正
ボタン名によるメソッド判定
- 更新処理の@PostMappingアノテーションで更新処理用のメソッドと削除処理用のメソッドを分ける
- ユーザー詳細画面では、更新/削除ボタンのどちらを押しても
/userDetail
にPOSTする- 更新処理か、削除処理かを判別する必要がある
- →params属性を使って、URLとボタンのname属性の両方を見て、処理を判断できる
- ユーザー詳細画面の更新ボタンのhtmlでいうと
<button class="btn btn-primary btn-lg pull-right" type="submit" name="update">更新</button>
- このname属性の値を、params属性に入れることで、ボタンによってコントローラークラスのメソッドを分けることができる!
@PostMapping(value = "/userDetail", params = "update")
HomeController.javapackage com.example.demo.login.controller; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import com.example.demo.login.domain.model.SignupForm; import com.example.demo.login.domain.model.User; import com.example.demo.login.domain.service.UserService; @Controller public class HomeController { @Autowired UserService userService; //結婚ステータスのラジオボタン用変数 private Map<String, String> radioMarriage; private Map<String, String> initRadioMarrige() { Map<String, String> radio = new LinkedHashMap<>(); // 既婚、未婚をMapに格納 radio.put("既婚", "true"); radio.put("未婚", "false"); return radio; } @GetMapping("/home") public String getHome(Model model) { //コンテンツ部分にユーザー詳細を表示するための文字列を登録 model.addAttribute("contents", "login/home :: home_contents"); return "login/homeLayout"; } @GetMapping("/userList") public String getUserList(Model model) { //コンテンツ部分にユーザー一覧を表示するための文字列を登録 model.addAttribute("contents", "login/userList :: userList_contents"); //ユーザー一覧の生成 List<User> userList = userService.selectMany(); //Modelにユーザーリストを登録 model.addAttribute("userList", userList); //データ件数を取得 int count = userService.count(); model.addAttribute("userListCount", count); return "login/homeLayout"; } @GetMapping("/userDetail/{id:.+}") public String getUserDetail(@ModelAttribute SignupForm form, Model model, @PathVariable("id") String userId) { // ユーザーID確認 System.out.println("userId = " + userId); // コンテンツ部分にユーザー詳細を表示するための文字列を登録 model.addAttribute("contents", "login/userDetail :: userDetail_contents"); // 結婚ステータス用ラジオボタンの初期化 radioMarriage = initRadioMarrige(); // ラジオボタン用のMapをModelに登録 model.addAttribute("radioMarriage", radioMarriage); // ユーザーIDのチェック if (userId != null && userId.length() > 0) { // ユーザー情報を取得 User user = userService.selectOne(userId); // Userクラスをフォームクラスに変換 form.setUserId(user.getUserId()); //ユーザーID form.setUserName(user.getUserName()); //ユーザー名 form.setBirthday(user.getBirthday()); //誕生日 form.setAge(user.getAge()); //年齢 form.setMarriage(user.isMarriage()); //結婚ステータス // Modelに登録 model.addAttribute("signupForm", form); } return "login/homeLayout"; } /** * ユーザー更新用処理. */ @PostMapping(value = "/userDetail", params = "update") public String postUserDetailUpdate(@ModelAttribute SignupForm form, Model model) { System.out.println("更新ボタンの処理"); //Userインスタンスの生成 User user = new User(); //フォームクラスをUserクラスに変換 user.setUserId(form.getUserId()); user.setPassword(form.getPassword()); user.setUserName(form.getUserName()); user.setBirthday(form.getBirthday()); user.setAge(form.getAge()); user.setMarriage(form.isMarriage()); //更新実行 boolean result = userService.updateOne(user); if (result == true) { model.addAttribute("result", "更新成功"); } else { model.addAttribute("result", "更新失敗"); } //ユーザー一覧画面を表示 return getUserList(model); } @PostMapping("/logout") public String postLogout() { //ログイン画面にリダイレクト return "redirect:/login"; } @GetMapping("/userList/csv") public String getUserListCsv(Model model) { return getUserList(model); } }SpringBootを起動してユーザ一覧画面確認!
- http://localhost:8080/userList
- ユーザー詳細画面から、名前を変更して更新ボタンを押し、ユーザー一覧画面に戻ると表示内容が変わることが確認できます
- これで更新処理を実装できました〜^o^
- 投稿日:2020-11-30T03:58:42+09:00
【Java】printf()メソッド (任意のフォーマットで文字を出力)
【タイトル】printf()メソッド
「 任意のフォーマットで コンソールやログに文字を出力するためのメソッド 」
【説明】printf()メソッド とは
この メソッド は簡単にいうと 「
指定子
を呼ばれる記号を使い、文字の好きな部分を装飾するメソッド 」です。
printf()メソッド
の 「f」は、フォーマット(書式)を意味しています。printfメソッドとprintメソッドの違い
System.out.println(), System.out.print() は「文字列をそのまま表示することしかできない」メソッドなのに対し、
printf()メソッド
は「出力する文字などに 様々な装飾 を施すことが可能 」なのが大きな違いで、その分非常に自由度が高いといえます。【使用場面】
printf()メソッド
は文字列や数値などを 指定した書式で画面に出力することができるため、以下のようなことが可能です。
- 「10,000」のように、値をカンマ区切りで整形する
- 数字の後ろに単位を付けて出力する
【書き方】
printf()メソッド
の記述の仕方は以下です。
printf()メソッド
は以下の形式で記述します。System.out.printf(書式, 引数1, 引数2, ・・・);書式指定子チートシート (値の形式を変更する記号)
「
printfメソッド
で 出力する変数を編集する 」には、書式指定子
という記号を使用します。書式指定子
は、編集したい内容によって色々な書き方や種類があります。
以下がその一覧表です。【型を指定する書式指定子】
指定子 型 説明 記述例 出力例 % なし 書式指定子の開始 なし なし d 整数 10進整数表記になる printf("%d", 123) 123 o 整数 8進整数表記になる printf("%o", 123) 173 x 整数 16進整数表記になる printf("%x", 123) 7b e 小数 指数で出力 printf("%e", 123.4f) 1.23E+02 f 小数 小数点数出力 printf("%f", 123.4f) 123.4 s 文字列 文字列を出力 printf("%s", “abc”) abc c 文字 文字を出力 printf("%c", ‘a’) a b 真偽値 真偽値を出力 printf("%b", true) true 【日付の書式指定子】
指定子 説明 記述例 出力例 tY 年(4桁) printf("%tY", new Date()); 2020 ty 年(2桁) printf("%ty", new Date()); 20 tm 月(2桁) printf("%tm", new Date()); 11 td 日(2桁) printf("%td", new Date()); 30 te 日(1~2桁) printf("%te", new Date()); 1 tH 時(2桁)24時間制 printf("%tH", new Date()); 21 tl 時(1~2桁)12時間制 printf("%tl", new Date()); 9 tM 分(2桁) printf("%tM", new Date());v 59 tS 秒(2桁) printf("%tS", new Date());v 30 tF 日付 printf("%tF", new Date()); 2020-11-30 tT 時刻 printf("%tT", new Date()); 21:04:05 【その他の書式指定子】
指定子 指定子を付与することで得られる効果 - 左寄せで出力される(幅指定必須) + 符号を出力する 0 前に0を詰める 【サンプルコード】 変数の値を表示する
第2引数以降には、整数や文字列などの変数を入れることができます。
、以下のプログラムは、「整数型の変数と、文字列の変数を編集して出力」したものです。
内容に関してはコード内のコメントを参照してください。// 整数型変数に値を格納 int num1 = 100; int num2 = 1000; int num3 = 10000; int num4 = 100000; // 文字列型変数に値を格納 String str = "¥"; // 「%s」は文字列型の変数。 // 「%,6b」は、「%6」をベースに、カンマ区切りと、最大桁数6という意味合いをもたせています。 // 「%n」は 改行を意味しています。 System.out.printf("%s%,6dです。%n", str, num1); System.out.printf("%s%,6dです。%n", str, num2); System.out.printf("%s%,6dです。%n", str, num3); System.out.printf("%s%,6dです。%n", str, num4); // カンマを入れない場合の出力結果も比較してください。 System.out.printf("%s%6dです。", str, num4);【実行結果】
¥ 100です。 ¥ 1,000です。 ¥10,000です。 ¥100,000です。 ¥100000です。【サンプルコード】 先頭に「0」をつけて、01,02,03,,,10,11,12と出力する
//拡張for文を用いて 1 ~ 10 の数を 二桁表記で出力する for (int i = 0; i <= 10; i++) { if (i == 0) { continue; } //"%0"は「前に0を詰める」"2"は「最大桁数」"d"は「整数」の書式指定子です。 System.out.printf("%02d,", i); }【実行結果】
01,02,03,04,05,06,07,08,09,10ちなみに、最大桁数3に指定した場合は以下のようになります。
System.out.printf("%03d,", i);出力結果
001,002,003,004,005,006,007,008,009,010,"%03"は第二引数を3文字で出力するため、3文字に満たない場合は不足分を0詰めされて上記のような結果となります。
System.out.printf()による日時の出力
【説明】
指定子を用いることで、取得した現在時刻を日本人に馴染みあるフォーマットへ変換するといったことも簡単に行えます。
【サンプルコード】 取得した現在時刻の形式を任意に変換
まず、現在時刻を取得します。
import java.util.Date; public class AboutPrintf { public static void main(String[] args) { // 取得した日付をインスタンス化する。 Date date = new Date(); //日付を出力する System.out.println(date); } }【実行結果】
Mon Nov 30 03:33:04 JST 2020取得した現在時刻の形式をに変換します。
「 年月日(曜日)午前or午後〇〇時〇〇分 」
java
System.out.printf("%tY年%<tB月%<te日(%<ta)%<tp%<tI時%<tM分", date);
<!-- 実行結果 -->【実行結果】
2020年11月月30日(月)午前03時36分変換完了しました。
【まとめ】
記事を書きながら色々な使い方ができる便利なメソッドだとおもいました。
組み合わせによって非常に幅広い表現が可能になるので、数をこなして習得していこうと思います。参考文献・記事
- 投稿日:2020-11-30T02:23:53+09:00
TomcatのJavaアプリ(VM環境)をTransformation Advisorを使ってモダナイズ(事前準備編)
1.はじめに
この投稿は、「 TomcatのJavaアプリ(VM環境)をTransformation Advisorを使ってモダナイズする 」 の内容を実際に、試したい方向けに必要な環境構築の手順について記載します。
今回、必要な環境は、以下の2つにります。
- TomcatのJavaアプリの分析を行うTransformation Advisor
- 分析対象のTomcat環境
2つの環境の導入を行った後に、「 TomcatのJavaアプリ(VM環境)をTransformation Advisorを使ってモダナイズする 」の流れにそって、手順をすすめると、TomcatのJavaアプリ(VM環境)をTransformation Advisorを使ったモダナイズを体感していただけます。
2. Transformation Advisor の インストール
Transformation Advisorの導入手順は、Qiita記事 「Transformation Advisor Localをインストールした時の手順メモ 」を使って導入してください。
3. 分析対象のTomcat環境のインストール
今回は2020/11/30でEOLを迎えるCentOS6をつかって構築しました。
分析対象の構成
- OS: CentOS6(x86_64)の最小構成インストール
- JDK: IBM Java 7 (java-x86_64-71)
- Tomcatのバージョン: 6.0.53
作業前の前提条件: 名前解決できること DNS等で名前解決できない場合は、 /etc/hostsにホスト名 (例: c603 )を記入してください。
# cat /etc/hosts 127.0.0.1 c603 localhost localhost.localdomain localhost4 localhost4.localdomain4
IBM Java SDK のダウンロード
作業環境:ローカルPC
ローカルPCのブラウザにて, 「 IBM SDK, Java Technology Edition, Version 7 Release 1 」 にアクセスし、
そして、Linux on AMD64/EMT64Tの下記のパッケージをダウンロード
Installable package (InstallAnywhere as root)
(File name: ibm-java-x86_64-sdk-7.1-4.75.bin, Size: 129MB)IBM Java SDK のインストール
作業環境:centOS
作業ユーザー: root事前にローカルPCにダウンロードした、IBM Java SDK のバイナリ「ibm-java-x86_64-sdk-7.1-4.75.bin」をCentOSにアップロードします。
そして、バイナリ「ibm-java-x86_64-sdk-7.1-4.75.bin」 を実行してIBM Java SDKのインストールを行います。
bash ./ibm-java-x86_64-sdk-7.1-4.75.binインストールが完了すると 「 /opt/ibm/java-x86_64-71 」のPATHにIBM Java SDKがインストールされます。
Tomcatのインストール
モダナイズを体感するためには、古めのTomcatをインストールする必要があるので、今回はTomcat6をインストールします。
まずは、Tomcat 6.0.53のバイナリを/usr/localにダウンロードし、ダウンロードしたapache-tomcat-6.0.53.zipを解凍します。
# curl -L https://archive.apache.org/dist/tomcat/tomcat-6/v6.0.53/bin/apache-tomcat-6.0.53.zip -o /usr/local/apache-tomcat-6.0.53.zip # cd /usr/local # ls apache-tomcat-6.0.53.zip bin etc games include lib lib64 libexec sbin share src # unzip apache-tomcat-6.0.53.zip Archive: apache-tomcat-6.0.53.zip # pwd /usr/local [root@c603 local]# ls apache-tomcat-6.0.53 bin games lib libexec share apache-tomcat-6.0.53.zip etc include lib64 sbin src # cd apache-tomcat-6.0.53 # ls bin conf lib LICENSE logs NOTICE RELEASE-NOTES RUNNING.txt temp webapps次に、Tomcat起動時に、JAVA_HOMEのパスを通すために Tomcatのsetenv.shをJAVA_HOMEの設定を行います。
# cat <<EOF > /usr/local/apache-tomcat-6.0.53/bin/setenv.sh JAVA_HOME=/opt/ibm/java-x86_64-71 EOFそして、Tomcatのbinフォルダのスクリプトに実行権限を付与します。
# cd /usr/local/apache-tomcat-6.0.53/bin/ # ls bootstrap.jar cpappend.bat setenv.sh tomcat-native.tar.gz catalina.bat daemon.sh shutdown.bat tool-wrapper.bat catalina.sh digest.bat shutdown.sh tool-wrapper.sh catalina-tasks.xml digest.sh startup.bat version.bat commons-daemon.jar setclasspath.bat startup.sh version.sh commons-daemon-native.tar.gz setclasspath.sh tomcat-juli.jar # chmod +x *.shこれで準備が整いました。 startup.shスクリプトを実行して、Tomcatを起動します。
# bash /usr/local/apache-tomcat-6.0.53/bin/startup.sh Using CATALINA_BASE: /usr/local/apache-tomcat-6.0.53 Using CATALINA_HOME: /usr/local/apache-tomcat-6.0.53 Using CATALINA_TMPDIR: /usr/local/apache-tomcat-6.0.53/temp Using JRE_HOME: /opt/ibm/java-x86_64-71 Using CLASSPATH: /usr/local/apache-tomcat-6.0.53/bin/bootstrap.jar
正常にTomcatが起動できているか確認するためには、ログを確認します。
「INFO: Server startup in 480 ms」と表示されれば正常起動しています。# tail -100f /usr/local/apache-tomcat-6.0.53/logs/catalina.out INFO: Deploying web application directory manager Nov 30, 2020 9:35:30 AM org.apache.coyote.http11.Http11Protocol start INFO: Starting Coyote HTTP/1.1 on http-8080 Nov 30, 2020 9:35:30 AM org.apache.jk.common.ChannelSocket init INFO: JK: ajp13 listening on /0.0.0.0:8009 Nov 30, 2020 9:35:30 AM org.apache.jk.server.JkMain start INFO: Jk running ID=0 time=0/12 config=null Nov 30, 2020 9:35:30 AM org.apache.catalina.startup.Catalina start INFO: Server startup in 480 msTomcatは8080番ポートを使って起動しますが、CentOS6のデフォルトでは、8080は
ファイアーウォール(iptables)で閉じているので、外部からアクセスできません。
今回は、便宜上、iptablesを停止して動作確認します。# service iptables stop iptables: Setting chains to policy ACCEPT: filter [ OK ] iptables: Flushing firewall rules: [ OK ] iptables: Unloading modules: [ OK ]最後に、ローカルPCからブラウザで、CentOSのIPアドレスの8080番ポートにあくせすすると(例: http://192.168.26.22:8080 ) Tomcatのサンプルページが表示されます。
4.最後に
これで、ソースホスト(分析対象)のTomcatの環境 と Tomcat環境を分析するTransformation Advisorの導入が終了しました。この後は、「 TomcatのJavaアプリ(VM環境)をTransformation Advisorを使ってモダナイズする 」の投稿を使って、ぜひ、Transformation Advisorを使ったTomcatのモダナイズを体感してください!