2018年11月1日木曜日

VSCodeでJavaのWebアプリ開発

Tomcat for Java を使ってVSCode簡単なWebアプリを開発してみる。

GradleとTomcatがインストールされていることが前提となるので、インストールされていないようならインストールしておいてほしい。

Gradle : https://gradle.org/
Tomcat : https://tomcat.apache.org/download-90.cgi

何はともあれ、Tomcat for Javaをインストールする。


指示はでないのだけれど、一度VSCodeを再起動したほうがいい。私の環境では、ちゃんと動いてくれなかったのだ。

ソースの構成は下記の通り。

-+-src
|  +-main
|  |  +-java
|  |     +-com
|  |        +-hello
|  |           +-HelloController.java
|  +-webapp
|     +-hello.jsp
+-build.gradle

まずはgradleから作成する。

■build.gradle
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'war'

sourceSets {
    main {
        java {
            srcDir 'src'
        }
    }
}

repositories {
    mavenCentral()
}

dependencies {
    providedCompile 'javax.servlet:javax.servlet-api:3.0.1'
}

gradleを書き終えたらbuild.gradleのあるディレクトリでコマンドを実行。

gradle eclipse

.classpathや.projectといったファイルが作成される。eclipseを使うわけではないので必要ないと思うのだけれど、これをやらないと何故かコンパイルができなかったり、インテリセンスが動作しなかったりと上手くいかなかった。誰か原因を知っていたら教えてほしい。

src/main/java/com/hello/HelloController.javaを作成する。HelloController.javaを開くとVSCodeがなにやらしはじめる。

こんなメッセージが表示されるはずだ。


100%になると消えるのでそれまで待ったほうがよさそうな感じがする。数秒程度なので、これが終わったらHelloController.javaのコードを書いていく。

■HelloController.java
package com.hello;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.sun.net.httpserver.HttpServer;

@WebServlet("/")
public class HelloController extends HttpServlet {

    private static final long serialVersionUID = 1L;

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {
        getServletContext().getRequestDispatcher("/hello.jsp").include(request, response);
    }
}

次はsrc/main/webapp/hello.jsp。

■hello.jsp
<html>
    <head>
        <title>Hello World</title>
    </head>
    <body>
        <h1>Hello World</h1>
    </body>
</html>

ここまで出来たら、Gradleでビルドを実行する。

gradle build

ビルドが成功すると/build/libディレクトリにwarが出来上がる。


出来上がったwarを右クリックしてメニューを表示させ、Debug on Tomcat Serverを選択。


Tomcat Serverを選択するダイアログが表示されるので、+Add New Serverを選択し、Tomcatのインストールディレクトリを指定する。


このような表示が output ビューに表示されたら、Tomcatの起動に成功。

情報: Server startup in 1279 ms


ブラウザでアクセスするときちんと表示されることが分かる。
http://localhost:8080/TomcatForJavaDemo/


これでTomcat上でJavaのWebアプリを動作させることができた。

やってみて思ったのだが、やはりEclipseなどのIDEのほうが便利だということだ。あまり考えなくて済む。私のやり方が悪いのかVSCodeだと、インテリセンスがうまく動いてくれないことがあった。またデバッガが少し不安定のような気がしている。

下記のように20行目にブレイクポイントを置いてみて実際にデバッグしてみる。


すると、ぜんぜん関係ないところで止まってしまう。


本来止まって欲しい、ブレイクポイントを置いたところではどうやっても止まってくれない。今回、この問題を解消することができなかった。何かやり方に問題でもあるのだろうか。

VSCode自体は動作が軽くていいので、出来ればJavaの開発でも使いたい。しかし、デバッガがちゃんと動作させられないと、複雑なプログラムを作るのは難しい。どうしたものだろうか。

2018年10月23日火曜日

VSCodeでJava環境構築

Visual Studio CodeでJavaの開発環境構築をやってみる。

まず、拡張機能ビューを開く。Ctrl + Shift + Xでビューが開くので「Java Extension Pack」をインストールする。



単純なソースを書いて保存。右下の言語モードの選択でJavaを選択すると、Javaのハイライトが行われるようになる。デフォルトだとこの欄はPlain Textとなっている。



F5で実行。はじめてF5を押した時はlaunch.jsonというファイルが作成されるだけなので、2回押す必要がある。



デバッグコンソールにHello World!と表示されたことが確認できた。

行番号の左横をクリックすることでブレイクポイントも置ける。

2018年10月22日月曜日

PostgreSQLにおけるスキーマの定義変更

スキーマの定義変更方法。すぐ忘れてしまうのでメモしておく。

スキーマの名称変更。

alter schema [name] rename to [newname]

nameが既存のスキーマ名で、newnameが新しいスキーマ名。

スキーマの所有者変更。

alter schema [name] owner to [newowner]

nameが所有者を変更したいスキーマ名で、newownerが新しい所有者のロール名。

スキーマの所有者を変更はスーパーユーザーでないと出来ない。

2018年10月21日日曜日

jarの依存関係をjdepsで調べる

JDK8からjdepsというjarとかclassの依存関係を調べてくれるツールが付属している。

自分で作ったものならいいのだが、いまどきのシステム開発は自前ですべてをそろえるなんていうことも少ないだろう。どっかからライブラリを持って来たりすると思う。

ただ、これも当初の開発メンバーがいなって1年以上なんてことになると、ライブラリの依存関係が分からなくなってしまうことがある。動いているものはほうっておくという考え方もあるのだが、整理したいなんて言い出す人もいるものだ。

そんなときにjdepsを利用すると簡単に依存関係を調べてくれるので便利だ。

jdeps helloworld.jar

このコマンドだけで指定したjarの依存関係を調べてくれる。半角スペースで区切って複数のjarを指定することもできる。また、jarだけでなくclassの指定も可能だ。

jdeps helloworld.class

クラスの場合、半角スペース区切りで複数指定することもできるけれど、ワイルドカードも使えるのでこちらのほうが便利だ。

jdeps *.class

なぜだか分からないが、ワイルドカードはjarでは使えない。

出力結果は下記のようなる。

helloworld.jar -> java.base
   helloworld                                         -> hellodependency                                    helloworld.jar

   helloworld                                         -> java.io                                            java.base
   helloworld                                         -> java.lang                                          java.base
   hellodependency                                    -> java.io                                            java.base
   hellodependency                                    -> java.lang                                          java.base

この例だとhelloworld.jarはhellodependencyに依存しているということが分かる。

依存関係が分からないときは「見つかりません」と表示される。

helloworld.class -> java.base
helloworld.class -> 見つかりません
   helloworld                                         -> hellodependency                                    見つかりません
   helloworld                                         -> java.io                                            java.base
   helloworld                                         -> java.lang                                          java.base

指定されたjarやclassの中に依存関係にあたるjarやclassが含まれていないとダメなのだ。有効な解決手段は見つからなかった。とは言っても、参照ライブラリにあたるjarはひとまとめのディレクトリに保管してあると思うので、そのディレクトリにあるjarをすべて指定すればきっと依存関係は判明するはずだ。

PostgreSQL : カレントスキーマの切り替え

PostgreSQLにおけるカレントスキーマの切り替え方法。たまにしか使わないものだから、忘れてしまって使うたびに調べなおしてしまっている。

このSQLでスキーマの切り替えを行うことができる。fooのところに切り替え後のスキーマ名を指定する。
set search_path = foo

ちゃんと切り替わったかどうかはこのSQLで確認できる。
select current_schema

2018年10月20日土曜日

EclipseでTomcatのタイムアウト時間の変更方法

EclipseでのTomcatのタイムアウト時間の変更方法。

サーバービューを開いて、Tomcatをダブルクリック。


タイムアウト欄の開始の値を変えることでTomcatのタイムアウト時間を変更することができる。

2018年10月10日水曜日

AntによるJARの作成

AntによるJAR作成方法。

HelloAntというプロジェクトをAntを使ってJARを作成までを行う。

■構成
HelloAnt
  ├─src
  │    ├─helloant
  │    │    Main.java
  │     MANIFEST.MF
  build.xml

build.xmlがAntのビルド設定のファイル。各ファイルの内容は下記の通り。

■Main.java
package helloant;
public class Main {
     public static void main(String[] args) {
          System.out.println("Hello Ant");
     }
}

Main.javaはコンソールに Hello Ant と出力するだけ。

■MANIFEST.MF
Main-Class: helloant.Main

マニフェストにはメインクラスを記載しておく。

■build.xml
<?xml version="1.0" encoding="UTF-8" ?>
<project name="HelloAnt" default="dist" basedir=".">
     <!-- 1.定数の定義 -->
     <property name="dir.src" value="src"/>
     <property name="dir.target" value="target"/>
     <property name="dir.target.bin" value="${dir.target}/bin"/>
     <!-- 2.初期化処理 -->
     <target name="init" description="初期化処理">
          <delete dir="${dir.target.bin}"/>
     </target>
     <!-- 3.コンパイルの実行 -->
     <target name="compile" depends="init" description="コンパイル">
          <mkdir dir="${dir.target.bin}"/>
          <javac srcdir="${dir.src}"  destdir="${dir.target.bin}" includeAntRuntime="false"/>
     </target>
     <!-- 4.JARの作成 -->
     <target name="dist" depends="compile" description="JARの作成">
          <jar destfile="${dir.target}/helloant.jar"  basedir="${dir.target.bin}"  manifest="${dir.src}/MANIFEST.MF"/>
     </target>
</project>

Antのビルド定義はXMLで書いていく。

一番外側がprojectタグ。このタグはname、default、basedirの3つの属性を持っている。nameはプロジェクト名。defaultはデフォルトで動作するtarget。targetについては後述する。最後のbasedirがパス計算を行うときのベースディレクトリ。

projectタグの中にはひとつ以上のtargetタグを定義する。このタグはビルドプロセスのひとまとまりを定義するもの。色々な属性を持っているけれど、今回使用したのはname、depends、descriptionの3つ。

nameはtargetの名前で、任意につけられる。

dependsはtargetの依存関係を示す。例えば、「4.JARの作成」には depends="compile"が設定されているので、「3.コンパイルの実行」に依存していることが分かる。依存関係を指定しておくことで、Antが勝手に解釈して必要なtargetを実行してくれる。

descriptionはtargetの説明を記述する、コメントのようなもの。

「1.定数の定義」のところでbuild.xml全体で使用する定数を指定している。name属性に定数名、valueに値を設定する。

「2.初期化処理」でビルド前の初期化処理を行っている。この例ではコンパイルした資源の削除を実行するようにしている。

「3.コンパイルの実行」ではソースのコンパイルを行っている。mkdirタグでコンパイル結果を格納するフォルダの作成を実行。javacタグではsrcdir属性で指定したソースコードをコンパイルし、destdirへ結果を出力するようになっている。includeAntRuntime属性はAntランタイムライブラリをクラスパスに含めるかどうかの設定を行っている。ちなみにfalseを設定することが推奨されていて、未指定だとAnt実行時にwarningが発生する。

「4.JARの作成」で実際にJARの作成を行っている。jarタグのdestfile属性でJARファイル名を指定。basedirでJARに含める資源を指定。manifestでマニフェストを指定する。今回は実行可能JARを作成したいのでマニフェストを指定しているが、普通のJARを作るだけなら指定する必要はない。

これでAntを実行すればJARの作成が行われる。Eclipseでみると以下のような構成になっているはず。


build.xmlを 右クリック > 実行 > Antビルド... をクリックする。下記のようなダイアログが表示されるので dist だけチェックを入れて実行。


HelloAnt/targetフォルダにJARが作成されているので、以下のコマンドを実行して、実行可能JARの作成が正常に行われていることを確認。

java -jar helloant.jar


参考サイト
https://ant.apache.org/manual/index.html

2018年9月22日土曜日

jQuery : jQuery-Validation-Engine でバリデーションを行う

ユーザーがformに入力した値のチェックなんかは、submit後にサーバサイドで行うこともできるけれど、ユーザーからするとちょっと不便な動きだ。何かの入力フォームで、入力を終え、ボタンをクリックして終わった気でいるのに、入力エラーがあるとかなんとか表示されることは結構腹立たしい。

しかも、入力したはずの値がきれいさっぱりなくなってしまっているなんてこともままある。面倒になってそのまま離脱してしまうなんてことは、よくある話なんじゃないだろうか。ユーザー、アプリの開発者、双方にとって不幸なことだ。

そこで入力をフロントでチェックして、submitする前にユーザーに注意を促したいという要求が出てくる。自分でゴリゴリ作りこむのは面倒だけれど、こうした要求に応えてくれる便利なものがいまの世の中には存在する。

それが「jQuery-Validation-Engine」というやつだ。Githubからダウンロードできる。
https://github.com/posabsolute/jQuery-Validation-Engine




いくつかのファイルがダウンロードされるのだが、以下の4つだけを作成中のWebアプリに組み込めば取りあえず動く。

・jquery.validationEngine.js
・jquery.validationEngine-ja.js
・jquery-1.8.2.min.js
・validationEngine.jquery.css

「jquery.validationEngine.js」はjQuery-Validation-Engineの本体となるjs。

「jquery.validationEngine-ja.js」はメッセージを日本語で表示したい場合に使う。もし英語なら「jquery.validationEngine-en.js」を使うなど、様々な言語のものが用意されている。このjsの中身を見ると自作するのもさほど難しくはなさそうである。使いたい言語のものがなければ自作すればいい。また、バリデーションを追加したい場合はこのファイルに追加してやるだけでいいし、デフォルトで用意されているバリデーションもこのファイルを見れば分かる。リファレンスは英語なので読むのがちょっとつらい。

あと「jquery-1.8.2.min.js」なんだけれど、きちんと検証したわけではないが私の環境では 3.3.1 でも問題なく動いている。jqueryのバージョンにはあまりこだわらなくてもいいかもしれない。jQuery-Validation-Engineという名前の通りjQueryに依存しているのだけは確か。

「validationEngine.jquery.css」は、バリデーションメッセージを表示するときに使われるCSS。

デモ用のコードも多数用意されていて、一緒にダウンロードされてくるので、詳しくはそちらを見ればいいと思うが、さわりの部分だけ以下に示しておこうと思う。

ファイルの構成は下記のように配置した。


-+-css-+-validationEngine.jquery.css
 |-js -+-jquery.validationEngine.js
 |     |-jquery.validationEngine-ja.js
 |     +-jquery-3.3.1.min.js
 +-index.html

index.htmlの内容
<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
  <title>jQuery-Validation-Engine</title>

  <!-- JS -->
  <script src="js/jquery-3.3.1.min.js"></script>
  <script src="js/jquery.validationEngine.js"></script>
  <script src="js/jquery.validationEngine-ja.js"></script>

  <!-- CSS  -->
  <link href="css/validationEngine.jquery.css" type="text/css" rel="stylesheet">
  
  <!-- Script -->
  <script>
    $(function(){
      jQuery("#form1").validationEngine();
    });
  </script>
</head>
<body>
  <br/><br/>
  <form id="form1">
    <input type="text" class="validate[required]" />
    <input type="submit" value="submit" />
  </form>
</body>
</html>


16行目~20行目までのスクリプトで、バリデーションを行うフォームを指定。25行目の class="[validate[required]]" の部分で具体的なバリデーションの内容を指定している。今回は必須入力チェックを意味する required を指定した。

これをブラウザで表示すると、テキストボックスとsubmitボタンがあるだけのシンプルな画面が表示される。



テキストボックスからフォーカスアウトすると自動的にバリデーションが行われて、エラー内容を表示してくれる。



submitボタンを押した時も同じで、エラーが検知されるとsubmitされずにエラーが表示される。

他にもメールフォーマットのチェックや半角英数字入力のチェック、最小文字数、最大文字数など多数のチェックを行える。複数のチェックを同時に行いたい場合は class="validate[required,minSize[10],maxSize[100]] といった感じでカンマ区切りで複数指定してあげればよい。

2018年8月29日水曜日

Materialize CSS : アイコンの表示

Materialize CSSの公式ページからテンプレートをダウンロードして開いてみると、アイコンがいくつか表示されているのが分かる。下記の赤枠部分。


この部分のコードを見てみる。

<div class="col s12 m4">
  <div class="icon-block">
    <h2 class="center brown-text"><i class="material-icons">flash_on</i></h2>
    <h5 class="center">Speeds up development</h5>

    <p class="light">We did most of the heavy lifting for you to provide a default stylings that incorporate our custom components. Additionally, we refined animations and transitions to provide a smoother experience for developers.</p>
  </div>
</div>

これは一番左側のアイコンを表示している部分なのだけれど、iタグがアイコン表示の役割をはたしている。class="material-icons" としてアイコンの名称 flash_on を指定することでアイコン表示が行えるのだ。

指定可能なアイコンは結構な数があるので、公式サイトを確認してもらいたい。

例えば上記のコードを以下のように書き換えてみる。

<div class="col s12 m4">
  <div class="icon-block">
    <h2 class="center brown-text"><i class="material-icons">android</i></h2>
    <h5 class="center">Speeds up development</h5>

    <p class="light">We did most of the heavy lifting for you to provide a default stylings that incorporate our custom components. Additionally, we refined animations and transitions to provide a smoother experience for developers.</p>
  </div>
</div>

そしてページを読み込みなおすとアイコンが変わっていることが分かる。自分で画像を探したり、作ったりしなくてもいいのでお手軽だ。


アイコンのサイズを変えることもできる。

<i class="tiny material-icons">android</i>
<i class="small material-icons">android</i>
<i class="medium material-icons">android</i>
<i class="large material-icons">android</i>

tinyが一番小さくて、small、medium、largeと大きくなっていく。



■参考サイト
https://materializecss.com/icons.html

2018年8月28日火曜日

Materialize CSS でモーダルの表示

Materialize CSSを使ったモーダルの表示を行ってみる。Bootstrapに似たような感じで記述することができるのでとっつきやすかった。

■ツリー
css -+- materialize.min.css
js  -+- index.js
     +- jquery-3.3.1.min.js
     +- materialize.min.js
index.html

materialize.min.cssとmaterialize.min.jsはMaterialize CSSの公式サイトからダウンロードができる。また、今回はjQueryも使うのでjquery-3.3.1.min.jsをダウンロードした。index.jsとindex.htmlがモーダル表示のサンプル。

■コード

index.html
<html>
  <head>
    <script src="./js/jquery-3.3.1.min.js"></script>
    <script src="./js/materialize.min.js"></script>
    <script src="./js/index.js"></script>
    <link rel="stylesheet" href="./css/materialize.min.css" />
  </head>
  <body>
    <!-- モーダルを表示するボタン -->
    <button data-target="modalview" class="btn modal-trigger">モーダル表示</button>
    <!-- モーダル画面の定義 -->
    <div id="modalview" class="modal">  <!-- idの値をボタンで設定したdata-targetの値と一致させる -->
      <div class="modal-content">
        <h4>モーダルヘッダ</h4>
        <p>あいうえおかきくけこさしすせそ</p>
      </div>
      <div class="modal-footer">
        <a href="#!" class="modal-close waves-effect waves-green btn-flat">閉じる</a>
      </div>
    </div>
  </body>
</html>

index.js
$(document).ready(function(){
  $('.modal').modal();
});

■参照
https://materializecss.com/modals.html

2018年8月22日水曜日

マテリアルデザインを実現するMaterialize CSS

CSSフレームワークはBootstrapしか使ったことがない。Bootstrapはいいものだけれど、こればかり使っていて少し飽きてしまった。

ということで、Bootstrapに変わるCSSフレームワークは何かないかなと思って探して見つけたのが「Materialize CSS」だ。

Googleが提唱しているマテリアルデザインを比較的簡単に実現できるらしい。

公式サイト:https://materializecss.com/


公式サイトを開いて「Get Started」ボタンをクリックすればダウンロードページに飛ぶ。あとはダウンロードすれば「Materialize CSS」を使うことができる。

少し見たところ、Bootstrapを使ったことがあれば、違和感なく使うことができそうだ。

一から勉強するのはちょっと面倒だと思えば、ダウンロードページをスクロールしていくと、テンプレートが2つほど提供されている。テンプレートをダウンロードして、基本的な使いかたと動きを確認すれば、ある程度までは事足りるんじゃないだろうか。


テンプレートも良く出来ていて、画像と文章だけ差し替えてしまえば、ほとんどそのまま利用できそうな感じだった。




しばらくは、これを使ってみようと思う。

2018年8月6日月曜日

Java コンパイラー・レベルが、インストールされている Java プロジェクト・ファセットのバージョンと一致しません。

Eclipseでコンパイラー準拠レベルを変更したら、「Java コンパイラー・レベルが、インストールされている Java プロジェクト・ファセットのバージョンと一致しません。」というエラーが発生した。



この場合、「ウィンドウ > 設定 > プロジェクト・ファセット」に設定してあるJavaのバージョンをコンパイラー準拠レベルと一致させてやると解決する。

2018年7月18日水曜日

Spring : @Controller、@Service、@Repository、@Component

Springのアノテーション、@Controller、@Service、@Repository、@Componentの4つなのだけれど、いまいち動きの違いがよく分からなかったので調べてみた。

どうやら、基本的には同じ動きをするらしく、これらのアノテーションが付与されたクラスをSpringのDIコンテナにビーンとして登録する。

コントローラ層には@Controller、サービス層には@Serviceというふうになる。アノテーションを見れば役割が分かるので、見た目には分かりやすいではある(それ以上の理解が出来なかった)。

@Controller
コントローラ層のクラスに付与する。リクエストやレスポンスなどのフロントとのやり取りに関わる処理を記述するクラスがこのアノテーションを使用する。

@Service
サービス層、つまりビジネスロジックなどが記述されるクラスに使用する。

@Repository
DAOなどのDBアクセスを担うクラスに使用する。

@Component
上記の3つ以外の役割でDIコンテナに登録しておきたいクラスに使用する。

2018年7月5日木曜日

Spring : トランザクションの管理

Springでは@Transactionアノテーションを使うと簡単にトランザクションの管理を行える。プログラミングによって管理をすることも出来るが、この記事では@Transactionアノテーションについて書いていくことにする。

package example;

import org.springframework.transaction.annotation.Transactional;

@Transactional
public class TransactionalClass {
    public void update(String str) {
        // 何か処理を行う
    }
    public void update2(String str) {
        // 何か処理を行う
    }
}

上記のようにクラスに@Transactionアノテーションを付与すると、そのクラス内のすべてのメソッドがトランザクション制御されることになる。メソッド単位でトランザクション制御したい場合は下記のようにメソッドに@Transactionアノテーションを付与する。

package example;

import org.springframework.transaction.annotation.Transactional;

public class TransactionalClass {
    @Transactional
    public void update(String str) {
        // 何か処理を行う
    }
    public void update2(String str) {
        // 何か処理を行う
    }
}

2018年7月3日火曜日

Spring : @Serviceアノテーション

Springでサービスレイヤを扱うクラスには@Serviceアノテーションをつける。主に業務プロセスを表現するのだけれど、@Serviceクラスの働きについてはいまいち理解していなかった。取りあえずおまじないのようにつけて、それでも動作してしまうものだから気にしてこなかったのだ。

調べてみたら、@Serviceアノテーションが設定されると、クラスがDIコンテナへの登録対象となるらしいことが分かった。

使いかたは以下のようになる。

Serviceクラス
package example;

import org.springframework.stereotype.Service;

@Service
public class ServiceClass {

}

Serviceクラスを呼び出すControllerクラス
package example;

import org.springframework.stereotype.Controller;

@Controller
public class ControllerClass {

    // サービスクラスがDIされる。
    @Autowired
    ServiceClass service;

}

2018年7月1日日曜日

Spring : data.sql が動作しない

Spring Bootではクラスパス直下のdata.sqlが起動時に実行されるらしい。なので、src/resources/data.sqlにSQLを記述して実行してみた。



初期データ投入が手軽になるなあ、と思っていたのだけれど上手く動いてくれない。SQL実行ツールでSQLを実行すると正常に動作したので、記述したSQLそのものに不備があるわけではなさそうだ。

なにか、data.sqlの実行には条件があるのだろうか?

2018年6月28日木曜日

PostgreSQL : テーブル一覧の取得方法

PostgreSQLにおけるテーブル一覧を取得するSQL。

select relname from pg_stat_user_tables

結果はこんな感じになる。

     relname
-----------------
reservable_room
meeting_room
usr
reservation

2018年6月26日火曜日

JPA : 複合主キー

JPAで複合主キーを定義する方法。その前に、まずJPAで単一主キーを定義する方法だが、これは@Idアノテーションを付加してやれば実現できる。

package example;

import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
public class Class1 {
    @Id
    private String id;

    private String col1;

    // Getter/Setterは省略

}

問題は@Idアノテーションはひとつしか指定できないこと。とはいえ、実務上、複合主キーを指定したい場合というのが必ずある。こうした場合は、まず複合主キーを定義するクラスを用意する。@Embeddableというアノテーションを使用する。また、主キーの一意性を確保するためにequalsメソッドとhashCodeメソッドは必ず定義すること。

package example;

import javax.persistence.Embeddable;

@Embeddable
public class Key {

    private Integer id1;

    private Integer id2;

    // Getter/Setter、equals、hashCodeは省略

}

複合主キーを定義するクラスが出来たら、これを使ってEntityクラスを作成する。複合主キーフィールドに@EmbeddedIdを付加する。

package example;

import javax.persistence.EmbeddedId;
import javax.persistence.Entity;

@Entity
public class Class2 {
    @EmbeddedId
    private Key key;

    private String col1;

    // Getter/Setterは省略

}

これで複合主キーを指定するクラスの完成。単一主キーに比べて、ちょっと煩雑。

2018年6月16日土曜日

Spring : リクエストマッピング用のアノテーション

知らなかったのだが、Spring Frameworkのバージョン4.3以降だとRequestMapping以外にリクエストマッピング用のアノテーションが用意されている。

  • @GetMapping
  • @PostMapping
  • @PutMapping
  • @DeleteMapping
  • @PatchMapping

一目瞭然ではあるが、@GetMappingなら@RequestMapping(method = RequestMethod.GET)に対応しているし、@PostMappingには@RequestMapping(method = RequestMethod.POST)が対応しているといった具合である。だから、下記の2つのソースは同じように動作してくれる。

GetMapping使用
package hoge;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping(path="/")
public class MainController {
    @GetMapping(path="/get")
    public @ResponseBody String get() {
        return "Hello World!";
    }
}

RequestMapping使用
package hoge;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping(path="/")
public class MainController {
    @RequestMapping(method = RequestMethod.GET, path="/get")
    public @ResponseBody String get() {
        return "Hello World!";
    }
}

厳密には@GetMappingや@PostMappingは合成アノテーションなので、完全に動作が一致するわけではないかもしれない。実際に@GetMappingの中を覗いてみる。

@GetMapping
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@RequestMapping(method = RequestMethod.GET)
public @interface GetMapping {

    // 色々書かれているけど省略

}

@GetMappingに限らず、他の4つのアノテーションも同じような感じになっている。詳しくはもう少し調べてみないとよく分からない。けれど、これらのアノテーションを使うほうが可読性があがる気がするので積極的に使っていこうと思う。

2018年6月3日日曜日

Spring, JPA, Hibernate

Spring、JPA、Hibernateを使ってDBアクセスする簡単なアプリケーションを作成する。DBはPostgreSQLを使用する。

EclipseでSpring スターター・プロジェクトを選び、下記のようにテンプレートを選択する。


まず最初にapplication.propertiesの編集を行う。このファイルはsrc/main/resources配下に自動的に作成されている。開くと白紙の状態なので、以下のようにHibernateでPostgreSQLに接続するための設定を行う。

application.properties
spring.jpa.database=POSTGRESQL
spring.jpa.hibernate.ddl-auto=create
spring.datasource.url=jdbc:postgresql://localhost:5432/db_example
spring.datasource.username=postgres
spring.datasource.password=postgres

次にエンティティクラスを作成する。

User.java
package spring.jpa;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="usr")
public class User {
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private Integer id;
    private String name;
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

このクラス定義に従って自動的にPostgreSQLにテーブルが作成される。

CRUDを行うクラスの作成。

UserRepository.java
package spring.jpa;

import org.springframework.data.repository.CrudRepository;

public interface UserRepository extends CrudRepository<User, Long> {

}

分かりづらいのだがこのインターフェースを作成することで、自動的に単純なCRUDを行うクラスが生成される。

最後にControllerクラスの作成。

MainController.java
package spring.jpa;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping(path="/")
public class MainController {
    @Autowired
    private UserRepository userRepository;

    @GetMapping(path="/add")
    public @ResponseBody String addNewUser(@RequestParam String name) {
        User u = new User();
        u.setName(name);
        userRepository.save(u);
        return "Saved";
    }

    @GetMapping(path="/all")
    public @ResponseBody Iterable<User> getAllUsers() {
        return userRepository.findAll();
    }
}

ここまで作成したらSpringアプリケーションを実行して、http://localhost:8080/add?name=ユーザー にアクセスしてみる。リクエストパラメータをきちんと設定する。


DBを確認すると、リクエストパラメータで指定したユーザーが作成されていることが分かる。

db_example=# select * from usr;
id |   name
----+----------
  1 | ユーザー
(1 行)

画面でも確認する。
http://localhost:8080/all

PostgreSQL : userテーブルは作成できない

PostgreSQLでは"user"という名称のテーブルを作成することが出来ない。Hibernate使用を前提として下記のようなEntityクラスを作成した。使用するDBは当然PostgreSQLである。

package entity;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class User {
 @Id
 @GeneratedValue(strategy=GenerationType.AUTO)
 private Integer id;
 private String name;
 private String email;
 public Integer getId() {
  return id;
 }
 public void setId(Integer id) {
  this.id = id;
 }
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
 public String getEmail() {
  return email;
 }
 public void setEmail(String email) {
  this.email = email;
 }
}

これで、アプリケーションを実行すれば勝手に"user"というテーブルが出来上がるはずだと思い実行してみたのだが上手くいかない。コンソールを見るとエラーが出ていた。テーブル作成のところでエラーになっているようである。

そこで、@Tableアノテーションを追加してテーブル名を"usr"にしてやったら上手くいった。

package entity;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="usr")
public class User {
 @Id
 @GeneratedValue(strategy=GenerationType.AUTO)
 private Integer id;
 private String name;
 private String email;
 public Integer getId() {
  return id;
 }
 public void setId(Integer id) {
  this.id = id;
 }
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
 public String getEmail() {
  return email;
 }
 public void setEmail(String email) {
  this.email = email;
 }
}

2018年5月29日火曜日

PostgreSQL : データベース一覧を確認する方法

PostgresSQL 10.4 で、データベース一覧を確認する方法。

クエリ
select * from pg_database

結果
  datname  | datdba | encoding | datcollate | datctype | datistemplate | datallowconn | datconnlimit | datlastsysoid | datfrozenxid | datminmxid | dattablespace |               datacl
-----------+--------+----------+------------+----------+---------------+--------------+--------------+---------------+--------------+------------+---------------+-------------------------------------
 postgres  |     10 |        6 | C          | C        | f             | t            |           -1 |         12937 |        549 |          1 |          1663 |
 mrs       |  16393 |        6 | C          | C        | f             | t            |           -1 |         12937 |        549 |          1 |          1663 |
 template1 |     10 |        6 | C          | C        | t             | t            |           -1 |         12937 |        549 |          1 |          1663 | {=c/postgres,postgres=CTc/postgres}
 template0 |     10 |        6 | C          | C        | t             | f            |           -1 |         12937 |        549 |          1 |          1663 | {=c/postgres,postgres=CTc/postgres}

2018年5月28日月曜日

Spring : templatesを階層化する

templatesを階層化する方法。何を言っているかというと、下記のような構成(赤枠の部分)のときにURLとhtmlをマッピングさせる方法を説明していく。


先日作った Spring Security を試すために作ったアプリのコードが作成済みなことを前提としているので、見ておいてもらったほうが何を書いているのか理解しやすいと思う。

src/main/resources/templates/home/home.html

<!DOCTYPE html>

<html>

    <head>

        <meta charset="UTF-8">

        <title>Home</title>

    </head>

    <body>

        <h1>HOME</h1>

        <label><a th:href="@{/greeting}">クリック</a>してください</label>

    </body>

</html>

MvcConfig.java(書き換え)

package springsecurityexample;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class MvcConfig implements WebMvcConfigurer {
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("greeting");
        registry.addViewController("/greeting").setViewName("greeting");
        registry.addViewController("/login").setViewName("login");
        registry.addViewController("/home").setViewName("home/home");
    }
}


registry.addViewController("/home").setViewName("home/home")

この部分が追加したソース。setViewNameのところを見てほしい。home/homeといった感じでスラッシュを入れて階層構造を表現していく。

http://localhost:8080/home にアクセスしてログインすると、home画面が表示されることが分かる。

2018年5月27日日曜日

Spring : Spring Securityでログイン画面を作る

概要


Spring Security を使ってログイン画面の実装を行う。画面構成は以下のようなものとする。


LOGIN

ログイン画面。ユーザーとパスワードを入力して、ログインを行う。ログインを行うとGreeting画面へ遷移する。

Greeting

Greeting画面。Hello <ユーザー名>を画面に表示する。ログアウトすることでLOGIN画面に戻る。


手順


ファイル > 新規 > その他


Spring スターター・プロジェクトを選択して次へ


名前、グループ、成果物、パッケージを書き換える。何でもいいが、ここではspringsecurityexampleとした。


ThymeleafとWebにチェックを入れて完了。


Spring Boot アプリケーションの骨格が出来上がる。今回は以下のような構成のアプリケーションを作成する。


Spring Securityを利用するにはpom.xmlに以下のコードを追加する。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>


pom.xmlに追加したらプロジェクト右クリック > 実行 > Maven installを実行する。


MvcConfig.java

package springsecurityexample;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class MvcConfig implements WebMvcConfigurer {
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("greeting");
        registry.addViewController("/greeting").setViewName("greeting");
        registry.addViewController("/login").setViewName("login");
    }
}

このクラスはURLとhtmlのマッピングを定義している。"/"は"greeting.html"、"/login"は"login.html"にマッピングされる。


WebSecurityConfig.java

package springsecurityexample;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .anyRequest().authenticated()
                .and()
            .formLogin()
                .loginPage("/login")
                .permitAll()
                .and()
            .logout()
                .permitAll();
    }

    @Bean
    @Override
    public UserDetailsService userDetailsService() {
        PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
        UserDetails user = User.withUsername("user")
                            .passwordEncoder(encoder::encode)
                            .password("password")
                            .roles("USER")
                            .build();
        return new InMemoryUserDetailsManager(user);
    }
}

WebSecurityConfigEnableWebSecurity

このアノテーションを指定することでSpring Securityがサポートされたクラスになる。

configure(HttpSecurity)

このメソッドでセキュアなURLとそうでないURLを指定する。今回はセキュアなURLはなし。formLoginに記載のところが、ログイン画面。

userDetailsService()


ユーザー情報を記録する。


src/main/resources/templates/login.html

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>ログイン</title>
    </head>
    <body>
        <div th:if="${param.error}">
            ユーザー名またはパスワードに誤りがあります
        </div>
        <div th:if="${param.logout}">
            ログアウトしました
        </div>
        <form th:action="@{/login}" method=post>
            <div><label> ユーザー名:<input type="text" name="username"/></label></div>
            <div><label> パスワード:<input type="password" name="password"/></label></div>
            <div><input type="submit" value="ログイン"/></div>
        </form>
    </body>
</html>

param.error

ユーザー名やパスワードに誤りがあったときに表示される情報を指定する。

param.logout


ログアウトしてログイン画面に遷移してきたときに表示される情報を指定する。


src/main/resources/templates/greeting.html

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>挨拶</title>
    </head>
    <body>
        <h1 th:inline="text">Hello [[${#httpServletRequest.remoteUser}]]!</h1>
        <form th:action="@{/logout}" method=post>
            <input type="submit" value="ログアウト"/>
        </form>
    </body>
</html>

httpServletRequest.remoteUser


ユーザー情報のユーザー名を取得する。


localhost:8080/loginにアクセスすると、ログイン画面が表示される。


ユーザー名(user)とパスワード(password)を入力してログインをクリック。


Greeting画面が表示される。


一度ログアウトして、今度はURLを指定して直接Greeting画面に飛ぼうとしてみる。
localhost:8080/greeting


Greeting画面ではなく、ログイン画面が表示される。

2018年5月20日日曜日

Spring Boot : 簡単なWebアプリケーションの作成

先日作成した Hello World を表示するアプリケーションでは、Webアプリケーションとしての拡張性や柔軟性がない。Java で作成した Controll クラスから固定の文字列を返却することしか出来ないからだ。

今回は html で作成したテンプレートに Java で作成した Controll クラスから値を渡すようなものを作成する。

ファイル > 新規 > その他


ウィザードから「Spring スターター・プロジェクト」を選択


名前、グループ、成果物、パッケージを「greeting」に書き換える。


テンプレート・エンジンに Thymeleaf を選択し、Webに Web を選択する。ここまで終わったら「完了」をクリック。


パッケージ・エクスプローラーを確認すると、Spring Boot アプリケーションの骨格が出来上がっている。


まずは Controller クラスの作成。

package greeting;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class GreetingController {
    @RequestMapping("/greeting")
    public String greeting(@RequestParam(name="name", required=false, defaultValue="World") String name, Model model) {
        model.addAttribute("name", name);
        return "greeting";
    }
}

@Controller
Controller クラスであることを示すアノテーション。

@RequestMapping
ここでは /greeting に greeting メソッドをマッピングしている。

@RequestParam
リクエストパラメータの設定を行うアノテーション。パラメータとして name を指定。required を false としているので、name パラメータは省略できる。省略した場合の値は defaultValue に設定してある World となる。

次にテンプレートとなる html を作成する。src/main/resources > templates 配下に greeting.html を作成する。

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html" charset="UTF-8">
    <title>挨拶</title>
</head>
<body>
    <p th:text="'Hello ' + ${name} + '!'" />
</body>
</html>

プロジェクトを右クリック、実行 > Spring Boot アプリケーション をクリックでアプリケーションを実行する。

http://localhost:8080/greeting にアクセスすると作成したWebアプリケーションが表示される。


name パラメータを指定してみる。
http://localhost:8080/greeting?name=Hitoshi