20200730のJavaに関する記事は12件です。

Java日記

⭕️Spring⭕️
今日勉強したことのまとめを少しだけ!

JSP(view)でよくあるフォームタグ!1行目のmodelAttributeとはなんぞやと。。。

1<form:form modelAttribute="□□□">
2
3<p><form:input path="id" /></p>
4<p><form:input path="name" /></p>
5
6<input type="submit" value="登録" />
7
8</form:form>

□□□の部分には、3,4行目で送るid,nameがあるModel名(セッター、ゲッターがたくさんあるやつ)を指定!(頭文字は小文字にするのがらしいよ)

Q:頭文字を小文字にしたら、Modelの名前と違うのになっちゃうんじゃないの?

A:
例えば、上記のModel名をMemberModelだとして、
ControllerのdoGETメソッドで

model.addAttribute("memberModel",new MemberModel());

と記述。(上手く説明できないけど、必要みたいなんだ。こいつが使いたいidとnameを持ってるから。。。)

これの第一引数のmemberModelを使うから

フォームタグのmodelAttributeの値は、Modelと同じ名前で頭文字が小文字になるみたい!

もし間違っていること書いていたら、教えていただけると嬉しいです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

コーディング面接練習サイト「Pramp」を使ってGAFAの面接に挑む

はじめに

コーディング面接というものをご存知でしょうか?

コーディング面接とはGAFAなどをはじめとする海外のTech系企業などで広く行われている面接で,データ構造やアルゴリズム,システムデザイン等の知識を問うものです.
面接 - Google

Googleで行われるようなコーディング面接は,

  • 45分程度の時間内に
  • データ構造やアルゴリズムの基礎に関する問題を
  • 面接官と話し合いながら(多くの場合英語で)
  • ホワイトボードにコードを書いて解く

といった特徴があります.

データ構造とアルゴリズムの問題自体は,Cracking Coding Interviewのような書籍やLeetcodeのようなサイトを使って練習を積むことができます.

しかしコーディング面接の最大の特徴は「面接官とコミュニケーションを取りながら」問題を解くことです.これは一人で本を読んで問題を解いたり競技プログラミングに取り組むのとはまた違った訓練が必要となります.またGAFAのような海外Tech企業を受ける場合は面接が英語で行われる場合も多いため,「自分の考えを英語で説明する」力も求められます.

それではどのように対策するのか.

もしコーディング面接の経験がある知り合いがいるなら,その人に模擬面接をしてもらうこともできますが,「そんな知り合いいないよ!」という方も多いと思います.しかし世の中は便利なもので,面接の練習ができるサービスがいくつかあります.

そのうちの1つで,かつ日本国内で無料で使えるのがPrampです.

Prampについて日本語で説明した記事があまりなかったので,(私も5回ほど使ってみた程度ですが)簡単に紹介していきたいと思います.

Prampとは

pramp

https://www.pramp.com

Prampとはコーディング面接練習用のサイトで,無料で登録・利用することができます.面接対策をする世界中の人が使っており,コミュニケーションは基本的に英語で行われます.

最大の特徴は,利用者が面接官と候補者両方の役割を交代して行うことです.
Prampには専門の面接官がいるわけではなく,面接の練習をしている利用者同士が自動的にマッチングされ,半分ずつの時間でお互いに問題を出し合います.
面接官を体験することで学ぶことも多く,面接への理解が深まるというメリットがある一方,面接官をやる分の負担が増えたり,あまり面接官が得意でない候補者とマッチングして面接がうまくいかない可能性があるというデメリットもあります.

「わざわざ面接官役なんてやりたくない!」という方もいると思います.気持ちはわかりますが,私が調べた限り無料の面接練習サイトはこれしかなかったので仕方ありません.

Prampを使ってみる

登録

まず,サイトに行ってみます.
スクリーンショット 2020-05-03 16.47.51.png

「Start Practicing」を押すと,名前とアドレス等を入力する画面になるので,入力するとメールが届きます.メールのリンクをクリックします.

スクリーンショット 2020-05-03 16.51.49.png

その後進んでいくと,住んでいる地域,現在のスキル,使用する言語などを入力します.これらの情報はあとでプロフィールから変更できるので適当でも構いません.

スクリーンショット 2020-05-03 16.52.51.png
スクリーンショット 2020-05-03 16.53.00.png
スクリーンショット 2020-05-03 16.53.14.png
スクリーンショット 2020-05-03 16.53.29.png

最後に練習の日程を聞かれます.「もう日程を登録するの?」と驚くかもしれませんが,これをしないと先に進めません.あとで変更,キャンセルができますのでとりあえず適当に選んでください.

スクリーンショット 2020-05-03 16.53.50.png

これで登録完了です!ダッシュボードに面接の日程が表示されていると思います.

スクリーンショット 2020-05-03 16.54.29.png

練習日程を決める

続いて練習日程を決めていきます.

ダッシュボードの「Start a practice session」をクリックすると,まず問題の種類を聞かれます.

スクリーンショット 2020-05-03 16.53.14.png

一般的なコーディング面接向けの練習であれば「Data structure and algorithms」で良いと思います(私もそれしかやったことがありません).

次に日程を聞かれます.

スクリーンショット 2020-05-03 16.53.50.png

日程カレンダーは2時間おきに時間を選択できます.
カレンダーにはところどころ色が付いている時刻がありますが,どうやら緑色->黄色->無色の順でマッチングしやすい時間帯のようです.ただ私の経験上,無色の時刻を選んでもマッチングできなかったことはないのであまり気にしなくていいかもしれません.

予定はダッシュボードで確認できます.変更,キャンセルしたいときは予定の横のボタンで行うことができます.
なお,予定を決めたからといって既に面接相手が決まっているわけではなく,開始時刻になってからマッチングが行われる仕組みのようなので,遠慮なく変更,キャンセルして大丈夫だと思います.

面接準備

面接のスケジュールを立てると,横に「Question You'll ask」という項目が現れます.これはあなたが面接官役のときに相手に出題する問題です.Prampでは出題する問題があらかじめ決められているので自分で考える必要はありません.面接の前にこの問題を予習しておき,面接官としてうまく振る舞えるように準備しておきます.
なお,初回はこの問題を自分で選ぶことはできません.3回くらい練習をすると,過去に相手から出題された問題の中から次に出す問題がランダムに選択されるようになるので,(キャンセルと再選択を繰り返せば)好きな問題を選べるようになります.

問題をクリックすると次のような画面になります.

スクリーンショット 2020-05-03 17.31.28.png

右側に「Question」「Hints」「Answer」の欄があり,問題文とヒント,答えを見ることができます.解答者からは問題文のみを見ることができ,ヒントと解答は見られません.面接前にこの問題を理解し,必要なら相手にヒントを与えられるようになっておきましょう.

このエディタでは,基本的には指定の入力に対し正しい出力を返す関数を実装すれば良いです(Leetcodeと似ています).
下の「Run Code」は好きな入力で挙動を確認できます.関数を実装したらprint文などを使って出力を確認できます.
スクリーンショット 2020-05-03 17.39.33.png

一方「Run tests」は用意されたテスト入力に対し正しい答えを返すかジャッジが行われます.全てパスすると緑色に,ミスがあると赤色になります.
スクリーンショット 2020-05-03 17.43.39.png

面接開始

予定の時刻の5分前になると,ダッシュボードのスケジュールの横に「Join session」というボタンが現れます.そこをクリックすると,マッチング待機画面になります.

経験上遅くとも開始予定時刻から5分以内にはマッチングができ面接に移ります.面接の様子はPramp公式がYoutubeにあげているのでそちらを見た方が雰囲気がつかめると思います.

Pramp - YouTube

デフォルトはカメラでお互いの顔が見える状態ですが,カメラをオフにして音声のみにすることもできます(私は基本的に音声のみで練習していました).
自分と相手どちらがはじめに問題を解くかは自動的に割り振られます.問題文は表示されているので,まずはそれを読むところから始め,相手とコミュニケーションを取りながら問題を解いていきます.解き終わったら左上の「Swap roles」のボタンで解答者を交代します.
解答時間の目安はお互い30分ずつです.1時間経っても練習を続けることはできますが,2時間経過すると自動的に終了となるようです.

なお,うっかり予定していた練習をすっぽかしてしまった場合も特に罰則などはないので安心してください.

面接後

お互いの練習が終了したら面接を終了します.終了後は相手へのフィードバックを記入する画面に移ります.相手のコーディングスキルやコミュニケーションスキルに付いて簡単に評価を書きましょう.

終了後はダッシュボード上で,自分が解いた問題と相手からのフィードバックを確認することができます.

スクリーンショット 2020-05-03 18.41.24.png

フィードバックはこのような形で見ることができます.大抵皆さん優しいので星3つか4つくれます.

スクリーンショット 2020-05-03 18.40.55.png

また,「Request Intro」というボタンがあるのですが,双方がこれを押すとマッチングした相手の連絡先を知ることができるようです.素晴らしいスキルを持った相手だったら情報交換してみるのもいいかもしれません.

感想

  • 日本でPrampなどの練習用サービスを使うのは,かなり面接準備を進めてきた人が多いと思いますが,海外では初学者も使っている裾野の広いサービスのように感じました.例えば私がマッチングした人の中には「Dynamic Programmingをほとんど知らない」と言っていた人もいたので,「レベルが高すぎるのではないか」という不安はあまり感じなくて良いと思います.

  • 少なくとも私が解いた問題はそこまで難しいものはありませんでした.感覚的には 「Leeetcodeのmediumの中でも簡単なほうの問題」くらいの難易度が多かったです.

  • 英語でコミュニケーションを取るという点においてはかなり練習になりました.私は英語ペラペラではないため聞き取れない時も多かったですが,具体例で説明してもらったりしながらなんとか理解していました.本番の面接も英語の場合は,こういった練習をやっているかやっていないかで精神的な負担がかなり違うと思います.

  • 大切なのは「まだスキルが十分でないからやめておこう」と思わないことです.スキルが十分でないから練習するのであり,わからないことがあったり詰まったりするのは当たり前なので,とりあえず一度やってみるのはありだと思います.

皆さんもPrampを初めてGAFAの面接突破を目指してみてはいかがでしょうか!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Spring Bootで書籍管理Webアプリを作ろう part2

はじめに

どうも、プログラミング勉強中の大学生、@Ikuto19です。今回は前回の続き(part1)からやっていこうと思います。前回のおさらいを簡単に説明した後、作成手順を解説して実際にアプリを作っていきます。

前回のおさらいと解説

前回について

part1では、書籍管理アプリの作成のための準備と流れを掴んでもらうためにテストアプリの作成と公開をしました。具体的には、Spring Frameworkを使うためのツールのインストールやHerokuへのアカウント登録などを行いました。

これ以降の注意点!!

このpartからコードやアノテーションの役割について説明していきますが、僕自身Spring Frameworkに触れるのが初めてです。要するに初心者なので、詳しい説明はできません。あくまで僕の解釈をざっくり説明することになるので、この記事を見てくださっている同じ初心者の方は鵜呑みにしないでください。大まかには合っているが、厳密には違うなんてことがあると思うので、ご自身でも調べてください。逆に上級者の方は前回でも言った通り、どんどん指摘してください。

前回のコードの解説

App.java

このApp.javaがwebアプリの実行を行ってくれています。なので、このメイン関数を含んでいなければ、アプリは起動しません。クラス名はなんでもいいんですが、僕はAppと名付けました。
もし、クラス名を違うものにするなら中身の「App.class」を「クラス名.class」にしてください。

@SpringBootApplicationについて、Springドキュメント日本語訳の「6.@SpringBootApplication アノテーションの使用」では以下のように書かれていました。

@EnableAutoConfiguration: Spring Boot の自動構成メカニズムを有効にする
@ComponentScan: アプリケーションが配置されているパッケージで @Component スキャンを有効にする (ベストプラクティスを見る)
@Configuration: コンテキストに追加の Bean を登録したり、追加の構成クラスをインポートしたりできます。

僕なりにまとめて解釈すると、こんな感じかと思いました。

  • @SpringBootApplication → 以下の3つの機能をまとめたもの
    • @EnableAutoConfiguration → 自動で構成するかどうか
    • @ComponentScan → コンポーネントスキャンを行う
    • @Configuration → Beanへの登録またはクラスのインポート
App.java
package com.app;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class App {
    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }
}
IndexController.java

IndexController.javaはMVCモデルにおけるControllerにあたるものです。
Controllerはユーザーの入力に基づいて、ModelとViewを制御するというものですが、今回はURLが"/"のときにindex.htmlを表示するようにしています。
「model.setAttribute("message", message)」で、呼び出されたhtmlファイルの中でmessageに格納されている文字列を扱うことができる。

  • @Controller → Controllerとなるクラスに付与
  • @GetMapping("(URL)") → "(URL)"にGETリクエストを行う
IndexController.java
package com.app.controller;

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

@Controller
public class IndexController {

    @GetMapping("/")
    public String getIndexPage(Model model) {
        String message = "Hello, World!!";
        model.addAttribute("message",message);
        return "index";
    }
}
index.html

「xmlns:th=~」の部分はテンプレートエンジンであるThymeleafを使うためのものだと解釈しました。これによって、controllerから値や文字列をHTML上でも扱うことができる。
「th:text="${message}」で格納されているmessageの中身(文字列)を表示できる。

index.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<meta charset="UTF-8">
<head>
<title>テストアプリ</title>
</head>
<body>
    <p th:text="${message}"></p>
</body>
</html>
Procfile

Java:Spring BootアプリのHerokuデプロイを試してみました
こちらの方の書き方をそのまま真似ました。\$JAVA_OPTSや--server.port=$PORTについて調べたのですが、あまりヒットしなくてわかりませんでした。
ざっくりですが、Heroku Dev CenterのThe Procfileを見る限り、「アプリのタイプ:実行コマンド」の書き方をするんだと勝手に思っています。

Procfile
web: java $JAVA_OPTS -jar target/*.jar --server.port=$PORT

作成手順

  1. プロジェクトの作成
  2. ホーム画面の実装
  3. DB認証によるログイン画面と画面遷移の実装
  4. ホーム画面から書籍検索・書籍情報表示・書影表示のページへの画面遷移実装
  5. 書籍検索後、DBから登録・削除を行う機能の実装
  6. 動作確認
  7. CSSの適用

プロジェクト作成

前回の要領でプロジェクトを作成します。プロジェクト名は「BookManagement-webapp」で、それ以外は前回と同じ設定で作成します。ただし、BookManagementWebappApplication.javaを削除してください。

ホーム画面の実装

新規ファイルの作成

App.java

com.appパッケージに以下のApp.javaを作成して配置します。先ほど説明した通り、このクラスが実行されることでSpringアプリケーションが起動します。

App.java
package com.app;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class App {
    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }
}
index.html

templatesフォルダにホーム画面となるindex.htmlを作成します。ホーム画面は以下の機能を持ちます。

  • APIによる書籍の情報の取得(operateCollate.html)
  • データベースの書籍情報の取得して表示(operateCheck.html)
  • データベースの書影を取得して表示(operateCheck.html)
indexhtml
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<meta charset="UTF-8">
<head>
<title>書籍管理アプリ</title>
</head>
<body>
    <div class="main_container">
        <div class=title>
            <h1>書籍管理 Web Application</h1>
        </div>
        <div class="middle_container">
            <div class="contains collate">
                <form method="get" action="operateCollate">
                    <input type="text" class="texts" name="isbn" value=""
                        placeholder="ISBN コード"> <input class="submit"
                        type="submit" value="書籍照合">
                </form>
            </div>
            <div class="contains flexbox">
                <form method="get" action="operateCheck">
                    <input class="submit" type="submit" value="書籍情報表示">
                </form>
                <form method="get" action="operateCover">
                    <input class="submit" type="submit" value="書籍表紙表示">
                </form>
            </div>
        </div>
    </div>
</body>
</html>

実行確認

以下のように表示されると思います。
スクリーンショット 2020-07-29 16.49.38.png

Spring SecurityのDB認証を用いたログイン実装

次にSpring SecurityのDB認証によるログインを実装していきます。修正するファイル(青色)、追加するファイル(赤色)は下記のようになります。このログイン認証はSpringSecurityで認証機能を実装①SpringSecurityで認証機能を実装③を参考にさせていただき、必要に応じて変更し作成します。なので、コードはほぼ同じかと思います。また、各ファイルに書かれているコメントはこの記事を書いた人のものなので削除しました。ですので、コメントを見たい場合はこの記事を読んでください。
スクリーンショット 2020-07-29 23.24.43.png

新規ファイルの作成・既存ファイルの修正

WebSecurityConfig.java

このクラスでセキュリティに関する設定を行っています。configure-WebSecurityのconfigureメソッドで必要なファイルやフォルダを認証から除いています。configure-HttpSecurityのconfigureメソッドでは、認証成功時や失敗した時の画面遷移やアクセスできるユーザーの設定を行っています。最後のconfigure-AuthenticationManagerBuilderのconfigureメソッドで認証に関する設定を行っています。

  • アノテーション

    • @EnableWebSecurity → Spring Securityを有効にする
    • @Autowired → 自動でオブジェクトを格納
    • @Bean → DIコンテナに登録する
    • @Override → オーバーライドを示す
  • 各メソッドのシグネチャ

    • configure-WebSecurity → Web全体のセキュリティ設定
    • configure-HttpSecurity → 各URLのセキュリティ設定
    • configure-AuthenticationManagerBuilder → 認証関係の設定
WebSecurityConfig.java
package com.app.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
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.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;

import com.app.service.UserDetailsServiceImpl;

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsServiceImpl userDetailsService;

    //パスワードの暗号化
    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        return bCryptPasswordEncoder;
    }

    //CSS・Javascriptなどや外部の画像ファイルを扱えるようにしている
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers(
                "/images/**",
                "/css/**",
                "/js/**"
                );
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception{
            http
                .authorizeRequests()
                .anyRequest().authenticated()
                .and()
            .formLogin()
                .loginPage("/login") //ログインページのURL
                .loginProcessingUrl("/login")
                .usernameParameter("username")
                .passwordParameter("password")
                .defaultSuccessUrl("/index", true) //認証成功によって遷移するURL
                .failureUrl("/login?error") //認証失敗によって遷移するURL
                .permitAll() //全ユーザで接続可能
                .and()
            .logout()
                .logoutUrl("/logout") //ログアウトページのURL
                .logoutSuccessUrl("/login?logout") //ログアウト成功後のURL
                .permitAll();
    }

    @Autowired
    public void configure(AuthenticationManagerBuilder auth) throws Exception{
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }
}
LoginController.java

URLが"/login"のとき、login.htmlを表示する。

LoginController.java
package com.app.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;

@Controller
public class LoginController {
    @GetMapping("/login")
    public String getSignUp(Model model) {
        return "login";
    }
}
LoginUser.java
  • アノテーション
    • @Entity → エンティティクラスに付与
    • @Table(name = "(テーブル名)") → アクセスするデータベースのテーブル名を指定
    • @Column(name = "カラム名") → テーブルのカラム名を指定
    • @Id → プライマリキー(今回はInteger型)
LoginUser.java
package com.app.entity;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "user")
public class LoginUser {

    @Column(name = "user_id")
    @Id
    private Long userId;

    @Column(name = "user_name")
    private String userName;

    @Column(name = "password")
    private String password;

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Long getUserId() {
        return userId;
    }

    public void setUserId(Long userId) {
        this.userId = userId;
    }
}
LoginUserDao.java

findUserメソッドでデータベースへアクセスし、ユーザー名が該当するユーザーオブジェクトを返します。

  • @Repository → DBへアクセスするクラスに付与
LoginUserDao.java
package com.app.repository;

import javax.persistence.EntityManager;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.app.entity.LoginUser;

@Repository
public class LoginUserDao {

    @Autowired
    EntityManager em;

    public LoginUser findUser(String userName) {

        String query = "";
        query += "SELECT * ";
        query += "FROM user ";
        query += "WHERE user_name = :userName ";

        return (LoginUser)em.createNativeQuery(query, LoginUser.class).setParameter("userName", userName).getSingleResult();
    }
}
UserRepository.java
UserRepository.java
package com.app.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import com.app.entity.LoginUser;

/*
 * <エンティティクラス, IDタイプ>
 */
@Repository
public interface UserRepository extends JpaRepository<LoginUser, Integer>{}
UserDetailsServiceImpl.java
  • @Service → ビジネスロジックを行うクラスに付与
UserDetailsServiceImpl.java
package com.app.service;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
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.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import com.app.repository.LoginUserDao;
import com.app.entity.LoginUser;

@Service
public class UserDetailsServiceImpl implements UserDetailsService{

    @Autowired
    private LoginUserDao userDao;

    @Override
    public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {

        LoginUser user = userDao.findUser(userName);
        if (user == null) throw new UsernameNotFoundException(userName + "はデータベースに存在しません.");

        List<GrantedAuthority> grantList = new ArrayList<GrantedAuthority>();
        GrantedAuthority authority = new SimpleGrantedAuthority("USER");
        grantList.add(authority);

        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        UserDetails userDetails = (UserDetails)new User(user.getUserName(), encoder.encode(user.getPassword()),grantList);

        return userDetails;
    }
}
index.html

以下のものを「class="contains flexbox"」のdivタグの中の一番下に配置します。

index.html
<form  method="post" id="logout" th:action="@{/logout}">
        <button type="submit">ログアウト</button>
</form>
login.html
login.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
    xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
<meta charset="UTF-8">
<title>LoginPage</title>
</head>
<body>
    <div class="main_container">
        <p th:if="${param.error}" class="message">※ユーザー名かパスワードが違います</p>
        <p th:if="${param.logout}" class="message">※ログアウト済みです</p>
        <div class="login_container">
            <form th:action="@{/login}" method="post">
                <div class="buttons username">
                    <i class="fas fa-users"></i> <input class="texts" type="text" name="username"
                        placeholder="username" />
                </div>
                <div class="buttons pass">
                    <i class="fas fa-lock"></i> <input class="texts" type="password" name="password"
                        placeholder="password" />
                </div>
                <div class="submitButton">
                    <input class="submit" type="submit" value="ログイン" />
                </div>
            </form>
        </div>
    </div>
</body>
</html>
application.properties
application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/manageBook
spring.datasource.username=(mysqlのユーザー名)
spring.datasource.password=(mysqlのパスワード)
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.jpa.database=MYSQL
spring.jpa.hibernate.ddl-auto=update
pom.xml

以下を追加で記述します。

pom.xml
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>

データベースの構築

インストール済みのMySQLに以下のコマンドを実行していきます。

terminal
$ mysql -u (mysqlのユーザー名) -p
Enter password: (mysqlのパスワード)
mysql> create database manageBook;
mysql> use manageBook
mysql> create table user(user_id int auto_increment,user_name varchar(256),password varchar(256),PRIMARY KEY(user_id));
mysql> insert user value(1,"(好きな名前)","(好きなパスワード)");
mysql> select * from user;

最後の「select * from user;」でテーブルの中身を確認すると、下記のようになっていると思います。
確認できたら、quitコマンドでログアウトしてください。

terminal
mysql> select * from user;
+---------+-----------+---------------+
| user_id | user_name | password      |
+---------+-----------+---------------+
|       1 |(好きな名前) | (好きなパスワード)|
+---------+-----------+---------------+
1 row in set (0.04 sec)

mysql> quit;
Bye

実行確認

Spring アプリケーション実行後、http://localhost:8080/login へアクセスして確認してください。おそらくログインできるようになっているかと思います。

終わりに

今回はここまでにします。次回で最後で、ホーム画面からの遷移やDBアクセス関係の機能の実装をします。
次回へ続く(part3) > 近々投稿

参考サイト

Spring Bootでコンポーネントスキャンできなかった初歩的なミス | エンジニア2ねんせいのきろく

SpringSecurityで認証機能を実装① - Qiita

Spring Bootを触ってみたメモ - Qiita

Spring Boot アノテーション集

Spring BootでConfigurationクラスを用いてBean定義する方法 - Reasonable Code

Spring Security 使い方メモ 基礎・仕組み - Qiita

Spring BootでWebセキュリティを設定しよう (1/2):CodeZine(コードジン)

JPA (Java Persistence API)のアノテーション

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PlantUML を Visual Studio Codeで使う

環境設定が重要
- JAVAのインストールと,PATHの設定
Oracle Java https://java.com/ja/download/win10.jsp のパスの設定(一応,Java SE Development Kit 14 もインストールした[2])

VSC Plugin PlantUML jebbs 2.13 のインストール
image.png

image.png
設定は特になにも変更していないが,stting.jsonは余計なものをいれないように注意する

-かかった時間 14:40から19:40なので,5時間くらい試行錯誤した。

参考文献
[1] https://proengineer.internous.co.jp/content/columnfeature/5205
[2] https://eng-entrance.com/java-install-jdk-windows

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Java]STSの導入からローカルホストでの動的ページの確認までの流れ(3/3)

前回の続きです。

記事は3つに分割しています。
1. MVCモデルの説明
2. STSの導入からPleiadesによる日本語化まで
3. プロジェクトの作成からローカルホストでページを確認するまで ←今ここ
となっています。

今回はプロジェクトの作成からローカルホストでページを確認するまでとなります。

プロジェクトの作成

今回はSpring-Bootでプロジェクトを作成します。一からSpringアプリケーションを作成する場合、たくさんの設定や機能を自分で組み上げなければいけませんが、Spring-Bootではその辺りを自動で行ってくれます。

STSのメニューからファイル>新規>Springスターター・プロジェクトと進みます。
project01

プロジェクトの作成ウィンドウが表示されるので、型の設定をMavenからGradleに、パッケージはJarからWarに変更します。
GradleはBuildshipが2.xか3.xか選べますが、基本的には3.xで良いと思います。
Gradleはビルドを自動化してくれるシステムです。.gradleファイルにビルド時の設定を記載すると、その設定の通りにWar(Jar)ファイルをビルドしてくれます。
自動化システムはMavenやAntといったものもあります。
project02

それ以外は特に変更せず次へ。
依存関係の設定画面が出てきますのでThymeleafとSpring Webを選択。
project03

完了ボタンを押すことで作成ウィンドウが閉じ、最初の画面に戻ると思います。
しばらく待つと左のパッケージエクスプローラーにプロジェクトが作成されます。今回であれば大きく変えたところはないので"demo"という名称になっているはずです。
project04

HTMLファイルの作成

次に表示するHTMLファイルを作成します。
といってもコードを一から書く必要はありません。STSには各種ファイルのテンプレートが用意されています。
プロジェクトツリーの中からsrc/main/resourcesというフォルダを開くと、中にtemplatesというパッケージがあるかと思います。
そちらを右クリックして新規>その他と進みます。
project05

すると新規作成のためのウィンドウが表示されますので、その中からWeb>HTMLファイルを選択して次へ。
project06

親フォルダを選択する画面に移りますがそちらは触らず、ファイル名だけデフォルトのNewFile.htmlからindex.htmlに変更します。そして完了ボタンをクリック。
project07

するとtemplatesの直下にindex.htmlファイルが作成されます。ページの表示に必要な部分は全て最初から書き込まれていますので、追加で"Hello, World!"と表示されるようにしておきましょう。
project08

最後にプロジェクトを右クリックして実行>SpringBootAppを選択します。
project09

下のコンソール画面でいくつかログが流れていった後に、"Started DemoApplication in xxx seconds"と表示されていれば無事にローカルホストが立ち上がっているはずです。
project10

ページの確認

ページを確認するためには、お好きなブラウザのアドレスバーに
http://localhost:8080
と打ち込みます。
project11
ちゃんと表示できていますね。

ローカルホストはそのままだと立ち上がったままなので、ページを確認したら停止ボタン(画像の青い丸)を押して停止させましょう。上と下のどちらのボタンを押しても問題ありません。
project12

以上がSTSを導入してWebページを表示するまでの簡単な流れになります。
本当はライブラリを追加したりプロパティを変更したりとやらなければならないことがありますし、データベースへの接続も必要ですので、また今度記事にしたいと思います。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Java]STSの導入からローカルホストでの動的ページの確認までの流れ(2/3)

前回のMVCモデルの説明からの続きです。

記事は3つに分割しています。
1. MVCモデルの説明
2. STSの導入からPleiadesによる日本語化まで ←今ここ
3. プロジェクトの作成からローカルホストでページを確認するまで

今回はSTSの導入からPleiadesによる日本語化までです。

使用ツール

  • SpringToolSuite 4.7.0 (Eclipseのプラグインとして使用)
  • Thymeleaf

STSはJavaのフレームワークの1つであるSpringを使うためのものです。そのSTSを導入するためにいくつかある統合開発環境(IDE)の中から今回はEclipseを選びました。
IDEというのはコードを書いたりコンパイルしたりデバッグしたりとった機能を提供します。Eclipse以外にもVSCodeやTheiaといったIDEにも導入できます。
ThymeleafはHTMLのテンプレートエンジンです。

STSの導入と起動まで

公式ページからSTSをダウンロードします。IDEは一番上のEclipse用を選びます。
download01

ダウンロード先は特に指定していなければ各自のダウンロードフォルダになっているはずです。そこに"spring-too-suite-4"という名前から始まるjarファイルがあるので実行します。
download02
PC画面の左上あたりにこんなウィンドウが出てきていれば正常にインストールが進んでいます。

インストールが終了するとSTSのフォルダが作成されていると思います。
今回はダウンロードフォルダにそのまま入れていますが、他のフォルダに移しても構いません。
download03

フォルダに入るといくつかファイルがあります。その中でもSTSのロゴが表示されている.exeファイルが本体です。
このファイルからSTSが起動できます。
download04

起動するとランチャーが出てきてワークスペースを指定するよう言われますので、あらかじめどこかにフォルダを作成しておきましょう。
今回はデスクトップに"HelloWorld"というフォルダを作成し、そこをワークスペースに指定しています。
launch

起動ボタンをクリックするとSTSの作業画面が表示されます。
この時点でプロジェクトを作成することはできますが、今回はPleiadesというEclipse用のプラグインを導入して日本語化します。
home01

Pleiadesを導入して日本語化する

まず準備としてSTSを開いている場合は閉じておきましょう。
Pleiadesはこちらのページからダウンロードすることができます。
ページには上段にAll in Oneが、中段にプラグインがダウンロードできるリンクが並んでいると思いますが、すでにEclipseをSTSという形でインストールしているため、プラグインだけで大丈夫です。
今回はWindowsなので一番左のボタンからダウンロードします。
pleiades01

ダウンロードが終わるとまたダウンロードフォルダに.zipファイルができているので解凍します。
画像は上が解凍前、下が解凍後です。
pleiades02

解凍後のフォルダに入るとまたいくつかファイルがあります。その中で"setup.exe"というファイルを実行します。
pleiades03

実行するとセットアップのウィンドウが表示されます。
PleiadesはEclipseだけではなく、Android StudioなどほかのIDEでも使用することができます。
この中で日本語化するアプリケーションの選択ボタンをクリックします。
pleiades04

ファイルの選択ウィンドウが出てくるので、すでにインストールされているSTSのフォルダの実行ファイル(SpringToolSuite4.exe)を選択します。
pleiades05

選択後は元のセットアップウィンドウに戻ります。この時点で日本語化するアプリケーション、Pleiadesが配置されるディレクトリ、Pleiadesの設定が追加されるファイルが記入されていると思います。
あとは右下の日本語化するボタンをクリックすることでSTSの日本語化が始まります。
pleiades06

セットアップウィンドウが閉じたらSTSを起動しましょう。最初のランチャーですでに日本語化されていることがなんとなく分かるかと思います。
プロジェクトのフォルダは上で作ったものと同様、デスクトップのHelloWorldを選択します。
Pleiadesが上手く実行されていれば作業画面も日本語化されているはずです。
home02

ここまでSTSのダウンロードからPleiadesによる日本語化まで進めました。
次は実際にプロジェクトを作成し、ローカルホストでページを確認するとこまでいこうと思います。

次回:プロジェクトの作成からローカルホストでページを確認するまで

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Java]STSの導入からローカルホストでの動的ページの確認までの流れ(1/3)

会社の研修ではだいたい2~3人ぐらいのグループで仮想プロジェクトを作成することになっています。
プロジェクトはSpringToolSuite(STS)を使うのですが、研修生向けマニュアルのようなものが今までなかったので、導入からローカルホストを立ててWebページを確認するまでをまとめました。
初めてプログラミングの仕事に就く人向けですので、初歩的なところも端折らず書いています。

記事は3つに分割しています。
1. MVCモデルの説明 ←今ここ
2. STSの導入からPleiadesによる日本語化まで
3. プロジェクトの作成からローカルホストでページを確認するまで

STSをダウンロードする前に、まずはWebアプリケーションの設計思想であるMVCモデルの説明から始めます。
最初から座学かよと思わず少しだけお付き合いください。

MVCモデルとは

MVCモデルというのは、一言で表すとWebアプリケーションの設計思想の1つです。
Webアプリケーションを作る際に開発者が思い思いに実装すると、その人にしか理解できなかったりバグが発生したりとトラブルになりがちですし、クライアントの側から直接データを参照するのはセキュリティの面でもよろしくありません。
そのため、要所々々で何をどう動かすかのルールを決めて実装しようという話です。
それぞれの役割は以下の通り。

M : Model
演算やデータ層へのアクセスなど、実際に何か処理を行う部分。ロジックやサービスという名前が付く。
Controllerによって呼び出されて演算結果やデータベースから取得したデータなどを返す。
V : View
Controllerによって生成されクライアントに送られる。名前の通り見た目の部分であり、グラフや図のほか、Webページに必要なHTMLファイルもここに含まれる。
C : Controller
HTTPリクエストの内容を確認して適切なModelを呼び出し、演算結果やデータなどをViewとして生成してクライアントに送り返す(HTTPレスポンス)するもの。

例)
クライアントがWebページでキーワードを入力する

Controllerがキーワードを受け取ってデータベースにアクセスするためのModelに飛ばす

Modelがデータベースにアクセスし、キーワードに紐づくデータを取得してControllerに返す

ControllerはViewとしてHTMLファイルを作成し、ファイル内にModelから取得したデータを記載してクライアントに送る

Webページが遷移してキーワードに紐づいたデータの一覧が表示される

MVCモデルはあくまでも設計思想であり、開発において明示的にMVCモデルだと設定するようなことはありません。
そうは言ってもMVCモデルを意識しなければ、リクエストをController以外のものが受け取ってしまったり、全然関係ない演算処理を1つのModelに入れてしまったりということが起こるかもしれません。
実装した人にしか理解できないコードはその場では動いたとしても後々障害になりますので、頭の片隅に置きながら開発を進めるのが良いと思います。

以上がMVCモデルの簡単な説明でした。次回はSTSをダウンロードして日本語化するところまで進めたいと思います。

次回:STSの導入からPleiadesによる日本語化まで

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

IntelliJ IDEA + Codewind + Appsody でKabanero 入門

TL;DR

巷で噂のKabanero にIntelliJ IDEA で入門してみました。
Codewind でプロジェクト作成 --> Appsody でKubernetes クラスタにデプロイまでの作業ログです。
それぞれv1.0 を迎えていないですが、普段docker / kubectl をバシバシ打っている人には、そこそこ便利に使えそうという感じです。

環境

  • PC: Macbook Pro
  • IDE: IntelliJ IDEA Ultimate 2020.1
  • Appsody CLI: 0.6.4
  • Codewind: 0.14.0

Appsody とは

Appsody は、すぐにKubernetes にデプロイ可能なプロジェクトの雛形を提供するオープンソースプロジェクトです。
また、コンテナレジストリやGithubと組み合わせて独自の雛形を共有することも可能なようです。

公式👉 https://appsody.dev/

Codewind とは

Codewind は、コンテナでの開発を支援するIDE 拡張です。
IDE から簡単にアプリケーションコンテナのシェルにアクセスできたり、コンテナのログを閲覧できたりします。
また、ホットリロードのような機能もあり、ローカルの変更が自動的にコンテナ上のアプリに反映されます。
VS Code / Eclipse / IntelliJ をサポートしているため、Java プログラマーの大体はすんなり使用できそうです。

公式👉 https://www.eclipse.org/codewind/

IntelliJ IDEA にCodewind を導入

Plugins のMarketplace からCodewind で検索すれば出てくるので、それをインストールするだけです。

Codewind で新規プロジェクト作成

新規プロジェクト作成時に、Codewind の選択肢が追加されていることがわかります。
0697365564E663E6F5DA441D5C2E312B.jpg

Codewind を使用するには、どうやらCodewind 用のDocker コンテナが必要のようです。
初回のみですが、INSTALL CODEWIND IMAGES をクリックして、インストールします。

インストールが終わると、Appsody のプロジェクトの雛形を選択することができます。(今回はQuarkus default template を選択)
F3887E4CB67C5ACC61E698619E565530.jpg

あとは、プロジェクトの名前などを決めたら終了です。

作成されたプロジェクトをいじいじ

作成されたプロジェクトは、こんな感じです。
正直、Maven なのか😞と思いましたが、今後Gradle も選択できるようになると嬉しいですね。

example-codewind/
├── .appsody-config.yaml   # Appsody の構成情報
├── .appsody_init          # 実は、これがアプリの本丸?Dockerfileとか入ってる
├── .cw-settings           # Codewind の設定が入っているっぽいが内容はよくわからん
├── .idea
├── .vscode                # プロジェクト作成時点であった
├── example-codewind.iml
├── mvnw
├── mvnw.cmd
├── pom.xml
└── src

プロジェクト作成直後、ビルドが走ってDocker 上にアプリが立ち上がります。
その様子は、新たに追加されたCodewind ビューから確認できます。
このビューから、ログをみたり、コンテナの中に入ったりできます。
個人的には、ターミナルとIDEを行ったり来たりしなくて良いので結構便利に感じました。
7CABCA90DE8F8E88E341749F0BF45125.jpg

ホットリロードもしっかり確認できます。

[Container] __  ____  __  _____   ___  __ ____  ______ 
[Container]  --/ __ \/ / / / _ | / _ \/ //_/ / / / __/ 
[Container]  -/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \   
[Container] --\___\_\____/_/ |_/_/|_/_/|_|\____/___/   
[Container] 2020-07-29 06:29:15,402 WARN  [io.qua.dep.QuarkusAugmentor] (vert.x-worker-thread-3) Using Java versions older than 11 to build Quarkus applications is deprecated and will be disallowed in a future release!
[Container] 2020-07-29 06:29:15,631 INFO  [io.quarkus] (Quarkus Main Thread) example 1.0-SNAPSHOT on JVM (powered by Quarkus 1.6.0.Final) started in 0.230s. Listening on: http://0.0.0.0:8080
[Container] 2020-07-29 06:29:15,632 INFO  [io.quarkus] (Quarkus Main Thread) Profile dev activated. Live Coding activated.
[Container] 2020-07-29 06:29:15,632 INFO  [io.quarkus] (Quarkus Main Thread) Installed features: [cdi, resteasy, smallrye-metrics]
[Container] 2020-07-29 06:29:15,632 INFO  [io.qua.dep.dev.RuntimeUpdatesProcessor] (vert.x-worker-thread-3) Hot replace total time: 1.091s 
[Container] 2020-07-29 06:29:34,524 INFO  [io.qua.dep.dev.RuntimeUpdatesProcessor] (vert.x-worker-thread-2) Changed source files detected, recompiling [/project/user-app/src/main/java/com/example/kabanero/GreetingResource.java, /project/user-app/src/main/java/com/example/kabanero/GreetingService.java]
[Container] 2020-07-29 06:29:34,635 INFO  [io.quarkus] (Quarkus Main Thread) example stopped in 0.001s
[Container] __  ____  __  _____   ___  __ ____  ______ 
[Container]  --/ __ \/ / / / _ | / _ \/ //_/ / / / __/ 
[Container]  -/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \   
[Container] --\___\_\____/_/ |_/_/|_/_/|_|\____/___/   
[Container] 2020-07-29 06:29:34,638 WARN  [io.qua.dep.QuarkusAugmentor] (vert.x-worker-thread-2) Using Java versions older than 11 to build Quarkus applications is deprecated and will be disallowed in a future release!
[Container] 2020-07-29 06:29:34,857 INFO  [io.quarkus] (Quarkus Main Thread) example 1.0-SNAPSHOT on JVM (powered by Quarkus 1.6.0.Final) started in 0.219s. Listening on: http://0.0.0.0:8080
[Container] 2020-07-29 06:29:34,857 INFO  [io.quarkus] (Quarkus Main Thread) Profile dev activated. Live Coding activated.
[Container] 2020-07-29 06:29:34,858 INFO  [io.quarkus] (Quarkus Main Thread) Installed features: [cdi, resteasy, smallrye-metrics]
[Container] 2020-07-29 06:29:34,858 INFO  [io.qua.dep.dev.RuntimeUpdatesProcessor] (vert.x-worker-thread-2) Hot replace total time: 0.346s 

Appsody でKubernetes クラスタにデプロイ

ここまでで、Codewind さんの出番はほぼ終わりです。ここからは、appsody コマンドを使用してデプロイしていきます。
まずは、kubectl でコンテキストを適切に設定しておきましょう。

Appsody Operator のインストール

appsody でのデプロイでは、AppsodyApplication というカスタムリソースを用います。
そのため、Kubernetes クラスタにAppsody Operator をインストールする必要があります。

appsody operator install

ワンライナーでデプロイ

通常、Kubernetes クラスタへのデプロイには、以下のようなステップを踏む必要があります。

  1. Docker イメージをビルド
  2. Docker イメージをDocker レジストリにプッシュ
  3. Deployment リソースをKubernetes クラスタに作成

appsody コマンドではこれらをワンライナーで済ませられます。

# --push-url のデフォルトは、Docker Hub
appsody deploy -t <namespace>/<repository>[:<tag>] --push --push-url <registry-url>

プライベートなDocker レジストリのイメージを使用してデプロイ

ワンライナー簡単でとっても便利なんですが、プライベートなDocker レジストリを使用したい場合は罠があります。
具体的には、Service Account (default) にImagePullSecretsを指定するだけでは、Pod がImagePullBackOff で起動できません。(めちゃくちゃハマった)
Appsody Operator によってDeployment が作成されることに起因しているのかなぁと想像しています。

1. appsody build してAppsodyApplication マニフェストファイルを作成

以下コマンドを実行して、app-deploy.yaml を作成します。
ついでにDocker レジストリにプッシュします。

appsody build -t <namespace>/<repository>[:<tag>] --push --push-url <registry-url>

2. app-deploy.yamlを編集

spec.pullSecretdocker-registry タイプのSecret 名を指定します。

3. appsody deploy でデプロイ

以下コマンドを実行して、デプロイを行います。

appsody deploy -t <namespace>/<repository>[:<tag>] --push-url <registry-url> --no-build

kubectl でリソースを確認

kubectl get appsodyapplication で作成されたAppsodyApplication が確認できます。
また、関連してDeployment, Service などの作成も確認できます。
NodePort が作成されているため、簡単にアプリにアクセス可能です。

まとめ

  • 今までは、docker / kubectl をたくさん叩く必要があったが、appsody で一本化できるのはいい感じ
  • Codewind の存在で、IDE にこもって作業ができるのもいい感じ
  • アプリが大きくなるにつれて、Docker を使ったホットリロードが重くならないかが気になる
  • spec.pullSecret の追記はKustomize でさくっとやりたいので、結局デプロイはkubectl apply になりそう
  • Jetbrains 信者としては、Codewind で選択できるAppsody テンプレートがJava プロジェクトのみなのは解せない😡

余談

今回はQuarkus アプリを作成してみたが、ビルドでハマった。
Quarkus のネイティブビルドはめちゃくちゃメモリ食い虫でかつ、Appsody はDocker のマルチステージビルドでネイティブビルドするため、Docker への割り当てメモリが足りなくてエラーになっているようだった。
Docker に16GB 割り当てるとエラーは解消した。(Quarkus くん…😢)

[参考]
https://medium.com/analytics-vidhya/maybe-native-executable-in-quarkus-is-not-for-you-but-it-is-awesome-967588e80a4

ということもあるので、ちゃんとDevOps 環境整えてAWS CodePipeline 、Code Build とかでビルドするようにしましょう。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【備忘】Amazon DynamoDBへのアクセスプログラム

Amazon DynamoDBにアクセスするための基本的なプログラムを記載

1.Entityの用意

@DynamoDBTable(tableName = "テーブル名")
public class SampleTableEntity {
    // HashKey
    @DynamoDBHashKey
    private String hashKey;

    // RangeKey
    @DynamoDBRangeKey
    private String rangeKey;

    // 項目
    @DynamoDBAttribute
    private String item;
}

2.接続

// 指定リージョンのDynamoDBにアクセスするためのClient生成
AmazonDynamoDB amazonDynamoDB = AmazonDynamoDBClientBuilder.standard()
                .withRegion(リージョン名)
                .build();

// テーブルへのMapperを生成
DynamoDBMapper mapper = new DynamoDBMapper(amazonDynamoDB);

3.データの取り出し(load)

String hashKey="000001";
String rangeKey="000002";
SampleTableEntity entity = mapper.load(SampleTableEntity.class, hashKey, rangekey);

4.データの検索(query)

String hashKey="000001";
String rangeKey="000003";

Map<String, AttributeValue> eav = new HashMap<String, AttributeValue>();
eav.put(":v1", new AttributeValue().withS(hashKey));
eav.put(":v2",new AttributeValue().withS(rangeKey));

DynamoDBQueryExpression<SampleTableEntity> queryExpression = new DynamoDBQueryExpression<SampleTableEntity>() 
    .withKeyConditionExpression("hashKey = :v1 and rangeKey <> :v2")
    .withExpressionAttributeValues(eav);

List<SampleTableEntity > entityList = mapper.query(SampleTableEntity.class, queryExpression);

5.データの検索(scan)

String item = "Item";

Map<String, AttributeValue> eav = new HashMap<String, AttributeValue>();
eav.put(":v1", new AttributeValue().withS(item));

DynamoDBScanExpression scanExpression = new DynamoDBScanExpression()
    .withFilterExpression("item = :v1")
    .withExpressionAttributeValues(eav);

List<SampleTableEntity > entityList = mapper.scan(SampleTableEntity.class, scanExpression);

6.データの登録・更新(save)

SampleTableEntity entity = new SampleTableEntity();
entity.setHashKey="0000001";
entity.setRangeKey="0000002";
entity.setItem="Item";

mapper.save(entity);
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Java8以降のNullPointException 対策例(Optional)

本稿について

Java8でNullPointerException の対策で新しいやり方が見つかっていますので自身の備忘的に書いておきます。

事象

早速ぬるぽ出してみます。

java
public class Test {
    public static void main(String[] args) {
        String str = null;
        System.out.print(str.length());
    }
}
処理結果
Exception in thread "main" java.lang.NullPointerException
    at Test.main(Test.java:6)

NullPointerExceptionが出てしまいました。
java8より実装された対処法として、Optional をつけてあげることで
NullPointer対処することができます。
下記のイメージで変更します。

対処例
import java.util.Optional;

public class Test {

    public static void main(String[] args) {
        String str = null;
//      System.out.print(str.length());

        Optional<String> strOpt = Optional.ofNullable(str);
        strOpt.ifPresent(v -> System.out.println(v.length()));
    }
}

NullPointerException は出ずに無事処理終了しましたー

簡単な解説

java8以降でOptionalが実装されています
https://docs.oracle.com/javase/jp/8/docs/api/java/util/Optional.html

Optional<String> strOpt = Optional.ofNullable(str);

のようにして、strをOptionalでラップしてあげることでofNullable()関数を使うことができます。
ifPresent関数の引数として、
いったん、変数vstrの中身を退避させて、Systemoutpintline内で使う
このようなやり方をラムダ式(lambda expression)といい、Optionalと合わせてjava8より実装された新機能となります。

strOpt.ifPresent(v -> System.out.println(v.length()));

※ラムダ式についてまとめてある記事
https://engineer-club.jp/java-lambda-expression

ちなみにisPresentget()を使っているだめな例・・・(2020/07/31追記)

最初に下記の例を別パターンとして書いていましたが、下記のやり方は 万死に値する対処法 なようで、
自身への戒めを込めて悪い例として載せておきます。
こちらの記事をご覧頂くとお分かりいただけます
https://qiita.com/BlueRayi/items/ef46496ef2ef36b9cbb7#%E3%81%AA%E3%82%8B%E3%81%B9%E3%81%8Foptionalifpresent%E3%82%82%E4%BD%BF%E3%81%86%E3%81%AA
(※この記事を読むとそもそもOptional使ってのNullチェック自体ナンセンスなようですが。。)

悪い例
import java.util.Optional;

public class Test {
    public static void main(String[] args) {
        String str = null;
//      System.out.print(str.length());

        Optional<String> strOpt = Optional.ofNullable(str);
        if(strOpt.isPresent()) {
            String message = strOpt.get();
            System.out.println(message.length());
        }
    }
}

具体的には、if文内でisPresent()を使ってその値をget()というやり方は安易に実装できるが
Optionalを使うメリットを活かせておらず、isPresent()関数はやむを得ない場合の使い方、という捉え方をするのがよく、ニュアンス的に下記の記事がわかりやすそうです。

getを使用する機会は少ないはずです。
Optionalをわざわざ使用すると言うことは「値が入っていない場合はよしなにしてくれ」というメッセージです。
getを使用していきなり例外になるのなら、NullPointerExceptionが発生するのと同じです。

https://irof.hateblo.jp/entry/2015/05/05/071450

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Java8以降のNullPointerException 対策例(Optional)

本稿について

Java8でNullPointerException の対策で新しいやり方が見つかっていますので自身の備忘的に書いておきます。

事象

早速ぬるぽ出してみます。

java
public class Test {
    public static void main(String[] args) {
        String str = null;
        System.out.print(str.length());
    }
}
処理結果
Exception in thread "main" java.lang.NullPointerException
    at Test.main(Test.java:6)

NullPointerExceptionが出てしまいました。
java8より実装された対処法として、Optional をつけてあげることで
NullPointer対処することができます。
下記のイメージで変更します。

対処例
import java.util.Optional;

public class Test {

    public static void main(String[] args) {
        String str = null;
//      System.out.print(str.length());

        Optional<String> strOpt = Optional.ofNullable(str);
        strOpt.ifPresent(v -> System.out.println(v.length()));
    }
}

NullPointerException は出ずに無事処理終了しましたー

簡単な解説

java8以降でOptionalが実装されています
https://docs.oracle.com/javase/jp/8/docs/api/java/util/Optional.html

Optional<String> strOpt = Optional.ofNullable(str);

のようにして、strをOptionalでラップしてあげることでofNullable()関数を使うことができます。
ifPresent関数の引数として、
いったん、変数vstrの中身を退避させて、Systemoutpintline内で使う
このようなやり方をラムダ式(lambda expression)といい、Optionalと合わせてjava8より実装された新機能となります。

strOpt.ifPresent(v -> System.out.println(v.length()));

※ラムダ式についてまとめてある記事
https://engineer-club.jp/java-lambda-expression

ちなみにisPresentget()を使っているだめな例・・・(2020/07/31追記)

最初に下記の例を別パターンとして書いていましたが、下記のやり方は 万死に値する対処法 なようで、
自身への戒めを込めて悪い例として載せておきます。
こちらの記事をご覧頂くとお分かりいただけます
https://qiita.com/BlueRayi/items/ef46496ef2ef36b9cbb7#%E3%81%AA%E3%82%8B%E3%81%B9%E3%81%8Foptionalifpresent%E3%82%82%E4%BD%BF%E3%81%86%E3%81%AA
(※この記事を読むとそもそもOptional使ってのNullチェック自体ナンセンスなようですが。。)

悪い例
import java.util.Optional;

public class Test {
    public static void main(String[] args) {
        String str = null;
//      System.out.print(str.length());

        Optional<String> strOpt = Optional.ofNullable(str);
        if(strOpt.isPresent()) {
            String message = strOpt.get();
            System.out.println(message.length());
        }
    }
}

具体的には、if文内でisPresent()を使ってその値をget()というやり方は安易に実装できるが
Optionalを使うメリットを活かせておらず、isPresent()関数はやむを得ない場合の使い方、という捉え方をするのがよく、ニュアンス的に下記の記事がわかりやすそうです。

getを使用する機会は少ないはずです。
Optionalをわざわざ使用すると言うことは「値が入っていない場合はよしなにしてくれ」というメッセージです。
getを使用していきなり例外になるのなら、NullPointerExceptionが発生するのと同じです。

https://irof.hateblo.jp/entry/2015/05/05/071450

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

int定数の代わりにenumを使用する

int enumパターン

表現力が乏しい。
オレンジを期待しているメソッドにアップルを渡したり
アップルとオレンジを==演算子で比較してもコンパイラに怒られない。

public static final int APPLE_FUJI = 0;
public static final int APPLE_PIPIN = 1;
public static final int APPLE_GRANNY_SMITH = 2;

public static final int ORANGE_NAVEL = 0;
public static final int ORANGE_TEMPLE = 1;
public static final int ORANGE_BLOOD = 2;

enumを使用した場合

public enum Apple {FUJI, PIPIN, GRANNY_SMITH}
public enum Orange {NAVEL, TEMPLE, BLOOD}

値によって切り替えるenum型

以下のコードでは、技術的にはメソッドの終わりに到達可能であることや、
switchへ対応するcaseの追加を忘れるなどの問題点がある

public enum Operation {
        PLUS, MINUS, TIMES, DIVID;

        // 定数で表される算術操作を行う
        public double apply(double x, double y) {
            switch(this) {
            case PLUS:
                return x + y;
            case MINUS :
                return x - y;
            case TIMES:
                return x * y;
            case DIVID:
                return x / y;
            }
            throw new AssertionError("Unknown op" + this);
        }
    }

抽象メソッドを定義し、定数ごとに抽象メソッドをオーバーライドすることで問題点を改善することができる。

public enum Operation {
        PLUS {
            public double apply(double x, double y) {
                return x + y;
            }
        },
        MINUS {
            public double apply(double x, double y) {
                return x - y;
            }
        },
        TIMES {
            public double apply(double x, double y) {
                return x * y;
            }
        },
        DIVIDE {
            public double apply(double x, double y) {
                return x + y;
            }
        };
        public abstract double apply(double x, double y);
    }

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む