- 投稿日:2020-09-16T23:27:07+09:00
Java カプセル化について private public
カプセル化とは
参考: 「徹底攻略 Java SE 11 Silver 問題集」から引用:
カプセル化は、ソフトウェアを分割する際に、関係するデータとそのデータを必要する処理を1つにまとめ、無関係なものや関係性の低いものをクラスから排除することで「何のためのクラスなのか?」というクラスの目的を明確化するために行い、ほかのクラスに重複するデータや処理がない状態を目指すもの。
修飾子
private 設定するとクラス外からアクセスする事ができなくなる(クラス内では可能) 非公開状態
public クラスの外からでもアクセスする事が可能ユーザが入力した値が0から10の場合private変数numに代入し表示する
class Number { private int num;//外からはアクセスできなくする public void setNum(int n){ if(n >= 0&&n <= 10){ num = n; }else{ system.out.println("入力された値は無効です。"); } } public int getNum(){// return num; //戻り値を返す } } import java.io.*; class Sample { public static void main(String[] args) throws IOException{ BufferedReader br = new BufferedReader(new inputstreamreader(system.in)) String str = br.readLine();//8を入力した事にします。 n = Integer.parseInt(str); Number nb1 = new Number(); //このようなアクセスはできない //nb1.num = 8; nb1.setNum(n); system.out.println("入力された値は"+nb1.getNum()+"です。"); } }private変数を更新する為に同じクラス内のpublicメソッドを使い条件式を設定し通過した変数にのみ変数を更新する事で誤った値の更新を防ぐ事ができる。
- 投稿日:2020-09-16T22:47:10+09:00
Java クラス変数 クラスメソッドについて
それぞれの変数、メソッドについて
・インスタンス変数
各オブジェクトに関連づけされているフィールド(変数)の事を指す。
・インスタンスメソッド
各オブジェクトに関連づけされているメソッドの事を指す。・クラス変数
クラス全体に関連づけされているフィールドの事を指す。
・クラスメソッド
クラス全体に関連づけされているメソッドの事を指す。クラス変数定義方法
class Car { public static int Car //クラス変数 型名の前にstaticが必要 publicは修飾子 } 型名 クラス名クラスメソッド定義方法
class Car { public static void show(); //クラスメソッド メソッド名 }Carクラスファイルを利用するプログラムでクラスメソッドshow()を呼び出す方法
Car.show();クラスメソッドの特徴
・クラスメソッドはオブジェクトが作成されていなくても呼び出せる。
・クラスメソッド内ではインスタンス変数、インスタンスメソッドにアクセスする事はできない。余談
メソッド内で宣言した変数はローカル変数といい、宣言したメソッド外では利用する事ができず、値を格納しているのはメソッドが終了するまで。class Car{ int num;//ローカル変数 static int sum;//クラス変数 void setCar(int a){//ローカル変数 int a //ローカル変数 } }
- 投稿日:2020-09-16T22:03:50+09:00
PowerMockでstaticイニシャライザを無効化する
目次
- PowerMockを使うための環境構築手順
- PowerMockにおけるモックとスパイ
- PowerMockでstaticメソッドをモック化する
- PowerMockでコンストラクタをモック化する
- PowerMockでprivateメソッドをモック化する
- PowerMockのWhiteBoxを使ってみる
- PowerMockでstaticイニシャライザを無効化する ←今ここ
概要
PowerMockにはstaticイニシャライザを無効化するための
@SuppressStaticInitializationFor
というアノテーションが提供されています。使用例
モック化クラス
クラスがロードされる際に、staticイニシャライザによってフィールドに"value"という文字列が設定されます。
ここでは、フィールドに"value"が設定されていればtrueを返し、そうでなければfalseを返すjudgeメソッドを用意しました。
SampleEm.javapublic class SampleEm { private static String field = null; static { field = "value"; } public boolean judge() { return "value".equals(field); } }テストクラス
JUnitでPowerMockを使用するために、
@RunWith
にはPowerMockRunnerを指定します。
@PrepareForTest
には、モック化するクラスを指定します。
@SuppressStaticInitializationFor
にもモック化するクラスを指定するのですが、@SuppressStaticInitializationFor(SampleEm.class)
ではない点に注意が必要です。@RunWith(PowerMockRunner.class) @PrepareForTest(SampleEm.class) @SuppressStaticInitializationFor("jp.co.sample_powermock.staticinitializer.SampleEm") public class SampleEmTest { @Test public void test() throws Exception { // 実行 SampleEm em = new SampleEm(); boolean result = em.judge(); // 結果確認 assertFalse(result); } }テストを実行すると、staticイニシャライザが無効化されることによりフィールドに"value"が設定されないため、このJUnitは成功します。
- 投稿日:2020-09-16T18:15:49+09:00
Visitorパターン
Visitorパターンとは
データ構造と処理を分離する。
データ構造を巡り歩く訪問者を表すクラスを用意し、そのクラスに処理を任せる。
データ構造側は、訪問者を受け入れてやる。Visitor(訪問者)の役
Visitor役はデータ構造の具体的な要素(ConcreteElement役)ごとに「xxxを訪問した」という
visit(xxx)メソッドを宣言する。
visit(xxx)はxxxを処理するためのメソッドで、実際のコードはConcreteVisit役の側に書かれる。package visitor; public abstract class Visitor { public abstract void visit(File file); public abstract void visit(Directory directory); }ConcreteVisitor(具体的訪問者)の役
ConcreteVisitor役はVisitor役のインターフェースを実装する。
visit(xxx)という形のメソッドを実装し、個々のConcreteElement役ごとの処理を記述する。package visitor; import java.util.Iterator; public class ListVisitor extends Visitor{ private String currentDir = ""; @Override public void visit(File file) { System.out.println(currentDir + "/" + file); } public void visit(Directory directory) { System.out.println(currentDir + "/" + directory); String savedDir = currentDir; currentDir = currentDir + "/" + directory.getName(); Iterator<Entry> it = directory.iterator(); while (it.hasNext()) { Entry entry = it.next(); entry.accept(this); } currentDir = savedDir; } }Element(要素)の役
Element役はVisitor役の訪問先を表す役。
訪問者を受け入れるacceptメソッドを宣言する。
acceptメソッドの引数にはVisitor役が渡される。package visitor; public interface Element { public abstract void accept(Visitor v); }ConcreteElement(具体的要素)の役
ConcreteElement役はElement役のインターフェースを実装する役。
package visitor; public class File extends Entry{ private String name; private int size; public File(String name, int size) { this.name = name; this.size = size; } public String getName() { return name; } public int getSize() { return size; } @Override public void accept(Visitor v) { v.visit(this); } }package visitor; import java.util.ArrayList; import java.util.Iterator; public class Directory extends Entry{ private String name; private ArrayList<Entry> directory = new ArrayList<>(); public Directory(String name) { this.name = name; } @Override public String getName() { return name; } @Override public int getSize() { int size = 0; Iterator<Entry> it = directory.iterator(); while (it.hasNext()) { Entry entry = (Entry) it.next(); size += entry.getSize(); } return size; } public Entry add(Entry entry) { directory.add(entry); return this; } public Iterator<Entry> iterator() { return directory.iterator(); } public void accept(Visitor v) { v.visit(this); } }ObjectStructure(オブジェクト構造)の役
ObjectStructure役はElement役の集合を扱う役。
ConcreteVisitor役が個々のElement役を扱えるようなメソッドを備えている。
この役は上記のDirectoryクラスが該当する。呼び出し元
package visitor; public class Main { public static void main(String[] args) { try { System.out.println("Making root entries..."); Directory rootDir = new Directory("root"); Directory binDir = new Directory("bin"); Directory tmpDir = new Directory("tmp"); Directory usrDir = new Directory("usr"); rootDir.add(binDir); rootDir.add(tmpDir); rootDir.add(usrDir); binDir.add(new File("vi", 10000)); binDir.add(new File("latex", 20000)); rootDir.accept(new ListVisitor()); System.out.println(); System.out.println("Making user entryies..."); Directory yuki = new Directory("yuki"); Directory hanako = new Directory("hanako"); Directory tomura = new Directory("tomura"); usrDir.add(yuki); usrDir.add(hanako); usrDir.add(tomura); yuki.add(new File("diary.html", 100)); yuki.add(new File("Composite.java", 200)); hanako.add(new File("memo.tex", 300)); tomura.add(new File("game.doc", 400)); tomura.add(new File("junk.mail", 500)); rootDir.accept(new ListVisitor()); } catch (FileThreatmentException e) { e.printStackTrace(); } } }実行結果
https://github.com/aki0207/visitor
こちらを参考にさせていただきました。
増補改訂版Java言語で学ぶデザインパターン入門
- 投稿日:2020-09-16T13:54:44+09:00
OrientJSとOrientDBの併用方法
このチュートリアルでは、Alibaba Cloud上でOrientDBを設定し、OrientDBと一緒にOrientJSの使い方を探っていきます。
本ブログは英語版からの翻訳です。オリジナルはこちらからご確認いただけます。一部機械翻訳を使用しております。翻訳の間違いがありましたら、ご指摘いただけると幸いです。
前提条件
このチュートリアルは中程度の難易度と言えます。そのため、このチュートリアルでは、いくつかの関連する背景知識が必要となります。また、このチュートリアルを進める前に、いくつかの設定をしておくことも大前提となります。具体的には、以下のものが必要です。
1、Linuxのコマンドラインインターフェースの機能についての一般的な理解。
2、Alibaba Cloud の ECS セキュリティグループの一般的な理解。
3、Java(具体的には1.7以降)がインストールされており、関連する環境変数も設定されていること。
4、JavaScriptの一般的な理解。Alibaba Cloud ECSへのOrientDBのインストール
このチュートリアルの最初のステップとして、Alibaba Cloud Elastic Compute Service (ECS) インスタンスを作成する必要があります。このチュートリアルでは、Ubuntuがインストールされ、ワンコアプロセッサと512MBのメモリを持つECSインスタンスを作成します。次に、SSHを使用するか、Alibaba Cloudコンソールを介してインスタンスにログオンします。その方法については、まだ知らない場合は、このガイドをチェックしてください。
次に、適切なバイナリパッケージをインストールする必要があります。まず、OrientDBの最新の安定版リリースをダウンロードします。あるいは、ウェブサイトから手動でダウンロードするのではなく、以下のコマンドを使って OrientDB 3.0.21 をダウンロードしてみることもできます。
curl https://s3.us-east-2.amazonaws.com/orientdb3/releases/3.0.21/orientdb-3.0.21.tar.gzダウンロードが完了すると、最初に curl コマンドを入力したディレクトリに
orientdb-3.0.21.tar.gz
という名前の zip ファイルが存在します。その後、zip ファイルの内容を展開し、環境変数ORIENTDB_HOME
の下の適切なディレクトリに移動します。現在のバージョンに応じた対応するコマンドは以下の通りです。
tar -xvzf orientdb-3.0.21.tar.gz
: フォルダを解凍します。cp -r orientdb-3.0.21 /opt
: フォルダ全体を/optディレクトリにコピーするために使用します。/etc/environment
の内容は以下のようにします。JAVA_HOME=/usr/lib/jvm/java-8-oracle ORIENTDB_HOME=/opt/orientdb-3.0.21 PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games :$ORIENTDB_HOME/bin"このチュートリアルの前提条件であるJava 1.7以降がインストールされていること、およびUbuntuでインストールされたインスタンスにスワップ領域が追加されていること、つまり、新しいインスタンスサーバーであり、まだインストールされていない場合です。
注: OrientDB を更新した後、必要であれば、このファイルをソースにして、新しい OrientDB の実行ファイルがターミナルで利用できるようにする必要があります。これに使用するコマンドは次のとおりです: source /etc/environment.
ここで、
ORIENTDB_DIR
の代わりにORIENTDB_HOME
の OrientDB ディレクトリの場所(もちろんORIENTDB_HOME
)と、USER_YOU_WANT_ORIENTDB_RUN_WITH
の代わりに使用したいシステムユーザを入力して、ORIENTDB_HOME/bin
にあるorientdb.sh
ファイルを編集する必要があります。OrientDBのインストールが完全に機能している状態で、以下のコマンドでOirentDBサーバを制御することができます。
orientdb.sh status
: サーバが稼働しているかどうかをチェックするために使用します。orientdb.sh start
: OrientDB サーバを起動するために使用します。orientdb.sh stop
: OrientDB をシャットダウンするために使用します。ほとんどの場合、本番環境では非常に安全なインストールが必要です。つまり、どのユーザーも自分の意思でデータベースを起動したり停止したりする権限を持たないような、安全なOrientDBのインストールが必要になります。そのため、
OrientDB bin/orientdb.sh
ファイルでは、USER_YOU_WANT_ORIENTDB_RUN_WITH
の代わりに管理ユーザーを入力することができます。そうすることで、管理者としてOriendDBの最も賢明なコマンドの完全な権利を持つ唯一のユーザーになることを意味します。この種のことをもっと知りたい方は、OrientDBのドキュメントを見てください。
さて、これでこれらのことはすべて完了しましたので、次に進みましょう。
orientdb.sh start
コマンドを実行してインストールをテストすることができます。次のスクリーンショットに示すように、ポータル、特にOrientDB Studioには、http://our_ecs_ip:2480
またはhttp://localhost:2480
のいずれかのアドレスからアクセスすることができます。OrientDB に接続してダッシュボードにアクセスするためには、ここで説明したように
$ORIENTDB_HOME/config/oritdenb-server-config.xml
ファイルの最後にユーザーを定義する必要があります。次に、2480番ポート(OrientDB Studioのポート)にインスタンスセキュリティグループを設定することを忘れないでください。
注: 外部からアクセスできるように設定する必要があります。
以下は、テスト用インスタンスの設定の出力です。
OrientJsの設定
OrientDBのOrientJSモジュールは、JavaScriptプロジェクトのための公式のOrientDBドライバとして記述することができます。これは、NodeJSの開発者の間で広く使われています。もちろん、他のパッケージと同様に、node package managerを使ってインストールするには、たった一つのコマンドが必要です。具体的には、ローカルにインストールするには、
npm install orientjs
コマンドを実行します。そして、OrientJSがインストールされて初期化されると、以下のようなことができるようになります。
OrientJSの初期化
OrientJSとOrientDBを相互に連携させるための最初のステップは、サーバーAPIを初期化することです。これを行うことは、OreintJSがOrientDBのサーバーAPIと対話できるようにするために重要です。なぜなら、OrientDBサーバーのホストとそのポートにデータベースユーザーが接続されている必要があるからです。
// Initializing the Server API var server = OrientDB({ host: 'localhost', port: 2424, username: 'admin', password: 'admin' });注: この場合、ユーザー資格情報には
admin:admin
を使用しています。しかし、これはOrientDB設定ファイルに設定した対応する資格情報に変更する必要があります。データベースのリスト
このチュートリアルの次のステップは、OrientJSを使って単一のクエリを実行して、ここまでに作成したすべてのデータベースを一覧表示することです。これに続いて、通常はDBオブジェクトを返すように、各データベースの名前とタイプを表示しています。
// Databases listing server.list() .then(list => { console.log(list.length + ' databases created so far'); list.forEach(db => { console.log(db.name + ' - ' + db.type); }); });データベースの作成
それでは、サーバーAPIからデータベースを作成する作業に移りましょう。これは比較的簡単です。この操作は、先ほど作成したデータベースオブジェクトとの約束を返す単一のコマンドでも行うことができます。
以下は、Create関数に関連するOrientJsの型の内容です。
/** * Create a database with the given name / config. * * @param config The database name or configuration object. * @promise {Db} The database instance */ create(name: string | DbConfig): Promise<Db>;この関数にコンフィギュレーション・オブジェクトまたは単にデータベース名を提供することで作成操作が完了することが明記されています。しかし、以下に示す2つ目のケースでは、デフォルト値は欠落しているフィールドのために選択されることになります。ここでは、設定オブジェクトを使ってデータベースを作成する方法を説明します。
// Creating a database server.create({ name: 'NewDatabase', type: 'graph', storage: 'plocal', }).then(dbCreated => { console.log('Database ' + dbCreated.name + ' created successfully'); });既存のデータベースを使用
データベースが作成された後は、後からインスタンスを取得して、より多くの操作を行うことができます。データベースのインスタンスを初期化するには、以下のメソッドを使用します。
var db = server.use('NewDatabase');バージョン2.1.11からは、ODatabaseクラスを使ってServer APIを初期化し、すぐにデータベースに接続することも可能になりました。そのための構文は以下の通りです。
var ODatabase = require('orientjs').ODatabase; var db = new ODatabase({ host: 'localhost', port: 2424, username: 'admin', password: 'admin', name: 'NewDatabase' }); console.log('Connected to: ' + db.name);レコードAPI
データベースインスタンスが初期化されると、保存されたレコード、つまりデータベースに保存された情報を、データベースのレコードID(RID)を使用して取得したり操作したりすることができます。
注意: レコード ID は一意の値なので、一般的な SQL ベースのリレーショナル・データベースのように、主キーを参照するフィールドをもう 1 つ作成する必要はありません。
レコードIDの構文は以下の通りです。
#<cluster>:<position>
となります。このコードの場合
cluster
:クラスタ識別子として機能します。これはクラスタが属するクラスタレコードを直接参照します。このパラメータの値は、正の値は永続的なレコードを示し、負の値は一時的なレコードを示します。position
:クラスタへのレコードの絶対位置を指定します。 ここでは、レコードのRID
を指定して 1 つのレコードを取得してみましょう。db.record.get('#1:1') .then( function(article) { console.log('Loaded article:', article); } );レコードを取得したので、いくつかの操作について説明します。まず、削除操作です。一般的には、レコードの削除は比較的簡単で、以下のコードで行うことができます。
db.record.delete('#1:1');次に、更新操作です。レコードの更新は少し複雑ですが、それでも私の中では問題ありません。更新したい対応するデータが読み込まれた後に行うことができます。以下に、更新関数の実装方法を示します。
db.record.get('#1:1') .then(function(article) { article.title = 'New Title'; db.record.update(article) .then(function() { console.log("Article updated successfully"); }); });注意:このコードを使用する際には、以下のことを考慮してください。
- The an asterisk (#) prefix is required to recognize a Record ID. - When creating a new record, OrientDB selects the cluster to store it using a configurable strategy, which can be the default strategy, the round-robin one, or a balanced or local strategy. - Also, note that, in our example, #1:1 represents the RID.クラスAPI
データベースの派生オブジェクトは、クラスにアクセスしたり、作成したり、操作したりするために特別に使用されます。具体的には、"クラス "と言うと
db.class
のことを指します。例えば、ここにクラスを作成するためのメソッドがあります。// Creating a new class(Article) using the Class API var Article = db.class.create('Article');既存のクラスを取得するには、以下のようにします。
var Article = db.class.get('Article');これらはすべてプロミスを返していることに注意しましょう。プロミスが解決したら、さらにアクションを実行することを意識したスタイルになります。現在接続しているデータベースに保存されているすべてのクラスのリストを返すには、次のコードを適用します。
// List all the database classes db.class.list() .then( function(classes){ console.log(classes.length + ' existing classes into ' + db.name); classes.forEach(cl => { console.log(cl.name); }); } );次に、作成操作があります。クラスを作成することは、データベース構造を完全に設計する前に知っておいた方が良いことです。私たちは、プロパティを操作する前に作業するクラスを正しくロードしなければなりません。
Articleのクラスのプロパティのリストは次のようになります。
db.class.get('Article').then(function(Article) { Article.property.list() .then( function(properties) { console.log(Article.name + ' has the properties: ', properties); } ); });プロパティの作成は、ほぼ同じ構文で行われます。
db.class.get('Article').then(function(Article) { Article.property.create([{ name: 'title', type: 'String' },{ name: 'content', type: 'String' }]).then( function(properties) { console.log("Successfully created properties"); } ); });クラスには1つのプロパティを設定するだけです。多くのプロパティを設定する必要はありません。では、いくつかのアクションを実行してみましょう。
まず、プロパティを名前で削除してみましょう。
db.class.get('Article').then(function(Article) { Article.property.drop('peroperty_to_drop').then(function(){ console.log('Property deleted successfully.'); }); });続いて、プロパティ名を変更してみましょう。
db.class.get('Article').then(function(Article) { Article.property.rename('old_name', 'new_name').then(function(p) { console.log('Property renamed successfully'); }); });Class API の詳細については、こちらのドキュメントを参照してください。
OrientDB でのクエリ
クエリは、データをより良く管理するために、データベースエンジンが提供する最も重要な操作の一つであり、OrientDBでは2つの方法のいずれかでクエリを実行することができます。直接SQLリクエストを発行するか、Query Builderを使用してNodeJsで暗黙的にクエリを構築するかのどちらかです。
// Find articles viewed 200 times var numberViews = 200; db.query( 'SELECT title, content FROM Article ' + 'WHERE number_views = :numberViews, { params: { numberViews: numberViews, } } ).then(function(articles) { console.log(articles); });上のクエリでは、200回閲覧された記事を探しています。このクエリは比較的簡単に実行できます。この可能性を利用してエンジンに命令を出す方法は、AND, OR, LIKEなどの演算子を使って、より面白いSQL構文を使うことができます。リクエストのサブストリングとパラメータを連結してSQL文字列を完全に構築するのではなく、パラメトリック化されたリクエストを使用するこの可能性(より簡単)。OrientDBのSQL構文についての詳細はこちらを参照してください。
SQL クエリを完全に記述する代わりに、代わりに Query Builder を使用することができます。クエリビルダは、データベースAPIアクションを通じて内部的にクエリを実行している特定のメソッドを呼び出すことができるように機能します。ここでは、SQL で行ったのと同じクエリを Query Builder で実行しています。
var numberViews = 200; var query = db.select('title, content').from('Article') .where({ "number_views": numberViews }) .all();イベント情報
OrientDBでは、イベントはコールバックメソッドとして機能し、クエリの終了時や開始時に実行することができます。イベントは、クエリのデバッグや、ログの記録、プロファイリング、データを調整するための特別なタスクの実行に便利です。イベントはデータベースに依存します。つまり、各イベントは単一のデータベースにアタッチされ、その作成には Database API を使用する必要があります。このAPIを使用する場合は、
db.on()
関数を使用します。以下の例では、BeginQuery
イベントを使用して、OrientDBサーバに送信された全てのクエリをログに記録しています。(クエリの終了にはendQuery
を使用することもできます)。db.on("beginQuery", function(queryObj) { console.log('DEBUG: ', queryObj); });結論
このチュートリアルでは、Alibaba Cloud ECSインスタンス上でOrientDBを設定する方法を見てきましたが、OrientDBと一緒にOrientJSを使用する方法も探ってきました。
アリババクラウドは日本に2つのデータセンターを有し、世界で60を超えるアベラビリティーゾーンを有するアジア太平洋地域No.1(2019ガートナー)のクラウドインフラ事業者です。
アリババクラウドの詳細は、こちらからご覧ください。
アリババクラウドジャパン公式ページ
- 投稿日:2020-09-16T11:34:13+09:00
private public について
アクセス修飾子ってなに?とりあえずつけとこ。という程度の理解しかなかったのですが、なぜ存在しているのかを学ぶことができたので自分の復習のためにかいときます。
publicとprivateの違い
アクセス修飾子が必要な理由
・外部からアクセスされてはまずい変数やメソッドへのアクセスを遮断できる
わかる
・保守を容易にする
例 メソッドの修正が必要となる
↓
publicを使っているものがたくさんあることにより、アクセスできる機能がたくさんでてくる
↓
アクセスできる機能すべてが正常に動いているか確認しなければならない(修正により元の機能が失われていないか確認が必要)
↓
そうならないためにも必要不可欠なデータ以外はprivateに設定してアクセスできる範囲を絞っておく他にも様々な理由があると思うのですが私が理解した範囲をかかせて頂きました。
- 投稿日:2020-09-16T06:25:22+09:00
Java の org.w3c.dom.Document オブジェクトと XML 文字列を変換する
サンプルコード
MyApp.java というファイル名で以下のサンプルコードを保存する。
import org.w3c.dom.Document; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.StringReader; import java.nio.charset.StandardCharsets; /** * XML 文字列と Document オブジェクトの変換サンプルコード (文字エンコーディングは UTF-8 固定)。 */ public class MyApp { /** * XML 文字列を Document オブジェクトに変換します。 * @param xml XML 文字列 * @return Document オブジェクト * @throws ParserConfigurationException * @throws SAXException * @throws IOException */ public static Document toDocument(String xml) throws ParserConfigurationException, SAXException, IOException { try (StringReader reader = new StringReader(xml)) { InputSource source = new InputSource(reader); DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); return builder.parse(source); } } /** * Document オブジェクトを XML 文字列に変換します。 * @param doc Document オブジェクト * @return XML 文字列 * @throws IOException * @throws TransformerException */ public static String toString(Document doc) throws IOException, TransformerException { try (ByteArrayOutputStream output = new ByteArrayOutputStream()) { TransformerFactory factory = TransformerFactory.newInstance(); Transformer transformer = factory.newTransformer(); // 指定しなくてもデフォルトは UTF-8 だったりする transformer.setOutputProperty(OutputKeys.ENCODING, StandardCharsets.UTF_8.name()); DOMSource source = new DOMSource(doc); StreamResult result = new StreamResult(output); transformer.transform(source, result); return output.toString(StandardCharsets.UTF_8); } } // 動作確認用メソッド public static void main(String[] args) throws IOException, SAXException, ParserConfigurationException, TransformerException, XPathExpressionException { // 動作確認用の XML 文字列を用意 // Java 15 から使える Text Blocks 機能による文字列リテラルを利用 String xml = """ <?xml version="1.0" encoding="UTF-8"?> <feed xml:lang="ja-JP" xmlns="http://www.w3.org/2005/Atom"> <id>helloworldfeed</id> <author>niwasawa</author> <title>Hello World フィード</title> <updated>2000-08-06T00:00:00+09:00</updated> <entry> <id>helloworldfeed:helloworld1</id> <title>Hello World こんにちは世界</title> <content>Hello World こんにちは世界</content> <updated>2000-08-06T00:00:00+09:00</updated> </entry> </feed> """; // XML 文字列を Document オブジェクトに変換 System.out.println("***** XML 文字列を Document オブジェクトに変換 *****"); Document doc = toDocument(xml); System.out.println("タイトル: " + XPathFactory.newInstance().newXPath().evaluate("//title", doc, XPathConstants.STRING)); System.out.println(); // Document オブジェクトを XML 文字列に変換 System.out.println("***** Document オブジェクトを XML 文字列に変換 *****"); doc.setXmlStandalone(true); String outputXml = toString(doc); System.out.println(outputXml); System.out.println(); } }サンプルの実行結果
実行環境: Java 15 (Oracle JDK) + macOS Catalina
$ java MyApp.java ***** XML 文字列を Document オブジェクトに変換 ***** タイトル: Hello World フィード ***** Document オブジェクトを XML 文字列に変換 ***** <?xml version="1.0" encoding="UTF-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ja-JP"> <id>helloworldfeed</id> <author>niwasawa</author> <title>Hello World フィード</title> <updated>2000-08-06T00:00:00+09:00</updated> <entry> <id>helloworldfeed:helloworld1</id> <title>Hello World こんにちは世界</title> <content>Hello World こんにちは世界</content> <updated>2000-08-06T00:00:00+09:00</updated> </entry> </feed>参考資料
- 投稿日:2020-09-16T03:42:29+09:00
ローカル(ホストOS)のJavaプログラムからDockerコンテナ上のMySQLにアクセスする
はじめに
自分の技術スタックがあまりにもレガシーで情けなく感じ
レガシーおじさんを脱却し、技術者として再出発したく
勉強を始めました。宜しくお願いします?ということでまずはDockerを勉強することに。
構築するもの(今回のゴール)
ソフトウェア情報
OS:Windows10
Docker:19.03.12
Program:Java11
MySQL:8.0.21
Adminer:latest
WebBrowser:なんでもとりあえず今回はホストOS上の自前のJavaプログラムから
コンテナ上のDBにアクセスするところからチャレンジ。構築作業
1. Dockerコンテナ作成
DockerHubのMySQLの説明ページにあるdocker-compose.ymlをちょっとアレンジして準備。
DockerHub MySQLページ# Use root/example as user/password credentials version: '3.1' services: db: image: mysql:8.0.21 #変更 command: --default-authentication-plugin=mysql_native_password restart: always environment: MYSQL_ROOT_PASSWORD: root MYSQL_DATABASE: hoge #追加 MYSQL_USER: hoge #追加 MYSQL_PASSWORD: hoge #追加 ports: #追加 - 3306:3306 #追加 adminer: image: adminer:latest restart: always ports: - 8080:8080#が付いてるところがアレンジ部分。
MySQLイメージはlatestを指定するとバージョンがころころ変わりそうな気がしたので8.0.21を指定。
今回はコンテナ外部からアクセスするため、
適当なDBの追加とポート3306を外部公開するように設定。上記設定ファイルと同階層のフォルダで
docker-composeコマンドで起動。docker-compose upフォアグラウンド実行なのでずらずらログが出るのを見つつ、
別コンソールで立ち上がってるか確認docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 0c5d267f22ee mysql:8.0.21 "docker-entrypoint.s…" 26 seconds ago Up 25 seconds 0.0.0.0:3306->3306/tcp, 33060/tcp mysql_db_1 258f5885810d adminer:latest "entrypoint.sh docke…" 26 seconds ago Up 25 seconds 0.0.0.0:8080->8080/tcp mysql_adminer_1(´・ω・`)おぉー
2. Adminerでテーブル、データ作成
AdminerとはPHPで作られたDB操作できるWebクライアントらしい。
MySQL、Adminerのコンテナが立ち上がってる状態で
http://localhost:8080/
にアクセスすると以下の画面が出るので
さっきのdocker-compose.ymlに記載したDB、ユーザ情報を入れる。
3. Javaプログラム作成
まずgradleにMySQLドライバの依存関係を記載。
apply plugin: 'java' apply plugin: 'application' apply plugin: 'eclipse' repositories { mavenCentral()} dependencies { compile group: 'mysql', name: 'mysql-connector-java', version: '8.0.21' testImplementation 'junit:junit:4.12' }そしてMySQLにSQLクエリを投げて結果を表示するクラスを作成。
public class DockerMySQLAccessor { public static void main(String[] args) { System.out.println("DockerコンテナのMySQLにアクセスするよ"); try(Connection con = DriverManager.getConnection( "jdbc:mysql://localhost:3306/hoge?useSSL=false", "hoge", // UserId "hoge" // Password )) { PreparedStatement pstmt = con.prepareStatement("select * from TEST_TBL"); ResultSet rs = pstmt.executeQuery(); while (rs.next()) { System.out.printf("ID:%d, HOGE:%s \n", rs.getInt("ID"), rs.getString("HOGE")); } } catch (SQLException e) { e.printStackTrace(); } } }4. 実行
EclipseからさっきのJavaコードを実行。
さっき入れたレコードが取得できてる!
やったぜ。(´・ω・`)vまとめ
とりあえずDockerを使って手軽に仮想的なDBサーバを立ち上げ、
ローカルのプログラムからアクセスすることができた。今回はDocker触りということで
設定ほぼ丸写しでしかもいきなりdocker-composeの方を使ったけど
実際の運用ではコンテナ毎にDockerfile作ってイメージを作っていくのかな?
あと、プログラムもコンテナ上で実行し、コンテナ間で通信したいところ。
ここら辺はまた今度。謝辞
Win10にDockerを入れるの大いに参考にさせて頂きました。感謝<(_ _)>
レガシーエンジニアによるDocker入門
- 投稿日:2020-09-16T01:42:08+09:00
Eclipse 画面レイアウト変更方法 (Java編)
画面レイアウト変更方法
参考動画
【Eclipse入門】初心者はまずココをイジれ!「Java編」
https://www.youtube.com/watch?v=5p_3OudszfA
- 投稿日:2020-09-16T01:20:53+09:00
JDK 11 ドキュメント Java 初学者向け
JDK11 の公式ドキュメントです? (All English)