- 投稿日:2019-07-11T19:32:56+09:00
【初心者】Javaの基礎知識で対戦ゲームを作成
1. はじめに
1.モチベーション
「Javaの基礎(というか、オブジェクト指向)がわかれば対戦ゲームが作れる!」と気づいたので作成しました。
「何を作ればいいかわからないから、学習のモチベーションがわかない」と考えている方に是非見ていただきたいです!!
※「スッキリわかるJava入門 第2版」を参考にして作成しました。2.アウトプット
1.ゲームルール
ドラゴン同士が戦うゲーム。
最初に、自分と敵のドラゴンを選択して生成。<選択・生成フェーズ>
互いに技を出し、HPが0になると終了。<バトルフェーズ>
※詳細は下記のゲームルールで記載。2.オブジェクト指向との関係
1.選択したドラゴンを設計図(=クラス)を用いて自分と敵とで生成する=オブジェクト指向のインスタンス化
2.技を使用した結果(HPの減少)はオブジェクト内の値を参照・更新する=getterとsetterの使用2. 内容
1.はじめに
1.ゲームルール
・選択・生成フェーズとバトルフェーズで、それぞれドラゴンと使う技をユーザ選択により決定する。
・ドラゴンを自分と敵とで1体づつ選択する<選択・生成フェーズ>
・ドラゴンは名前・HP・技が違う3体を用意
・技は1体のドラゴンにつき3つ持つ。
・ドラゴンに技を命令しバトルする<バトルフェーズ>
・技は自分→相手の順番で出す。
・自分のドラゴンは選択した技を、相手のドラゴンはドラゴンの持つ技をランダムで1つ繰り出す。
・技を出し相手のHPを減らした段階で相手のHPが0かどうかの判定を行い、0なら攻撃した側の勝ちとなる。2.フォルダ構成
├── DragonMain.java
├── bean
│ ├── ButtleDragon.java
│ ├── Move.java
│ └── SimpleDragon.java
└── util
├── buttle
│ ├── ButtleContents.java
│ ├── ButtleMain.java
│ └── RandomEnemyChoice.java
└── choice
└── ChoiceDragon.javabeanフォルダ内のクラスを使用してドラゴンをインスタンス化(生成)する。
選択・生成フェーズでの
「選択」段階では、SimpleDragon.javaを
「生成」段階では、ButtleDragon.javaとMove.javaを使用。2.全体処理
↓mainメソッド
DragonMain.javapackage dragon; import java.io.BufferedReader; import java.io.InputStreamReader; import dragon.bean.ButtleDragon; import dragon.util.buttle.ButtleMain; import dragon.util.choice.ChoiceDragon; public class DragonMain{ public static void main(String[] args)throws Exception { System.out.println("ドラゴンのバトルを始めます"); BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); try{ //ドラゴン一覧を取得する ChoiceDragon.searchDrageon(); //どのドラゴンを作成するかを選択する String choiceMyDragon = null; String choiceOpponentDragon = null; System.out.print("自分が使用するドラゴンをidで選んでください>"); choiceMyDragon = br.readLine(); System.out.print("相手に使用させるドラゴンをidで選んでください>"); choiceOpponentDragon = br.readLine(); //ドラゴン生成 ButtleDragon myDragon = ChoiceDragon.makeDragon(Integer.parseInt(choiceMyDragon)); ButtleDragon oppoDragon = ChoiceDragon.makeDragon(Integer.parseInt(choiceOpponentDragon)); //Buttle ButtleMain.doButtle(myDragon,oppoDragon); }catch(Exception e){ System.out.println("深刻なエラーが出ました"); } } }
ChoiceDragon.searchDrageon();:ドラゴン一覧を取得
ChoiceDragon.makeDragon());:自分と敵のドラゴンを生成しそれぞれ「myDragon」「oppoDragon」に格納
ButtleMain.doButtle();:「myDragon」と「oppoDragon」を引数にしてバトルスタート3.選択・生成フェーズ
ドラゴン一覧を取得し、選択されたドラゴンを生成・ドラゴンに技を紐付ける
・クラス(Bean)
↓シンプルドラゴンを生成するために使用。
技を持たない、選択時にIDとドラゴン名の一覧を表示するときに使用SimpleDragon.javapackage dragon.bean; public class SimpleDragon { int dragonId; String dragonName; int hitPoint; //シンプルドラゴンのコンストラクタ public SimpleDragon(int dragonId,String dragonName, int hitPoint){ this.dragonId = dragonId; this.dragonName = dragonName; this.hitPoint = hitPoint; } public int getDragonId() { return dragonId; } public void setDragonId(int dragonId) { this.dragonId = dragonId; } public String getDragonName() { return dragonName; } public void setDragonName(String dragonName) { this.dragonName = dragonName; } public int getHitPoint() { return hitPoint; } public void setHitPoint(int hitPoint) { this.hitPoint = hitPoint; } }↓バトルドラゴンを作成するために使用。
シンプルドラゴンクラスを継承し、バトル中に参照するHPと技を持たせる。ButtleDragon.javapackage dragon.bean; import java.util.Map; /** * * バトル中に使用するドラゴンクラス * HPの増減に使用する */ public class ButtleDragon extends SimpleDragon { int buttleHp; int move1; int move2; int move3; Map<Integer, Move> moves; /** * バトル用ドラゴンのコンストラクタ。バトル用HPの初期値はHPとする * @param dragonId * @param dragonName * @param hitPoint */ public ButtleDragon(int dragonId, String dragonName, int hitPoint) { super(dragonId,dragonName,hitPoint); this.buttleHp = hitPoint; } public int getButtleHp() { return buttleHp; } public void setButtleHp(int buttleHp) { this.buttleHp = buttleHp; } public int getMove1() { return move1; } public void setMove1(int move1) { this.move1 = move1; } public int getMove2() { return move2; } public void setMove2(int move2) { this.move2 = move2; } public int getMove3() { return move3; } public void setMove3(int move3) { this.move3 = move3; } public Map<Integer, Move> getMoves() { return moves; } public void setMoves(Map<Integer, Move> moves) { this.moves = moves; } }↓技を作成するために使用。
Move.javapackage dragon.bean; /* * バトル中に使用する技クラス */ public class Move { int moveId; String moveName; int power; int movePoint; int buttleMovePoint; /** * 技のコンストラクタ。 * 戦闘中のMPは[buttleMovePoint]を使用して増減させる * * @param moveName * @param power * @param movePoint */ public Move(int moveId,String moveName, int power, int movePoint) { this.moveId = moveId; this.moveName = moveName; this.power = power; this.movePoint = movePoint; this.buttleMovePoint = movePoint; } public int getMoveId() { return moveId; } public void setMoveId(int moveId) { this.moveId = moveId; } public String getMoveName() { return moveName; } public void setMoveName(String moveName) { this.moveName = moveName; } public int getPower() { return power; } public void setPower(int power) { this.power = power; } public int getMovePoint() { return movePoint; } public void setMovePoint(int movePoint) { this.movePoint = movePoint; } public int getButtleMovePoint() { return buttleMovePoint; } public void setButtleMovePoint(int buttleMovePoint) { this.buttleMovePoint = buttleMovePoint; } }・ChoiceDragon
↓ドラゴンを選択するためのリストの取得や、選択されたドラゴンの生成を行う。生成した後のドラゴンに技を持たせるのもここで行う。ButtleDragon.javapackage dragon.util.choice; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import dragon.bean.ButtleDragon; import dragon.bean.Move; import dragon.bean.SimpleDragon; public class ChoiceDragon { /** * ドラゴンを選択する * ※この部分をDBから取得すると良いかもしれません * @throws Exception */ public static void searchDrageon(){ //ここで選択できるドラゴンを作成する SimpleDragon dragon1 = new SimpleDragon(1,"ホワイトドラゴン", 20); SimpleDragon dragon2 = new SimpleDragon(2,"ブルードラゴン", 25); SimpleDragon dragon3 = new SimpleDragon(3,"レッドドラゴン", 15); //作成したドラゴンをリストにつめる List<SimpleDragon> choiceDragonList = new ArrayList<SimpleDragon>(); choiceDragonList.add(dragon1); choiceDragonList.add(dragon2); choiceDragonList.add(dragon3); //リストを表示する System.out.println("ID:\tドラゴン名"); for(SimpleDragon list : choiceDragonList){ System.out.println(list.getDragonId()+":\t"+list.getDragonName()); } } /** * 選択された値を元にして、リストからドラゴンを生み出す * その後、技を持たせる */ public static ButtleDragon makeDragon(int DragonId){ //ドラゴンを生み出す ButtleDragon buttleDragon = makeButtleDragon(DragonId); //技リストを取得する Map<Integer, Move> buttleMoveMap = makeButtleMove() ; //技をドラゴンに持たせる Map<Integer, Move> buttleDragonMoveMap = new HashMap<>(); //ドラゴンが持つ技のidを取得する int moveId_1 = buttleDragon.getMove1(); int moveId_2 = buttleDragon.getMove2(); int moveId_3 = buttleDragon.getMove3(); //ドラゴンが持つ技を技リストから取得する Move move1 = buttleMoveMap.get(moveId_1); Move move2 = buttleMoveMap.get(moveId_2); Move move3 = buttleMoveMap.get(moveId_3); //ドラゴンと技を結びつける buttleDragonMoveMap.put(1, move1); buttleDragonMoveMap.put(2, move2); buttleDragonMoveMap.put(3, move3); buttleDragon.setMoves(buttleDragonMoveMap); return buttleDragon; } /** * ドラゴンを生成し、技リストのidをそれぞれに付与する。 * ※ここでDBを使用すると良いと思います。 * @param dragonId * @return */ private static ButtleDragon makeButtleDragon(int dragonId) { ButtleDragon makeDragon = null; //引数によって異なるドラゴンを生み出す switch(dragonId) { case 1: //バトルドラゴンのコンストラクタへの引数はID・ドラゴンの名前・HP ButtleDragon dragon1 = new ButtleDragon(1,"ホワイトドラゴン", 20); //バトルドラゴンに技をセットする dragon1.setMove1(1); dragon1.setMove2(2); dragon1.setMove3(5); makeDragon = dragon1; break; case 2: ButtleDragon dragon2 = new ButtleDragon(2,"ブルードラゴン", 25); dragon2.setMove1(1); dragon2.setMove2(3); dragon2.setMove3(5); makeDragon = dragon2; break; case 3: ButtleDragon dragon3 = new ButtleDragon(3,"レッドドラゴン", 15); dragon3.setMove1(1); dragon3.setMove2(4); dragon3.setMove3(5); makeDragon = dragon3; break; } return makeDragon; } /** * 技リストを取得する。 * ※ここでDBを使用すると良いと思います。 * @return */ private static Map<Integer, Move> makeButtleMove() { //技リスト一覧を宣言する Move move1 = new Move(1,"アタック\t", 2, 20); Move move2 = new Move(2,"ホワイトブレス", 4, 2); Move move3 = new Move(3,"ブルーブレス", 3, 2); Move move4 = new Move(4,"レッドブレス", 5, 2); Move move5 = new Move(5,"つよいアタック", 6, 1); //技リストをマップにつめる Map<Integer, Move> moveList = new HashMap<>(); moveList.put(1, move1); moveList.put(2, move2); moveList.put(3, move3); moveList.put(4, move4); moveList.put(5, move5); return moveList; } }1.ドラゴン一覧の取得
ChoiceDragon.searchDrageonメソッド内で行う。
SimpleDragon dragon1 = new SimpleDragon()でそれぞれドラゴンを生成。
SimpleDragon型のドラゴンをコンストラクタを利用して生成し、id・名前・HPをそれぞれ格納
choiceDragonListで生成したドラゴンをリストに格納して全て表示する2.バトル用のドラゴンの生成
ChoiceDragon.makeDragonメソッド内で行う。
1:バトル用のドラゴンの生成
ButtleDragon(SimpleDragonに、使用する技のidとバトル用のHP(攻撃を受けると減少する)を追加したクラス)から生成される
2:技リスト一覧の生成
Moveとしてid・技名・威力・MPを生成し、idとMoveを紐付けた「技リスト一覧」マップを生成
3:生成したドラゴンと技を結びつける
ドラゴンには使用する技のidが降られているので、それに合致する技を技リスト一覧から取得して格納敵のドラゴンでも同じ内容を実施することで、「技を持つドラゴン」が2体生成される
4.バトルフェーズ
↓バトルのメインメソッド。自分のターンと相手のターンを、どちらかのHPがなくなるまで続ける。
ButtleMain.javapackage dragon.util.buttle; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import dragon.bean.ButtleDragon; public class ButtleMain { /** * Buttleの基本的な流れ * @throws IOException */ public static void doButtle(ButtleDragon myDragon, ButtleDragon oppoDragon) throws IOException{ boolean enemyDownFlg = false; //敵が倒れたかどうかの判定 BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); System.out.println("ドラゴンバトルをスタートします。"); do{ ButtleContents.outputMoveList(myDragon); String str = null; str = br.readLine(); System.out.println("こちらの攻撃!"); ButtleContents.useMove(myDragon.getMoves().get(Integer.parseInt(str)), myDragon, oppoDragon); if(oppoDragon.getButtleHp() == 0){ enemyDownFlg = true; break; } System.out.println("相手の攻撃!"); RandomEnemyChoice.randomChoice(oppoDragon,myDragon); }while(myDragon.getButtleHp() != 0); ButtleContents.outputResult(enemyDownFlg); System.out.println("バトルが終了しました"); } }↓技を出したときの流れ。
テキストを表示し、敵のHPを減らし、自分の技のMPを減らす。ButtleContents.javapackage dragon.util.buttle; import dragon.bean.ButtleDragon; import dragon.bean.Move; public class ButtleContents { /** * 基本的な技の流れ * @param offenceMove:攻撃側の技 * @param offenceDragon:攻撃側のドラゴン * @param defenceDragon:防御側のドラゴン */ public static void useMove(Move offenceMove,ButtleDragon offenceDragon, ButtleDragon defenceDragon){ int nokoriMP = offenceMove.getMovePoint(); //現在のMP //攻撃技の表示 String moveName = offenceMove.getMoveName().replaceAll("\t", "");//技名に含まれているタブ区切りを解除する System.out.println(offenceDragon.getDragonName()+"の"+moveName+"!!"); //攻撃技 Attack(offenceMove,offenceDragon,defenceDragon); //MPの減少 nokoriMP--; offenceMove.setButtleMovePoint(nokoriMP); } /** * 攻撃技の流れ * @param offenceMove * @param offenceDragon * @param defenceDragon */ public static void Attack(Move offenceMove,ButtleDragon offenceDragon, ButtleDragon defenceDragon){ int damage = offenceMove.getPower(); //技の威力 int defenceDragonNokoriHp = 0; //buttleで更新する防御側ドラゴンのHP量 //相手の残りHPの計算 defenceDragonNokoriHp = defenceDragon.getButtleHp() - damage; if(defenceDragonNokoriHp <= 0){ defenceDragon.setButtleHp(0); }else{ defenceDragon.setButtleHp(defenceDragonNokoriHp); } System.out.println(defenceDragon.getDragonName()+"は"+damage+"のダメージで残り体力が"+defenceDragon.getButtleHp()+"になった!"); } /** * 技リストを表示する * @param myDragon */ public static void outputMoveList(ButtleDragon myDragon){ System.out.println("\nコマンド\t\t技名\t\t\t\t残りポイント"); System.out.println("\t1:\t\t"+myDragon.getMoves().get(1).getMoveName()+"\t\t"+myDragon.getMoves().get(1).getButtleMovePoint() ); System.out.println("\t2:\t\t"+myDragon.getMoves().get(2).getMoveName()+"\t\t"+myDragon.getMoves().get(2).getButtleMovePoint() ); System.out.println("\t3:\t\t"+myDragon.getMoves().get(3).getMoveName()+"\t\t"+myDragon.getMoves().get(3).getButtleMovePoint() ); System.out.print("技を選んでください>"); } /** * 勝敗結果を表示する * @param enemyDownFlg */ public static void outputResult(boolean enemyDownFlg){ if(enemyDownFlg){ System.out.println("\n勝ちました!"); }else{ System.out.println("\n負けました‥"); } } }↓敵の繰り出す技をランダムに決めて、技を繰り出す処理
RandomEnemyChoice.javapackage dragon.util.buttle; import dragon.bean.ButtleDragon; /** * 敵側のランダムな動きを指定するクラス * */ public class RandomEnemyChoice { /** * ランダムに技を生成し、実行する * @param oppoDragon * @param myDragon */ public static void randomChoice(ButtleDragon oppoDragon, ButtleDragon myDragon){ //ランダムに繰り出す技を選択する int randomChoice = 0; randomChoice = (int)(Math.random()*3 + 1); //技を繰り出す ButtleContents.useMove(oppoDragon.getMoves().get(randomChoice),oppoDragon, myDragon); } }1.処理の流れ(ButtleMain.java)
敵が倒れる(oppoDragon.getButtleHp() == 0)か、自分が倒れる(myDragon.getButtleHp() == 0)までバトルを続ける。
自分の攻撃はButtleContents.useMoveメソッドに入力値を渡して、敵の攻撃はRandomEnemyChoice.randomChoiceメソッド内のButtleContents.useMoveメソッドにランダム値を渡して処理を行う。インスタンス化されたドラゴンが保持している値を更新(getter)・参照(setter)しながら処理を進める。
2.技を選択した時の処理(ButtleContents.useMove)
1.メソッドの説明
このメソッドは引数として「offenceMove・offenceDragon・defenceDragon」の3つを取る。今回のゲームでは、自分のドラゴンが技を使用して攻撃する時には、相手のドラゴンが防御側のドラゴンになる(攻撃側が敵の場合ももちろん、防御側は自分のドラゴンとなる)。
そのため、自分が攻撃する時と相手が攻撃する時には第2・第3引数に渡すドラゴンを交換するだけで、「攻撃側が防御側にダメージを与えた」という処理が攻撃側=自分でも、攻撃側=敵でも成立する。
また、このメソッドに入った時点で、攻撃側が選択した技が引数として渡っている(offenceMove)。2.技選択時の処理の流れ
1:メッセージ表示
2:攻撃処理(ButtleContents.Attack)
技から技の威力を取得し、防御側の残りHPを計算する。その後計算した値を防御側のButtleHPにセットする。
3:MPの減少
攻撃側が使用した技のMPを減らす3. 最後に
ここまで読んでいただいてありがとうございました!
内容を読んでいただく・実際に作成していただく等でドラゴンが生成される・動く(=インスタンス化される・使用される)をイメージしていただければ幸いです。
- 投稿日:2019-07-11T17:45:40+09:00
JavaScriptを触ってみた Part.2 オブジェクト指向
はじめに
ちゃんとがっつり開発のエンジニア歴2ヶ月目が学んだことをまとめる備忘録。
最近はまた毎日新しく学ぶことがたくさんで、楽しい気持ちとちょっと情報がたくさんすぎて追いつかないぞ!!!ってなっています。そんな自分の外付けHDDみたいな感じで書いていこうと思います!↓ちなみにこれまでの記事はこちら
- 第15弾
- 第16弾
- 第17弾今日はふたつも記事をあげましたよ(.・v・)ノ
オブジェクト(Object)の原義
- Object・・・物体、対象、目的(from weblio英和辞典)
オブジェクト指向とは
- 開発における考え方。
- 作成するアプリケーションなどをものとして捉えて考える開発手法。
Javaにおけるオブジェクト指向
- 基本の考え方は上記と同じ。
- クラスとその中に書かれているコードをもとにインスタンス化して作成 →つまり、設計図からものを作っていくというイメージ。
- 存在するのは、クラスとインスタンスのふたつ。
クラス
- Javaにおける 『設計図』 としての役割をもつ。
- クラスの中で実際の設計を行なっていくので、以下のようなものがクラスの中に存在する。
- メソッド・・・設計図の中でも作るものの 『振る舞い』 を記載したもの
- コンストラクタ・・・オブジェクト作成時に同時に作られる処理
インスタンス
- 実物。実際に作られているものという認識。
- クラスのインスタンス化 ・・・クラスを実物化して、そのクラスの中で使えるようにしたもの。インスタンス化した結果できたのがオブジェクト =クラスはオブジェクトの設計図!
JavaScriptにおけるオブジェクト指向
- 基本の考え方は上記と同じ。
- JavaScriptの場合は、クラスが存在しないのが大きな特徴のひとつ
- クラスの代わりにプロトタイプオブジェクトが存在する
- プロトタイプオブジェクト ・・・設計図としてのオブジェクト(オブジェクトを毎回書かなくても済むように作成)
- JavaScriptにおけるオブジェクト ・・・実体、実物(Javaにおけるインスタンスに近いもの)。
- 同じオブジェクトを何度も作るのが大変/機能を追加したい
→もととなるオブジェクトを利用してもっと簡単に対応できるように作られたのがプロトタイプオブジェクト
→つまり、もともとあるものから設計図を使ってより作りやすさを求めていくというイメージ。まとめ
- JavaでもJavaScriptでもおおもととなるオブジェクト指向の考え方については一緒
- 開発する対象を 『もの』として見る ことで設計図と実体が存在する
- ただ、オブジェクト指向の中でアプローチの仕方が反対
- Javaは設計図をもとにものを組み立てていって完成させるというイメージ
- JavaScriptは、作られた実体をもとに、さらに設計図や実体を作成していき、それらを使って最終的なものを完成させるというイメージ
あとがき
オブジェクト指向って大事だよって話はPythonを触っていたときから、今JavaやJavaScriptを学んでいる間もちょこちょこ注意はあったけど、どこまで自分って理解しているんだろう・・・というか、そもそもちゃんとわかっているのかなぁと思ってしっかり一度まとめてみてもいいかも、と思って今回はオブジェクト指向についてにしました!
オブジェクトのイメージは正直あまり理解しきれていなかったり、このコトバ、知ってはいるけど意味なんだっけ・・・ってわからないことがあったりしましたが、まとめるにあたって改めて調査したり、参考書を読んで落とし込んでなんとか今理解できているレベルまではかけたかなぁと思います。
アウトプットすることで時間がかかることもありますが、自分の頭の情報を整理して補完することができるので、改めてこうやって人を意識してまとめるって大事なんだなぁと再認識しました!!!
またまとめようと思います!!
ではでは
- 投稿日:2019-07-11T17:15:07+09:00
Java圧縮PDFドキュメント
この文はJavaでPDF文書を圧縮する方法を以下の二つの面から紹介します。
•文書の内容を圧縮する
•ドキュメントの画像を圧縮する文書の内容を圧縮する:
import com.spire.pdf.*; public class CompressPDF { public static void main(String[] args) { String inputFile = "Sample.pdf"; String outputFile = "output/CompressPDFcontent.pdf"; PdfDocument document = new PdfDocument(); document.loadFromFile(inputFile); document.getFileInfo().setIncrementalUpdate(false); document.setCompressionLevel(PdfCompressionLevel.Best); document.saveToFile(outputFile, FileFormat.PDF); document.close(); } }ドキュメントの画像を圧縮する
まず、元のPDF文書の画像を抽出し、画質を低下させることで、画像を小さくし、縮小された画像を元のドキュメントの画像に置き換えることで、PDF文書のサイズを低減します.
import com.spire.pdf.*; import com.spire.pdf.exporting.PdfImageInfo; import com.spire.pdf.graphics.PdfBitmap; public class CompressPDF { public static void main(String[] args) { String inputFile = "Sample.pdf"; String outputFile = "output/CompressPDFImage.pdf"; PdfDocument document = new PdfDocument(); document.loadFromFile(inputFile); document.getFileInfo().setIncrementalUpdate(false); for (int i = 0; i < document.getPages().getCount(); i++) { PdfPageBase page = document.getPages().get(i); PdfImageInfo[] images = page.getImagesInfo(); if (images != null && images.length > 0) for (int j = 0; j < images.length; j++) { PdfImageInfo image = images[j]; PdfBitmap bp = new PdfBitmap(image.getImage()); bp.setQuality(20); page.replaceImage(j, bp); } } document.saveToFile(outputFile, FileFormat.PDF); document.close(); } }
- 投稿日:2019-07-11T15:32:56+09:00
分散型台帳 Scalar DLT のエミュレータを使って資産管理アプリケーションを触ってみた
今回は、前回解説した資産管理アプリケーションを用いて Scalar DLT のエミュレータを使ってみます。
実行環境は今までと同じくmacOS 10.14.4で作業を行います。エミュレータの入手と実行
まずはエミュレータを入手しましょう。
以下のコマンドで取得します。$ git clone https://github.com/scalar-labs/scalardl-tools
クローンしてきたらビルドを行います。
$ cd scalardl-tools/emulator $ ./gradlew installDistビルドしたら早速実行してみましょう。
$ ./build/install/emulator/bin/emulator Scalar DL Emulator Type 'help' for more information scalar>入力待ちになれば起動完了です。
サクッと起動しますね!資産管理アプリケーションの入手
続いて資産管理アプリケーションを入手しましょう。
ソースの場所は前回ご紹介していますので、早速クローンしてきましょう。$ git clone https://github.com/indetail-blockchain/getting-started-with-scalardl.git
なお、2つのプロジェクトを利用するのでディレクトリ構成は以下の形にしています。
git/
├ scalardl-tools/
└ getting-started-with-scalardl/資産管理アプリケーションのビルド
前回の記事でスマートコントラクトが6つ用意されていると紹介しました。
そのソースが実際に配置されているのは以下の場所になります。$ ls -l getting-started-with-scalardl/src/main/java/com/scalar/am/contract AddAssetContract.java AddTypeContract.java AssetHistoryContract.java ListContract.java ListTypeContract.java StatusChangeContract.javaではこちらをビルドしていきましょう。
ビルドはエミュレータのsrc/main/java
以下にソースを配置する事で可能です。
※スマートコントラクト以外のファイルを置いてしまうとビルドが失敗するので、余計なファイルはコピー後に削除しています。$ cp -r getting-started-with-scalardl/src/main/java/com scalardl-tools/emulator/src/main/java/ $ rm -rf scalardl-tools/emulator/src/main/java/com/scalar/am/command $ rm -f scalardl-tools/emulator/src/main/java/com/scalar/am/AssetManager.java $ cd scalardl-tools/emulator/ $ ./gradlew build無事ビルドされたら build ディレクトリを覗いてみましょう。
$ ls -l build/classes/java/main/com/scalar/am/contract AddAssetContract.class AddTypeContract.class AssetHistoryContract.class ListContract.class ListTypeContract.class StatusChangeContract.classclass ファイルが出来ていますね。
スマートコントラクトの登録と実行
ではいよいよスマートコントラクトの実行を行っていきます。
まずはエミュレータを起動しましょう。$ cd scalardl-tools/emulator $ ./build/install/emulator/bin/emulator Scalar DL Emulator Type 'help' for more information scalar>まずはコントラクトを登録していきます。
全部で6つ登録します。scalar> register add-type com.scalar.am.contract.AddTypeContract ../../getting-started-with-scalardl/build/com/scalar/am/contract/AddTypeContract.class {"holderId": "Admin"} Contract 'add-type' successfully registered scalar> register add-asset com.scalar.am.contract.AddAssetContract ../../getting-started-with-scalardl/build/com/scalar/am/contract/AddAssetContract.class {"holderId": "Admin"} Contract 'add-asset' successfully registered scalar> register list-type com.scalar.am.contract.ListTypeContract ../../getting-started-with-scalardl/build/com/scalar/am/contract/ListTypeContract.class {"holderId": "Admin"} Contract 'list-type' successfully registered scalar> register list-asset com.scalar.am.contract.ListContract ../../getting-started-with-scalardl/build/com/scalar/am/contract/ListContract.class {"holderId": "Admin"} Contract 'list-asset' successfully registered scalar> register status-change com.scalar.am.contract.StatusChangeContract ../../getting-started-with-scalardl/build/com/scalar/am/contract/StatusChangeContract.class {"holderId": "Admin"} Contract 'status-change' successfully registered scalar> register asset-history com.scalar.am.contract.AssetHistoryContract ../../getting-started-with-scalardl/build/com/scalar/am/contract/AssetHistoryContract.class {"holderId": "Admin"} Contract 'asset-history' successfully registered登録の際の
register
コマンドの仕様は以下の通りです。register [実行時に使う名前] [Javaのクラス名] [クラスファイルのパス] [初期パラメータ]スマートコントラクトの登録時に初期パラメータが渡せるのですが、この資産管理アプリケーションでは
holderId
を指定する必要があります。
このholderId
は登録時のみ渡され、変更されない値になります。
これをスマートコントラクト内で利用・チェックすることで、自分が登録した資産情報を他人が更新することを防ぐことが可能になっています。
簡単なイメージとしては以下の感じです。
Scalar DLT ではアセット(資産)に対する参照・書き換えの権限コントロールは行っていないので、こういった形で予期せぬデータの更新を防ぐことが可能です。それではいよいよ実行していきましょう。
なお、実行にはexecute
を使います。execute [スマートコントラクトの登録名] [パラメータ]まずは資産の種類を登録します。
scalar> execute add-type {"name": "Tablet"} { "result": "success", "message": "type Tablet put completed." } scalar> execute add-type {"name": "SmartPhone"} { "result": "success", "message": "type SmartPhone put completed." }Tablet と SmartPhone という種類を追加しました。
次は本当に登録されているか確認しましょう。scalar> execute list-type {} { "result": "success", "message": "get list completed.", "types": [ { "type": "SmartPhone", "age": 1 }, { "type": "Tablet", "age": 0 } ] }ちゃんと保存されていますね。
ここの注意点としては、引数が無い場合は空の配列{}
を渡すというところです。
これを省略してしまうとエラーが出るのでご注意下さい。続いて、資産を登録してみましょう。
scalar> scalar> execute add-asset {"type": "Tablet", "asset": "iPad", "timestamp": 20190701120000, "id": "1001"} { "result": "success", "message": "asset iPad put completed." }ID が 1001 で、Tablet に分類される iPad を登録しました。
timestamp にはUNIXタイムスタンプを登録するのですが、わかりやすく仮の値を指定しています。
これもデータが登録されているか確認してみます。scalar> execute list-asset {"type": "Tablet"} { "result": "success", "message": "get list completed.", "Tablet": [ { "id": "1001", "name": "iPad", "timestamp": 20190701120000, "status": "in-stock" } ] }確かに iPad が登録されていますね。
status が in-stock になっているので、早速借りてみましょう。scalar> execute status-change {"asset_id": "1001", "status": "on-loan", "timestamp": 20190701130000} { "result": "success", "message": "Borrowed" } scalar> execute list-asset {"type": "Tablet"} { "result": "success", "message": "get list completed.", "Tablet": [ { "id": "1001", "name": "iPad", "timestamp": 20190701130000, "status": "on-loan", "holderId": "Admin" } ] }無事借りることが出来ました。
timestamp も更新され、status も on-loan に変更されていますね。
次は返却してみましょう。scalar> execute status-change {"asset_id": "1001", "status": "in-stock", "timestamp": 20190701140000} { "result": "success", "message": "Returned" } scalar> execute list-asset {"type": "Tablet"} { "result": "success", "message": "get list completed.", "Tablet": [ { "id": "1001", "name": "iPad", "timestamp": 20190701140000, "status": "in-stock" } ] }こちらも無事出来ました。
それでは最後に貸し出し履歴を確認しましょう。scalar> execute asset-history {"id": "1001"} { "result": "success", "message": "get history complete.", "history": [ { "timestamp": 20190701140000, "status": "in-stock", "age": 2 }, { "timestamp": 20190701130000, "status": "on-loan", "age": 1, "holderId": "Admin" }, { "timestamp": 20190701120000, "status": "in-stock", "age": 0 } ] }登録、貸し出し、返却と履歴が残っていますね。
まとめ
というわけでエミュレータを使って資産管理アプリケーションを動かしてみました。
エミュレータは起動も早くて動作も速いので作業が捗りますね。
今回はエミュレータを使ったので、exit してしまうとコントラクトとデータが消えてしまいます。
なので次は実際に Sandbox 環境への登録やその呼び出しといった辺りを追っていきたいと思います。
- 投稿日:2019-07-11T14:29:17+09:00
気象庁のサイトで見れる過去の天気のスクレイピング的なやつ
ミクロ経済学や環境経済学の記事を書こうかと思ってサボり続けています。
そろそろ国内誌に投稿した論文の査読結果(という名のボロカスな批評、別にリジェクトはされないと思うが痛いこと書かれている気がする…)が返ってくる予感がするので、その修正作業のためにそっちの記事は当面書けないと思いますが…今回は私が京大の総人にいた頃(3年くらい前の2016年)に授業でつくったjavaアプリ(jarファイルなので使うためにはjavaのインストールが必要)を紹介します。
当時から今の研究室にはちょくちょくお邪魔していて、環境経済学の研究に使えそうな小ネタ的アプリの開発をしていたんですが、ちょうどそのときとっていたjavaの授業が「何でもいいからアプリつくって発表せよ」ってものでしたので、どうせなら研究で使えるものをと思い気象庁の過去の気象データ検索をスクレイピングするプログラムを作りました。以下、そのリンク。環境経済学の研究では気象データを使うことは頻繁にあるので、今でもこのプログラムは度々使っています。以下、アプリの画像。
まず都道府県のプルダウンメニューで、気象データを取得したい場所の都道府県を選択。
すると市区町村(役場名)に、その都道府県の市区町村役場の名称が出ます。
気象データを取得したい市区町村の役場名を選択して、あとは取得したいデータの期間を年月日で指定してダウンロードするだけ。csvファイル形式(UTF8 BOM付)で出力されます。取得する情報は、環境経済学的によく使うデータである降水量、最低・最高・平均気温、日照時間と年月日だけです。
なお、全ての市区町村に気象観測所が設置されているわけではありません。ですから、このプログラムは指定した市区町村(の役場の緯度・経度)から最短距離にある同じ都道府県内の観測所を内部で自動的に特定し、そこの観測所が保持している記録をダウンロードします。どこの観測所が指定した市区町村役場の最寄観測所なのかは、このプログラムのテキストエリア内を見れば分かります。
市区町村役場の緯度・経度は、GIS関係のデータを提供している国土地理院の国土数値情報ダウンロードサービスで、市区町村役場の施設情報(住所や緯度・経度など)が記されたXMLファイルから取得しています。このXMLファイルはプログラムに同梱されています。(役所の移転やらで緯度・経度が変わったらその都度XMLファイルをダウンロードして更新すればいいのですが、自分は一度もやってませんので、デフォルトでは2016年のままです)
ちなみに、特に田舎の市区町村によってはダウンロードデータがなかったりします(!)
すみません、これはどうやらアップロードしたjarファイルが、バグを治していない古いソースのプロジェクトをエクスポートしたやつのまま放置していたせいでした。最新版のやつからエクスポートしたら直ってました。上記DropBox内のファイルは新しいバージョンに更新してあります。上述のように、もともと降水量・気温・日照時間のデータをとるために作ったプログラムですが、全国の気象観測所はこれらを全て記録しているわけではありません。たとえば、日照時間を記録しない小規模な自動観測所などもあります。こうした必要なデータを記録しない観測所は除き、「降水量・気温・日照時間」の3点を最低限観測する観測所の中で、指定した市区町村役場から最も近いところが選ばれるプログラムです。
あと大学の演習室だの計算機室だのはそうだと思いますが、こういうプログラムからネット接続する際にプロクシ設定を要求するような環境で作業する人のために、プロクシ設定機能を設けてあります。
今回は以上です。
ソースコード
ソースは長いので個別説明は諦めました。なので以下、ソースコードの全部を公開。
ソース(Dropbox)基本eclipseで作業してたので、それに準じたディレクトリ構造です。srcディレクトリ内にソースが入ってます。GIS_XMLディレクトリ内には国土地理院からDLした47都道府県分の公的施設(役場など)の位置情報等に関するXMLファイルが入っています。HTMLパーサとしてjsoupを使っているのでそれが同梱されています。そこら辺は適宜最新版に変えるといいかもしれません。
- 投稿日:2019-07-11T14:26:04+09:00
JavaScriptを触ってみた Part.1 基本的な処理コード系
はじめに
ちゃんとがっつり開発のエンジニア歴2ヶ月目が学んだことをまとめる備忘録。
訳あって、1回データサイエンスから仕事では少し離れて、開発の見聞を広めていくことにしました!
また心機一転、頑張ります!↓ちなみに、前回までの記事はこちら。
懐かしい記事がたくさんだ!w
使用環境
今回は、Webアプリケーションの開発になれる目的も含め、以下の環境で触ってみた。
- テキストエディター→Sublime Text 3
- 実際にコードを書く場所として使用。
- 文法が正しく記入されていれば、自動でカラーリングをしてくれるため、何を書いたかの確認がよりしやすくなる。
- Webブラウザ→Google Chrome
- Webアプリケーションの動作確認を行うために使用。
- .htmlファイルをこのアプリケーションで開き、以下の項目を確認
- ページビュー→実際に画面にどのように表示されているか
- Console→コードが正しく書けているか(求めている処理を正しく行なっているか)、行なっていない場合はどこでエラーなどが発生しているかを特定するために、段階的に処理結果をはじめとする状況を確認
変数/変数定義の仕方
変数定義
- JavaScriptは基本的に変数の宣言はその変数に格納されるデータの型に関わらず、この書き方で宣言する
var 変数名 ;
- 変数への数値の代入はJavaと同じで変数を左辺において右辺に代入する値をおき、『=』演算子でつなぐ。
変数名 = 変数に代入する値 ;
- 数値演算子についても、Javaと同じものを使用すればよい(詳細は演算子のところで記載)。
変数について
- 文字列は、シングルクオーテーションで文字列を囲んで右辺におく(Javaではダブルクオーテーション)
- 別にダブルクオーテーションで囲んでも問題は発生しない
- が、.htmlファイルでは、文字列値を代入する際にダブルクオーテーションを使用
- .htmlファイル内に<すくりぷと> </すくりぷと> で囲んでJavaScriptを使用してコーディングを行う際に、識別がしづらくなるため、開発のチームによってシングルクオーテーションを推奨していたりする
- コーディングルールについては、開発のチームによってそれぞれ統一して決められている(統一することで、エラーの発生箇所を特定したり、バグ発生のリスクを下げたり、そもそもとしてコードをチームの全員が読みやすいようにすることが目的)ため、そのルールに従う
文字列の結合を行いたい場合は、Java同様、『+』を使用して結合することができる
文字列と数値の結合も可能。ただし、求めている結果と違うものが返ってくる可能性もあるため注意。
var a = 5 + 6 ; console.log(a) ; var b = '5' + '6' ; console.log(b) ; var c = '5' + 6 ; console.log(c) ;
- a は数値同士を足すということになるため、 5 + 6 = 11 として処理を行うため、出力結果は 11 になる。
- b は文字列同士を結合する処理を行うため、出力結果は 56 になる。
- c は文字列『5』に数値の 6 を結合するという処理を行うため、出力結果は 56 になる。
スコープ
Java同様、JavaScriptにもスコープという概念は存在する。
スコープとは
- スコープ・・・変数の有効範囲。どこから参照することができて、どこから参照することができないのか。
グローバル変数とローカル変数
Java同様、スコープによって変数は分類することができる。
- グローバル変数・・・プログラム内全体から呼び出し、使用することができる変数(関数の外で宣言しているため)。
- ローカル変数・・・関数の中で宣言、その関数の中でしか使うことができない変数。
変数使用時のルール(適宜更新)
- グローバル変数は、なるべく使わないようにする
- どこからでも参照できてしまう分、使い勝手が悪くなってしまう
- グローバル変数を使用するのではなく、即時関数で代用できないかまず検討するとよい(即時関数については関数で詳細を記載)
関数
- 関数・・・複数の処理をまとめて再利用できる形にするための概念(Javaでいうメソッドに近い)。
- 基本的な書き方は以下の通り。
function 作成したい関数名 (引数) { 実行させたい命令 ; return 戻り値 ; ←コンソールなどで段階的にそこまでの処理が正しく行われているか確認したいときは必ず書くようにする }
- 関数には名前を設定する必要がない→無名関数という
即時関数
- 即時関数・・・関数名を設定することなく、即時的にそこでだけ使用するために書く関数。
書き方は以下の通り。
(function 作成したい関数名 (引数) { 実行させたい命令 ; return 戻り値 ; ←コンソールなどで段階的にそこまでの処理が正しく行われているか確認したいときは必ず書くようにする })();
- 関数全体を ()で囲んで、スコープに閉じるようにする。
即時関数を使用するメリット
- 関数名の重複を考えることなく、関数を書くことができる =エラー発生などの可能性を減らすことができる
制御文
制御文とは
- 制御文・・・『〇〇(条件)ならば処理Aを行い、そうでなければ処理Bを行う』などの条件に合わせた処理設定を行う文(=Javaなどの条件分岐や繰り返し処理と同じ)。
- 代表的な制御文の例は以下のふたつ。
- if文
- for文
制御文の書き方
基本的な書き方は、Javaとほぼ変わらない。
if文
if (実行するための条件式) { 実行したい命令 ; } else if (実行するための条件式) { 実行したい命令 ; } else { 実行したい命令 ; }
- 『else if』は条件を複数回重ねて設定したい場合にのみ記載する。
- 条件式がtrueのときに命令が実行され、falseのときに次の条件式がtrueか判定していき、最終的に条件を満たすところでそこで定義した命令が実行される。
for文
for (初期化(実行開始時の状態) ; 実行するための条件式 ; 完了したときの更新命令) { 実行したい命令 ; }
- 実行するための条件式がtrueの間、繰り返しで実行される。
- 『完了したときの更新命令』は、命令した実行が完了した時に、条件式で使用している変数を更新する命令を記載する。
演算子
制御文では特に、演算子を使用することが多い他め、各演算子についてここでまとめておく。
四則演算子
基本はJavaと同じ。
- 『+』:たす(加)
- 『-』:ひく(減)
- 『*』:かける(乗)
- 『/』:わる(除)
- 『%』:割り算のあまり(余)
比較演算子
等式をのぞき、基本はJavaと同じ
- 『>=』:左辺は右辺以上
- 『>』:左辺は右辺よりも大きい
- 『<=』:左辺は右辺以下
- 『<』:左辺は右辺よりも小さい
等式は、JavaScriptにおいては基本は以下のふたつを使用する。
- 『===』:左辺と右辺は等しい(データ型が同じ場合に使用)
- 『!==』:左辺と右辺は等しくない
Javaで使用する以下の演算子は、JavaScriptの場合は少し異なる使い方をするため、注意。
- 『==』
- Javaでは、『左辺と右辺は等しい』という意味で使用。
- JavaScriptでも、基本的な意味は『左辺と右辺は等しい』。ただしJavaScriptでは、この記号を使用した場合は左辺と右辺それぞれのデータの型に関係なく同じ値か確認する。
JavaScriptにおける論理演算子
基本はJavaと同じ。
- 『&&』:左辺かつ右辺
- 『||』:左辺または右辺
配列とオブジェクト
配列
JavaScriptでは、グループ化した値を格納するために配列を使用できる。
配列の書き方
配列名 = ['要素', '要素', '要素', ・・・]配列内の各要素の数え方は、順番に 0番目、1番目、2番目・・・ となる。
配列の操作方法
配列を操作したいときに使えそうな命令をまとめておく。
// 配列のn番目の要素を出力 console.log(配列名[n]) ; // 配列の要素をすべて出力 console.log(配列名) ; // 配列の要素を追加したい 配列名.push('追加する要素') ; // 配列の要素を削除したい 配列名.splice(削除したい要素の始まる要素番号, 消す個数) ; // 配列を構成する要素の個数を確認/出力したい console.log(配列名.length) ;オブジェクト
※JavaとJavaScriptのオブジェクト指向の違いについては、改めてまとめる。
オブジェクト(Object)の原義
- Object・・・物体、対象、目的(from weblio英和辞典)
JavaScriptにおけるオブジェクト
- オブジェクト・・・名前と値をセットでグループ化して値を扱うための概念。
基本的な書き方
var 変数名(オブジェクト名) = { キー(名前) : バリュー(値), キー(名前) : バリュー(値), ・・・ }
- キーとバリューがそれぞれ対応している(対応しているもの同士を : でくっつけて書く)
オブジェクト内の指定のバリュー(値)の呼び出し方
→以下のふたつのかきかたのいずれでもOK変数名['キー(名前)'] ; 変数名.キー(名前) ;オブジェクト内の指定のバリュー(値)を上書きする
→基本は呼び出して代入するだけ。変数名['キー(名前)'] = 代入する値 ; 変数名.キー(名前) = 代入する値 ;オブジェクトの情報を出力する
console.log(オブジェクト) ;メソッド・・・オブジェクトの中に書いた関数
JavaScriptを触ってみて
結論
Javaと比較すると、使いやすかった!
理由
Javaと比較して、環境構築がしやすかった(おそらく、学習時に指定された環境が大きく違ったから?)
→Javaでは、ローカルサーバホストの設定やサーバーでの実行時の設定、DBとの連携のために別途Visual Studio 2017のパッケージのインストールなどの対応が多く、大変だった。
- ちなみにJavaで使用した環境はこんな感じ
- エディター→eclipse 2019-06
- サーバーホスト→Tomcat 9.0
- 使用DB→MySQL
変数の型の宣言が必要ないため、変数定義が楽だった
→Javaではデータ型も指定する必要があった
→データ型を設定する手間が省ける分、バグも起きやすいかも・・・?(データ型がわからなくてもとりあえず定義してある程度のところまでコードを書き進めることができるから)あとがき
開発って難しいな、と思いつつ、とっつきやすい言語もあるんだなって認識しました。
少しずつこの難しさと仲良くなれるようにマイペースにまた勉強していこうと思います^^ではまた!
P.S.)今回はSimple is the BESTなあとがきをめざしてみた!w
- 投稿日:2019-07-11T10:39:46+09:00
Implクラス Voクラス
https://matome.naver.jp/odai/2141432737100734901
-Implクラス接尾辞パターン インターフェイス名には特別な接辞をつけず、 そのインターフェイスを実装したクラスに Impl 接尾辞をつけるパターン。 Javaなどで見られる。へー と思ったのでメモりますっ(^^)/
- 投稿日:2019-07-11T09:34:00+09:00
JJUG CCC 2019 Spring に参加してみた
※2019/6/3に、会社のオウンドメディアに投稿した記事を移植しました。
https://www.chuo-system.co.jp/csclib/「参加したことがない」「参加してみたいけれど一人で参加するのは不安」な方向けに、
2019年5月18日(土)に開催されたJJUG CCC 2019 Springが
どんなものだったかレポートします。JJUGとは?
日本Javaユーザーグループは日本の任意団体で、
Java 技術の向上・発展と一層の普及・活性化を目指されています。
Japan Java User Group、略してJJUGですね。
http://www.java-users.jp/JJUG CCCとは?
CCCは「Cross Community Conference」の略で、
JJUGが主催する日本最大のJavaコミュニティイベントです。
毎年2回、春と秋に開催されています。Javaに関連するセッションが行われ、日本人のスピーカーはもちろん、
海外のスピーカーもいらっしゃいます。JJUG CCCのすごいところ
なんと、一般参加枠(懇親会なし)の場合、無料です。
一般参加枠(懇親会あり)の場合であっても¥1,000で参加できちゃいます。この手のITイベントは参加費有料&少しお値段お高めという傾向が見られますが、
JJUG CCCでは国を問わず優秀なエンジニアの皆さまのお話しが無料で聞けちゃうという…。
「本当に良いんですか?」と言いたくなっちゃうレベルです。逆に「無料」と言われると、『本当に大丈夫なの?変なイベントじゃない?』と
不安になる方もいるかもしれませんが、そこはJJUG=日本最大のJavaコミュニティ主催です。調べると、どうやら2009年頃から開催されているようで、
10年以上続いているという実績もあります。実は…
私も初めての参加でした(小声)
Javaエンジニアの先輩から、かねがねお話は聞いていて、
「参加したいな~」とぼんやりしていたら2019年を迎えてしまいました。直近でJava案件に関わっていたり、Javaを教える機会も出てきたりしたため、
「四の五の言わず飛び込んでみよう!」と意を決して申し込みをしました。
一般参加枠(懇親会なし) での参加です。いざ、当日。
なんだか立派な建物。エレベーターで会場の5階に上がります。
受付は下画像のようになっていて、参加申し込み後にメールで送られてくる
QRコードを読み取ってもらうだけでOKでした。あら簡単。周りをみると、一人で参加していると思われる方が断然多く、
「イベントに一人で参加するのがちょっと苦手」な方でも無問題です!実は、事前に 「どのセッションを受けたいか」のアンケートがとられています。
会場となる部屋はいくつかあり、 キャパシティもまちまちです。
恐らく運営側が、事前アンケート結果を元に
「どのセッションにどの部屋を割り当てるとよいか」を検討してくれているようです。
なるべく立ち見がでないよう、配慮がされているように思えます。通路は一方通行になっていて、
「セッションが終わって部屋を出る人」「次のセッションを受けに部屋へ入る人」が
入り乱れないようになっていました。
おかげで人波に揉まれることなく、入退出ができていました。受けてきたセッション
私は早起きが苦手なので、午後から参加してまいりました。
「1日中参加しなければならない」という訳ではなく、
受けたいセッションだけ受けるでOKというスタンスが有難いです。入門: 末尾呼び出し最適化
最近再帰関数を知った(小声)こともあり受けてきました。
初めてのJJUG CCC参加、初めてのセッションで上級者向けをチョイスする謎の勇気!!
スピーカーの方の説明が丁寧だったので、置いてきぼりにはなりませんでした。再帰呼び出しではスタックがどんどん積まれていく、
故にスタックオーバーフローが発生してしまう。
戻り値返却は「返すだけ」なんだから、一個一個返さなくとも、
最後に一気に返したらいいんじゃない?のくだりで「おお~」と理解できました。スピーカーの宮川さんは、Kinkという言語の開発もされているらしいです。
すごい(小並感)ゴールドマン・サックスにおけるApache Beamを用いたビッグデータ処理の紹介と実例
なぜかApache Beamを「Apache Bean=豆!?」だと勘違いしていましたが、
Batch + Stream からきていたのですね(恥)。ゴールドマン・サックス社はIT部門にも力を入れているとのこと。
ITではない企業のIT部門はあまり力を入れてもらえない印象を持っていたのですが…、さすがです。残念ながら資料は公開されていないようなので、
ゴールドマンサックス社とApache Beamのリンクを置いておきます。
- ゴールドマンサックス社:https://www.goldmansachs.com/japan/
- Apache Beam:https://beam.apache.org/
JJUG会長と一緒に考えたSpring Boot x JavaScript x IntelliJ x アジャイルというモダンな新人研修を今まさにやっている話
Buzzworks(会社の研究開発チーム)は2019年度新入社員研修を担当していることもあり、
私的にはこちらが大本命でした。一番大きいお部屋が会場だったのですが、ほぼ満員でした。「100%宣伝です」とおっしゃってはいたものの、どんなフレームワークやソフトを使っているのか、
研修担当者から見た感想(新人がどのくらい理解できていたか等)、
あたりを知ることができて大満足でした。そして何より、資料やスピーカーの方のお話が上手くて、
こうなりたいなと思いました(小並感part2)。最後に
私はノートとペンというアナログスタイルで参加しましたが、
ノートPC持ち込みの参加者が多く、薄型ノートPCが欲しくなりました。日頃お目に掛かれない方々のお話が聞けたこと、
参加者の数も多くなんだかお祭り気分になれたこと、
そんなこんなでとっても刺激になりました。
(感想がいちいち雑で申し訳ありません…)登壇資料も公開されているので、受けられなかったセッションの資料も見ることができます。
本当に有難いですね。
- JJUG CCC 2019 Spring 登壇資料まとめ:https://github.com/jjug-ccc/slides-articles-2019Spring
2019 Fallも是非参加したいです!!!
もし「敷居が高いかも…」と思ってJJUG CCCの参加を敬遠してしまっている方、
気軽に参加することをオススメします。「高度な専門知識・技術知識がないとNG」ということはありませんし、
みなさんの刺激になることはお約束します!
- 投稿日:2019-07-11T00:57:45+09:00
SpringでMySQLエラー Unknown column ' 値1 ' in 'field list'
Spring Java の Entityで
Unknown column ' 値1 ' in 'field list'
が出てハマりました。
結論から言うと大文字が混ざっていたのが問題でした。
ターミナルからMySQLに直接SQLを流し込むと大文字でも正常に動作しますが、
Spring + Java のプログラムから呼び出そうとするとカラムがないというエラーになります。field がない と特定の列名を指定してくる場合はカラムに日本語や大文字などが混ざっていないか注意しましょう。
- 投稿日:2019-07-11T00:26:54+09:00
Javaセキュアプログラミング基本~SQLインジェクション~
初めに
今回はJavaにおけるセキュアコーディングを、攻撃の種類と対応策の形で
記述していこうと思います。
セキュアコーディングというものを意識したことがない方や、
セキュリティに関して考えたことのない方(私みたいな)を対象としています。
メインの意図は私の覚書だからあまり読む価値はないかもセキュアコーディングとは?
かつて、コンピュータやインターネットは
今とは比べ物にならないくらい閉鎖的でした。しかし時代は進み、個人が大多数に向けてインターネット上で
情報を発信できるようになりました。(qittaもその一部です。)
更には、電子マネーやネットショッピング等、
商売や通貨としても使えるようになっていきました。それと共に、プログラムも複雑化、人間が完全に管理できないレベルになり、
どうしても欠陥が生まれてしまう場合があります。(セキュリティホール)
そこを突いて攻撃をするプログラマーがいると、個人情報や、最悪の場合は金銭を
奪い取ることができるようになりました。そういった脆弱性を無くそうというのが、セキュアプログラムの役割です。
攻撃の種類と対策法(Java)
【SQLインジェクション】
SQLインジェクションは、悪意のある入力によって予想外のSQLが実行されてしまう攻撃の事を指します。
【例】
以下のコードは、画面にあるテキストボックスの入力値をwhere句に使用し、
結果を取得するJavaのソースコードです。
(dayが画面から取得した値だと考えてください)SqliSample.javapublic class SqliSample(){ public void selectUserData(String day){ Class.forName("org.postgresql.Driver"); Connection conn=DriverManager.getConnection("jdbc:postgresql:Training","postgres",""); Statement statement=connection.createStatement(); String sql = "SELECT * FROM USERDATA WHERE INSERT_DAY <" + day ; statement.executeQuery(sql); }パッと見では問題なさそうです。
SQLの内容は、「登録日付が渡された値以下のデータを取得する」です。
例えば、2019-07-10とかが入力されれば、それ以下の値を取得します。
BETWEEN...しかし、入力値が以下だとどうでしょうか?
「2019-07-10; DELETE FROM USERDATA;--」
このような値が入ってしまうと、String sqlの値は
"SELECT * FROM USERDATA WHERE INSERT_DAY < 2019-07-10; DELETE FROM USERDATA;"
となってしまいます。
検索の後、テーブルが削除されてしまいます。こういった事象がSQLインジェクションであり、実際に起きた事例としては
ソニーのサービス「PlayStation Network」(PSN)
で約7700万人の個人情報漏えいが発生等が起こっています。回避策
プレースホルダを利用しましょう。
プレースホルダとは、SQL 文の中で可変な項目を暗号化し、後で変更できる方法です。
Javaでは、PreparedStatementがプレースホルダに対応しています。SqliSample.javapublic class SqliSample(String day){ public void selectUserData(String day){ Class.forName("org.postgresql.Driver"); Connection conn=DriverManager.getConnection("jdbc:postgresql:Training","postgres",""); PreparedStatement prep = conn.prepareStatement("SELECT * FROM USERDATA WHERE INSERT_DAY <" + ?); prep.setString(1 , day); prep.executeQuery(); }また、mybatisでは${}(置換変数)で同様のSQLインジェクションを起こされる可能性があるので、mybatisで実行する際は、バインド変数の型チェックを行います。
以下のコードの場合は、${day}に、「2019-07-10; DELETE FROM USERDATA;--」をいれることができてしまいます。SqliSample.xml<select id="selectInsertDay"> SELECT * FROM userdata WHERE insert_day <![CDATA[ < ]]> ${day} </select>回避法としては、バインド変数を使用する。置換変数の型チェックを行うなどがあります。
SqliSample.xml<select id="selectInsertDay" parameterType="string" resultType="long"> SELECT * FROM userdata WHERE insert_day < ${day} </select>SqliSample.xml<select id="selectInsertDay"> SELECT * FROM userdata WHERE insert_day < #{day} </select>バインド変数(#{day}の部分)は、mybatis→PreparedStatementを呼び出す実装になっています。
その為、既に暗号化がされた状態でSQLの構築が行われています。しかし、使用できる箇所が、以下に限られています。(PreparedStatementの都合)
・4大命令のwhere句
・InsertのValues
・UpdateのSETですので、使用できる場合はPreparedStatement(バインド変数)を使用し、
使用できない箇所は置換変数やstatementを型チェックをしながら利用していきましょう。
できることなら、PreparedStatementを使用できない場合はJavaからSQLを利用しない等の対処が望ましいでしょう。終わりに
以上です。
私情ですが、現在セキュリティエンジニアを目指して学習中ですので至らぬ点があればご指摘ください。応援も待ってます。