20210415のJavaに関する記事は4件です。

【Java アルゴリズム修行⑦】二分探索

二分探索とは 線形探索では、目的とするキー値を持つ要素に出会うまで先頭から順に要素を走査していましたが、 そんな線形探索よりも高速に探索が行えるのが二分探索たるものらしいです。。 要素がキーの昇順または降順にソートされている配列から効率よく探索を行うアルゴリズム とのことなので、探索対象となる配列は昇順・降順にソートされている必要があるみたいなので 配列だったら何でもかんでも使えるという訳ではなさそうです汗 具体的な探索手順としては、n個要素を持つ配列のちょうど中央に位置する(n-1/2)の要素を調べて、 探索対象よりも大きいか少ないかで、探索範囲を中央値よりも後か、前かに絞ると言った流れです。 (これ考えた人も頭ふにゃふにゃそう。。) 言葉で説明するのもあれなのでざっくりイメージで見てみましょう。 11個の要素が昇順で構成された配列があるとして、その中で5というキー値の位置を見つけたいとします。 11個の要素なので、まずは中央位置を(11-1)÷2で求めます。(インデックスは0から始まるので、-1をしています) すると間のインデックスは5と分かるので、5番目に位置している8の値とキー値を比較します。 5は8より小さく、中央値よりもキー値の方が小さいということになるので、先頭〜中央位置-1の間にキー値があるの絞ることができます。 これを繰り返し、最終的に間がなくなってしまったら探索失敗という判断ができます。 条件分岐とするなら下記の2つを繰り返していくイメージです。 中央値がキー値より大きければ左(中央値より大きい方)に絞り込む 中央値がキー値より小さければ右(中央値より小さい方)に絞り込む  イメージはなんとなくできたので、次にこの流れをコードに落とし込んでみましょう! コードに落とし込んでみる algo.java import java.util.*; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int count = sc.nextInt(); int array [] = new int[count]; array[0] = sc.nextInt(); for(int i = 1; i < count; i++){ do{ System.out.print("昇順で入力してください" + i +"番目の値: "); array[i] = sc.nextInt(); // 入力された値が、一つ前の要素より大きくなるまで入力を繰り返す }while (array[i - 1] > array[i]); } System.out.print("探す値: "); int target = sc.nextInt(); int answer = search(array,count,target); if(answer == -1){ System.out.println("探索失敗"); }else{ System.out.println(++answer +"番目に存在します"); } } public static int search(int [] array, int n, int key){ int start = 0; // 探索範囲開始インデックス int end = n - 1; // 探索範囲末尾インデックス do { //中間インデックスを取得 int middle = (start + end) / 2; //中間インデックスの値がキー値と一致していればキー値のインデックスを返す if (array[middle] == key) { return middle; //キー値が中間値よりも大きければ、開始インデックスを中間より一つ後ろに設定(探索範囲を前半に分ける) } else if (array[middle] < key) { start = middle + 1; //キー値が中間値よりも小さければ、末尾インデックスを中間より一つ前に設定(探索範囲を後半に分ける) } else { end = middle - 1; } //開始インデックスが末尾インデックス以上になれば超えてしまっているので終了 }while (start <= end); return -1; } } 昇順で入力された数字で構成されたn個の配列から二分探索を使ってキー値の位置を求めています。 searchメソッドで実際に二分探索を行っていますが、条件分岐としては、キー値と一緒か、キー値の方が中央値より大きいか小さいかの3つとなります。 初期の探索範囲はインデックス的に 0 ~ n -1 となるので、この値を変えていくことで探索範囲を絞っています。 中央値がキー値より大きければ左(中央値より小さい方)に絞り込む → 中央位置から -1して後ろにする 中央値がキー値より小さければ右(中央値より大きい方)に絞り込む → 中央位置から +1して前にする 中央値を基準に探索範囲を前後に絞っていくという発想は凄いですよね。。 繰り返す分だけ、探索範囲が半分になっていくので、先頭から1つずつ要素をみていく線形探索よりも高速に行えるのは納得です。。 Arrays.binarySearchメソッド 先のように二分探索を自前で書くこともできるんですが、実はArraysクラスのメソッドとして既に定義されているみたいです。。 公式リファレンス つまり、先ほどのsearchメソッドをそのまま1行で書けてしまうということですね、、 algo.java import java.util.*; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int count = sc.nextInt(); int array [] = new int[count]; array[0] = sc.nextInt(); for(int i = 1; i < count; i++){ do{ System.out.print("昇順で入力してください" + i +"番目の値: "); array[i] = sc.nextInt(); // 入力された値が、一つ前の要素より大きくなるまで入力を繰り返す }while (array[i - 1] > array[i]); } System.out.print("探す値: "); int target = sc.nextInt(); //binarySearchメソッドを使って二分探索を実施 int answer = Arrays.binarySearch(array,target); if(answer < 0){ System.out.println("探索失敗"); }else{ System.out.println(++answer +"番目に存在します"); } } } これだけで終わりです、、昇順であれば基本的に扱えますが、Arraysクラスが提供しているメソッドで渡せる配列の型は下記になります。 byte,char,double,float,int.long,short,Object あれ、Object型もいけるならほとんどのクラスはいけるやん!って話なんですが、このObject型の配列を渡せるメソッドのお陰で、Integer型やString型も扱うことができるんですね。。恐るべしbinarySearchメソッド。。  ちなみに、要素の大小関係は自然な順序で判定しているそうで、この自然な順序というと、整数や実数であれば、小さい方から大きい方へ、日付であれば古い方から新しい方へ、などと言った順序付けのことだそうです。 String型であってもObject型の配列として渡せるのはこれができるのは、ComparableというインターフェースをStringクラス内で実現しているとともに、compareToメソッドを実装しているからなんですね。。! algo.java //Stringクラス public int compareTo(String anotherString) { byte[] v1 = this.value; byte[] v2 = anotherString.value; if (this.coder() == anotherString.coder()) { return this.isLatin1() ? StringLatin1.compareTo(v1, v2) : StringUTF16.compareTo(v1, v2); } else { return this.isLatin1() ? StringLatin1.compareToUTF16(v1, v2) : StringUTF16.compareToLatin1(v1, v2); } } //Integerクラス public int compareTo(Integer anotherInteger) { return compare(this.value, anotherInteger.value); } 細かいところまではみませんが、どちらも比較する2つの値を持ってきて、大小判定を行っています。 このように、compareToメソッドを実装しているクラスであれば、binarySearchメソッドの引数にObject型の配列として渡すことができるんですね! 自前のクラスでやってみる String型とかInteger型とかでも使えるのは分かりましたが、実際のデータオブジェクトはデータの種類によってクラス分けされていることが多いですし、String型だけで構成されているデータ型というのもなかなかないと思います。 そんな自前のクラスでもbinarySearchを使いたいな、、となった場合に頼りになるのが下記メソッドです public static <T> int binarySearch​(T[] a, int fromIndex, int toIndex, T key, Comparator<? super T> c) パッと見よく分かりませんが、これまでには存在しなかった第三引数にComaratorインターフェース方のインスタンスを渡していますね。。 実はbinarySearchメソッドが二分探索をするときには、昇順・降順に並んでいる配列の大小関係を判定する過程があり。。(ちょっと細かいところまでは分かっていません。。精進します。)自前のクラスで使用する場合は、何を以ってして大小とするのかをbinarySearchメソッドに通知する必要があるみたいです。 その通知方法というのが、この第三引数ということですね。。早速使ってみましょう。 alog.java import java.util.*; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); //名前と身長を持つPhysicsDataのインスタンスで構成された配列を生成 PhysicsData [] people ={ new PhysicsData("BIM",163), new PhysicsData("PUNPEE",175), new PhysicsData("KREVA",187), new PhysicsData("TOFUBEATS",191), }; System.out.print("何cmの人を探していますか?: "); int target = sc.nextInt(); int answer = Arrays.binarySearch(people,new PhysicsData("",target),PhysicsData.COMPARATOR); if(answer < 0){ System.out.println("指定の身長の人はいません"); }else{ System.out.println("指定の身長の人は" + ++answer +"番目にいます"); } } } public class PhysicsData{ private String name; private int height; public PhysicsData(String name, int height) { this.name = name; this.height = height; } public static final Comparator<PhysicsData> COMPARATOR = new HeightOrderComparator(); //Comparatorクラスを実現して、compareメソッドを実装 private static class HeightOrderComparator implements Comparator<PhysicsData>{ public int compare(PhysicsData a,PhysicsData b){ return (a.height > b.height)? 1 : (a.height < b.height)? -1 : 0; } } } 名前と身長で構成されたPhysicsDataクラスを要素に持つ配列から、入力した値の身長の人が何番目にいるかを binarySearchメソッドを使って判定しています。 Arrays.binarySearch(people,new PhysicsData("",target),PhysicsData.COMPARATOR); が実際にメソッドを使用している部分ですが、ここで第三引数で持ってきているPhysicsData.COMPARATORがPhysicsDataクラスにおける大小判定を表している部分です。 Comparatorインターフェースを実現しているHeightOrderComparatorクラスにてcompareメソッドも実装しています。 alog.java public int compare(PhysicsData a,PhysicsData b){ return (a.height > b.height)? 1 : (a.height < b.height)? -1 : 0; } 引数で渡さらた2つのPhysicsDataのインスタンスの内、前者の身長が大きければ1、後者の身長が大きければ -1 身長が同じであれば 0を返すようにしています。 このcompareメソッドの判定基準に基づいてbinarySearchメソッドが二分探索を行い、 キー値となる身長の人がいればそのインデックスを返すという実装が可能になるわけですね。。! 学んだこと 探索範囲を常に半分にする二分探索は線形探索よりも探索速度が早く、binarySearchメソッドで実装も可能 既にJavaのクラスにあるメソッドも中身を書いてみると理解が深まる Comparatorインターフェースは奥深いけど、もっと学びたい 学んだことに、もっと学びたいってって何だよ笑って感じですが、 正直Comparatorインターフェースの仕様はまだまだ分かっていない部分も多いので、今後も学びを深めていきたいです汗 また、今までであれば、binarySearchメソッドがよしなにやってくるのかとスルーしていた部分を二分探索という方法論から、 実際にコードに落とし込んでみることで、理解が深まった気がします! 深くいき過ぎる必要はなさそうですが、この "よしな" な部分を気にかけていく癖を付けていきたいです! 引き続き頑張っていきます!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

springでwebアプリを作成する機会があったのでまとめてみました(メモ)

自社で資材を管理するシステムを作ったので復習も兼ねてまとめていきたいと思います。 スキル ・Java Silve 取得 ・oracle_bronze[12c SQL基礎] 取得 ・サーブレット、javaScriptは軽くわかる ・HTML、CSSはわかる 上記のスキルでspring開発に携わりました。 spring開発で重要だと感じた3つの項目についてまとめていきたいと思います。 ・3層アーキテクチャ ・システム構成 ・Webアプリ(apring) 3層アーキテクチャ ※アーキテクチャ・・・構成のこと Webアプリは3種類のサーバーから成り立っています。 ■Webサーバー クライアントからの要求に対して 「静的コンテンツを見せる」と「APサーバーに動的コンテンツを要求し、返ってきた結果を見せる」という2つの役割。 ※静的コンテンツ → 常に同じ内容  動的コンテンツ → 検索、送信内容によって異なる ■APサーバー Webサーバーからの要求に対して「動的コンテンツを生成」と「データを保存したり、やりとりができる」という2つの役割。 ■DBサーバー Webサーバーからの要求に対して「データを書き込んだり、必要な情報を引き出したりできる」という役割。 さらに、APサーバーは3層に分けることができます。 各層によって役割が違います。 例えば、4択クイズアプリを作成する (例) プレゼンテーション層 → ユーザとやりとり ビジネスロジック層 →「問1は1番が正解、問2は4番が正解」などのルール決める データアクセス層 → 問題の結果を保存 「表示方法、ルール、データの永続化を分離する」という 3 層が何より基本 システム構成 今回のシステム構成はこんな感じだったと思います。 Webアプリ(apring) springの動きについてついて書いていこうと思います。 ■APサーバー3層 こんな感じで役割が分かれています。 ■プレゼンテーション層 ・Controller・・・クライアントからのリクエストに対応し、処理の結果を再びクライアントに返す司令塔の役割をします。 ・Model・・・ View と Controller 間のデータ受け渡しをする役割をします。 ・view・・・画面への表示や入出力処理をする役割をします。 ・ajax・・・非同期処理。※jQueryでajax作成       (例)データ更新する        同期:URL又は画面を変更することでデータの更新可能。        非同期:URL又は画面を変更することなくでデータの更新可能。            (実際は裏で変更している) ■ビジネスロジック層 この層ではルールを決めていきます。 基本、コントローラに呼ばれ、各メソッド単位でのトランザクション処理が行われます。 トランザクション処理・・・処理が始まり終わるまでの処理のことをいいます。 ※メモ DI(Dependency Injection)・・依存性の注入 DIを用いることによってメリット ・newしてインスタンスを生成しなくていい ・インスタンス化は1回でいい @Controller public class ItemController { @Autowired //DI private ItemService itemService; (メソッドなど) } ■データアクセス層 ・DAO(Data Access Object)・・・DBとやりとりするクラスのこと ・MyBatis・・・オブジェクト指向言語におけるオブジェクトとデータベースの関係を築いてくれる便利ツールのこと。 ※MyBatisのようなにオブジェクトとデータベースの関係を築いてくれることを総称O/Rマッパーという。  MyBatisもO/Rマッパーの一つということ。MyBatis以外にもSpring Data JPAなど便利なツールはたくさんあります。 ・Mapper・・・Javaファイル(インターフェイス)とXMLファイル(SQL)の2セット生成する。         DBとのやりとりが可能になる。 感想 ・jQuery、springフレームワークを慣れるのに時間がかかった。 ・デバックがどれだけ重要かわかった。 ・成果物があると達成感がある。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Azure Functions(Java)を利用するための準備運動

はじめに Java楽しんでいますか この記事では以下のことを書いています Javaおよびツールのインストール(on macOS 10.15.7) 雛形プロジェクトの動かし方 Azure Functionsへのデプロイ 「Java開発者のためのAzure入門 (2021/4/6– 2021/5/9)」というキャンペーンへの投稿記事です 私はElixirというプログラミング言語を使って、「【毎日自動更新】Java開発者のためのAzure入門(2021/4/6–2021/5/9) LGTMランキング!」という記事を自動更新しています 当初は、これと同じことをJavaでやってみようと考えていました ただそれだとただキャンペーンに参加するためだけの記事になってしまう気がしました 自分にとっても面白くはないので、別のことはないかと模索しました 自分の役に立つことはないかと そこでおもいついたのが、Seventyになんなんとする母がスマートフォンに最近、買い替えまして、その操作の練習支援になるようなことをしたいとおもいました みうらじゅんさんの「親孝行プレイ」に通じるものがあるかもしれません ごめんなさい、まだ読んでいないです 「「ない仕事」の作り方1」は読んでいます ところが最近、Javaに触れる機会が少なかったのでさてどこから手をつけようかと逡巡してしまいました それで次にとった行動は、「Azure Java」で検索してたどり着いたAzureの公式ドキュメントをそのままやってみるということです 以下のドキュメントをみていくとよさそうです Azure Functions のドキュメント2 Azure Functions の概要 Azure Functions の概要 - Java クイックスタート: Visual Studio Code を使用して Azure に Java 関数を作成する ここが一番、私にとってはためになりました Maven を使用して Azure で Java サーバーレス機能を開発する この記事を書いている人 Javaは使ったことがありますが、ここ5年くらいはほとんど触っていません 個人開発でリリースしているandroidアプリはメンテナンスを続けています オートレースオンデマンド再生 読書日記 ご利用のみなさま、ありがとうございます 最近はElixirというプログラミング言語が大のお気に入りでございます ① 環境構築 macOS Catalina 10.15.7 Oracle JDK、JREを以前インストールしていた まずは、環境を構成するを丁寧にやってみませふ Oracle JDK、JREのアンインストール macOSでのJDKのアンインストール macOSでのJREのアンインストール 上記に従ってすすめました なんかこわい おっかなびっくりだけど公式の手順なので迷わず行けよ、行けばわかるさ、ありがとう! なぜアンインストールしたのかについては、環境を構成するというところで、Azul Zulu for Azure - Enterprise Edition JDK buildsのインストールがすすめられていて、なんとなく同じようなものが2つあるのはよくないのかなあとおもったからです 共存できたのかもしれませんし、 詳しくはよくわかっていないのですが、JDKの新しいリリース・モデ および提供ライセンスについて が関係しているようにおもいます Java11 のインストール https://www.azul.com/downloads/azure-only/zulu/?version=java-11-lts ここから.dmgをダウンロードしてダブルクリック 画面の指示通りすすめればこわくない インストーラーの画面はなんだか楽しそう! ~/.zshenv export JAVA_HOME=`/usr/libexec/java_home` と書いていました いつ書いたのかはとんと思い出せないのです $ source ~/.zshenv $ echo $JAVA_HOME /Library/Java/JavaVirtualMachines/zulu-11.jdk/Contents/Home $ java -version openjdk version "11.0.10" 2021-01-19 LTS OpenJDK Runtime Environment 21.1-(Zulu-11.45+27-macosx_x64)-Microsoft-Azure-restricted (build 11.0.10+9-LTS) OpenJDK 64-Bit Server VM 21.1-(Zulu-11.45+27-macosx_x64)-Microsoft-Azure-restricted (build 11.0.10+9-LTS, mixed mode) Apache Mavenのインストール 昔インストールしたような記憶がありますが、mvnでcommand not foundと言われてしまいました 公式の手順は面倒そうにみえたので、Homebrewでインストールしました $ brew install maven $ mvn -v Apache Maven 3.8.1 (05c21c65bdfed0f71a2f2ada8b84da59348c4c5d) Maven home: /usr/local/Cellar/maven/3.8.1/libexec Java version: 1.8.0_282, vendor: Azul Systems, Inc., runtime: /Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home/jre Default locale: ja_JP, platform encoding: UTF-8 OS name: "mac os x", version: "10.15.7", arch: "x86_64", family: "mac" Visual Studio Code 私はすでにインストール済みでした 重宝しております ありがとうございます Java Extension Pack リンク先に飛んで、Installボタンを押す Visual Studio Code 用 Azure Functions 拡張機能 リンク先に飛んで、Installボタンを押す Visual Studio Codeが立ち上がって、そちらでInstallボタンを押す ② ローカル プロジェクトを作成する リンク先の通りにやればいいのですが、最初のフォルダ選択は、中身が空のmyFunctionディレクトリを選択すると吉です ディレクトリ作ってくれるだろうと高を括ってすすめるとぶちまけられます なんのことだかわからない方は何事も経験なので~/Desktopでも選んでやってみるとわかりますが後始末が面倒なのでおすすめしません もしやっちまったら、ls -laとかして日付をみて、ぶちまけてしまったファイルやフォルダを消していくとよいでしょう 「provide an app name (アプリ名を指定してください) : [myFunction-12345] 」のところの12345という数字は、Visual Studio Codeが表示していた値を変更せずにそのままエンターを押しました ③ 関数をローカルで実行する F5を押しますと、azure-functions-core-toolsのインストールがはじまりました Azure Functions Core Tools のインストールに書いてあるようなことです イゴいた、イゴいた ここまでポチポチやっただけで、自らはJavaのコードを一切書いていません デフォルトで以下のコードが生成されています nameをキーとするクエリパラメータの値を、"Hello, " + nameして返すプログラムです @HttpTriggerのところはなにやらごちゃごちゃしていますが、とりあえず景色だとおもって関数本体に目を通してみるとそんなに難しいことは書いてありません src/main/java/com/function/Function.java package com.function; import com.microsoft.azure.functions.ExecutionContext; import com.microsoft.azure.functions.HttpMethod; import com.microsoft.azure.functions.HttpRequestMessage; import com.microsoft.azure.functions.HttpResponseMessage; import com.microsoft.azure.functions.HttpStatus; import com.microsoft.azure.functions.annotation.AuthorizationLevel; import com.microsoft.azure.functions.annotation.FunctionName; import com.microsoft.azure.functions.annotation.HttpTrigger; import java.util.Optional; /** * Azure Functions with HTTP Trigger. */ public class Function { /** * This function listens at endpoint "/api/HttpExample". Two ways to invoke it using "curl" command in bash: * 1. curl -d "HTTP Body" {your host}/api/HttpExample * 2. curl "{your host}/api/HttpExample?name=HTTP%20Query" */ @FunctionName("HttpExample") public HttpResponseMessage run( @HttpTrigger( name = "req", methods = {HttpMethod.GET, HttpMethod.POST}, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage<Optional<String>> request, final ExecutionContext context) { context.getLogger().info("Java HTTP trigger processed a request."); // Parse query parameter final String query = request.getQueryParameters().get("name"); final String name = request.getBody().orElse(query); if (name == null) { return request.createResponseBuilder(HttpStatus.BAD_REQUEST).body("Please pass a name on the query string or in the request body").build(); } else { return request.createResponseBuilder(HttpStatus.OK).body("Hello, " + name).build(); } } } ④ Azure へのサインイン リンクの通りに進めます すでにAzureのアカウントは持っていましたし、すんなりいきました まだもっていないよ〜 という方は、 Azure | クラウドコト始め l まずは"Azure"に登録してみよう l 初心者向け01 にて詳しく丁寧に解説されています! のでご参照ください そうそう、なにせ私には日本マイクロソフト賞④の受賞実績がありますから、Azureのアカウントは持っているのでありますよ もう一度言います $\huge{日本マイクロソフト賞④}$ を受賞したことがあります その原動力となったのはElixirが好きだというただ一点です その話はまた別の機会に ⑤ Azure にプロジェクトを発行する リンクの通りに進めます awesome-test-12345と、Enter a globally unique name for the function appに対して今回は入力してみました ⑥ Azure で関数を実行する リンクの通りに進めます イゴいた、イゴいた ⑦ リソースをクリーンアップする 私の場合ですとリソースグループawesometest12345を削除しました まとめ ポチポチしただけですが、Azure FunctionsにJavaのプログラムをデプロイできました 次は、本題のタイマをトリガとしてAzure FunctionsでJavaのプログラムをイゴかす方法を書きたいとおもいます あわせて読みたいオススメ記事 @statemachine さんの「Java で Azure Functionsの関数を実装する」 最後の最後に Elixirって何よ という方へ ちょいちょいElixirを散りばめました 2020/12/26時点くらいのスクリーンショット Elixirについてもっと知りたい方は下記の本をオススメします プログラミングElixir(第2版) Elixir実践ガイド elixir.jp Slackの#autoracexというところに私は入り浸っておりますのでお気軽にお声がけください 勉強会が頻繁に行われています 私がよく参加している勉強会です autoracex 【毎週月曜】 主催 Sapporo.beam  【毎週水曜】 OkazaKirin.beam 【毎週木曜】 fukuoka.ex/kokura.ex 【毎月2~3回】 NervesJP  【毎月1回】 (@piacerex さん作 ) 「「ない仕事」の作り方」は、2021年本屋大賞 『発掘部門』にて、「超発掘本!」に選ばれております。本屋大賞に選ばれたから読んだのではなく、その前から私は推していました。証拠は、2021/04/09にアップロードしたLT資料に紹介をいれています。紹介文は「私の5分の話なんかより、この本を1時間〜2時間かけて読んだほうがよっぽどいい」です。 ↩ どうしてAzure Functionsにすぐ飛びつけたのかというと、AWSの話で申し訳ありませんが、Lambdaっぽいものを探そうとしてたどり着きました。じゃあ、その前のLambdaとの馴れ初めは忘れてしまいました。 ↩
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

SpringBoot + MyBatis + Thymeleaf + MySQL で超簡潔なCRUD処理

以前に投稿させていただいた記事の続き的なものです。 CRUD処理全て実装できたので、自分用のアウトプットとして投稿させていただきます。 記載が稚拙だったり誤っている箇所等あるかもしれませんがご容赦ください。 誤りについてはご指摘いただけますと大変幸いですm(_ _)m。 環境 Spring Boot 2.4.4 Java 11 OS  : macOS Big Sur IDE : SpringToolSuite4 Maven 目標 SQLでテーブルusers(カラムはid, name, age)を作成し、以下の4つの処理ができるアプリを作成。 新規ユーザー登録(C) ユーザー情報表示(R) ユーザー情報更新(U) ユーザー情報削除(D) ディレクトリ構成 . ├src/main/java/com/example/demo/ │                 ├controller / UController.java │                 ├model / User.java │                 ├repository / UMapper.java │                 ├service / UService.java │                 └MyBatisPracticeApplication.java └ src/main/resources/          ├mapper / UMapper.xml          ├templates / users          │         ├change.html          │         ├details.html          │         ├list.html          │         ├register.html          │         └top.html          ├application.properties          ├data.sql          └schema.sql 各コード application.properties spring.datasource.url=jdbc:mysql://localhost:3306/[任意のDB名を記載してください]?serverTimezone=Asia/Tokyo spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.username=root spring.datasource.password=[MySQLのパスワードを記載してください] spring.datasource.sql-script-encoding=UTF-8 spring.datasource.initialization-mode=always spring.datasource.schema=classpath:schema.sql spring.datasource.data=classpath:data.sql #MyBatis mybatis.mapper-locations=classpath*:/mapper/*.xml #Log Level logging.level.com.example=debug MySQLの利用に必要な記載と、アプリ実行時に実行するSQLファイルの記載です。 #MyBatis…読み込むxmlファイルの場所を記載してください。 #LogLevel…コンソールにSQLの処理を出力してくれます(無くてもOKです)。 schema.sql CREATE TABLE IF NOT EXISTS users ( id VARCHAR(50) PRIMARY KEY, name VARCHAR(50), age INT ); 作成するテーブルの内容を記載します。 data.sql INSERT IGNORE INTO users (id, name, age) values ('1', 'Tom', 30), ('2', 'Mike', 31); usersテーブルに予めINSERTしておくユーザー情報を記載します。 list.html <!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"></meta> <title>ユーザーList</title> </head> <body> <table border=1> <tr> <th>ID</th> <th>名前</th> <th>年齢</th> </tr> <tr th:each="u:${users}"> <td th:text="${u.id}"></td> <td th:text="${u.name}"></td> <td th:text="${u.age}"></td> </tr> </table> </body> </html> http://localhost:8080/users/list で全ユーザー情報を表示する画面です。 私が初めに作成したselect全件処理時のファイルを残しているだけですので、無くても大丈夫です。 top.html <!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>ユーザー一覧</title> </head> <body> <h1>ユーザー一覧(top.html)</h1> <div th:if="!${users.size()}"> <p>登録されているユーザーはいません</p> </div> <a th:href="@{/users/register}"><!-- URL「/users/register」生成 --> <button>新しいユーザーを登録</button> </a> <table th:if="${users.size()}" border=1> <!-- DB内のデータがtrue = 0以外の時 --> <thead> <tr> <th>ID(PRIMARY KEY)</th> <th>名前</th> <th>年齢</th> <th></th> <th></th> <th></th> </tr> </thead> <tbody> <tr th:each="users:${users}" th:object="${users}"> <td th:text="*{id}"></td> <td th:text="*{name}"></td> <td th:text="*{age}"></td> <td><a th:href="@{/users/details/id={id}(id=*{id})}"><button>詳細</button></a></td> <td><a th:href="@{/users/change/id={id}(id=*{id})}"><button>変更</button></a></td> <td> <form th:method="post" th:action="@{/users/delete/id={id}(id=*{id})}"><button>削除</button></a> </form></td> </tr> </tbody> </table> </body> http://localhost:8080/users で表示されるトップページです。 全ユーザー情報を表示し、各ボタンの機能は以下の通りです。 [新しいユーザーを登録]ボタン→register.htmlへ遷移 [詳細]ボタン→details.htmlへ遷移 [変更]ボタン→change.htmlへ遷移 [削除]ボタン→当該ユーザー情報を削除 details.html <!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>ユーザー詳細</title> </head> <body> <h2>ユーザー詳細表示(details.html)</h2> <div th:object="${users}"> <table border="1"> <tr> <th>ID</th> <th>名前</th> <th>年齢</th> </tr> <tr> <td th:text="*{id}"></td> <td th:text="*{name}"></td> <td th:text="*{age}"></td> </tr> </body> </html> register.html <!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>新規ユーザー登録</title> </head> <body> <h2>新規ユーザー登録(register.html)</h2> <form th:method="post" th:object="${users}" th:action="@{/users/register}"> <label>ID(VARCHAR):<input type="text" th:field="*{id}"></label><br> <label>名前(VARCHAR):<input type="text" th:field="*{name}"></label><br> <label>年齢(INT):<input type="text" th:field="*{age}"></label><br> <button>新規作成</button> </form> </body> 当初はth:fieldの部分を単なるname属性で記載していてそれでも動いたのですが、th:fieldで動かして見たくて書き換えました。 その時以下のエラーが出て悩んでおりました。 java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name ‘users’ available as request attribute その後th:objectについて調べ、ControllerクラスにModelの記載を追加して解決しました。 (参考にさせていただいたteratailの質問:https://teratail.com/questions/26218) change.html <!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>ユーザー変更</title> </head> <body> <h2>ユーザー変更(change.html)</h2> <form th:method="post" th:object="${users}" th:action="@{/users/change/id={id}(id=*{id})}"> <label>ID(VARCHAR):<input type="text" th:field="*{id}"></label><br> <label>名前(VARCHAR):<input type="text" th:field="*{name}"></label><br> <label>年齢(INT):<input type="text" th:field="*{age}"></label><br> <button>変更</button> </form> </body> </html> User.java package com.example.demo.model; import lombok.Data; @Data public class User { private String id; private String name; private int age; } エンティティクラスです。 UMapper.xml <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.example.demo.repository.UMapper"> <resultMap type="com.example.demo.model.User" id="user"><!-- id属性は任意の値 --> <!-- columnはSQLのカラム propertyはエンティティクラスのフィールド --> <id column="id" property="id"/> <result column="name" property="name"/> <result column="age" property="age"/> </resultMap> <select id="findOne" resultMap="user"> select * from users where id = #{id} </select> <select id="find" resultType="com.example.demo.model.User"> select * from users </select> <insert id="insertOne"> insert into users ( id, name, age ) values ( #{id}, #{name}, #{age} ) </insert> <update id="updateOne"> update users set name = #{name}, age = #{age} where id = #{id} </update> <delete id="deleteOne"> delete from users where id = #{id} </delete> </mapper> UMapper.java package com.example.demo.repository; import java.util.List; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; import com.example.demo.model.User; @Mapper public interface UMapper { //select1件 public User findOne(String id); //select全件 public List<User> find(); //insert public void insertOne(User u); //update public void updateOne(@Param("id") String id, @Param("name") String name, @Param("age") int age); //delete public void deleteOne(User u); } UService.java package com.example.demo.service; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.example.demo.model.User; import com.example.demo.repository.UMapper; @Service public class UService { @Autowired UMapper mapper; //select1件 public User getUserOne(String id) { return mapper.findOne(id); } //select全件 public List<User> getList() { return mapper.find(); } //insert public void insertOne(User u) { mapper.insertOne(u); } //update public void updateOne(String id, String name, int age) { mapper.updateOne(id, name, age); } //delete public void deleteOne(User u) { mapper.deleteOne(u); } } UController.java package com.example.demo.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.validation.BindingResult; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import com.example.demo.model.User; import com.example.demo.service.UService; import java.util.List; @Controller @RequestMapping("/users") public class UController { @Autowired private UService service; //select全件表示 @GetMapping("/list") public String getUserList(Model model) { List<User> userList = service.getList(); model.addAttribute("users", userList); return "users/list"; } //トップページ top.html表示 @GetMapping("") public String top(Model model, @ModelAttribute User u) { model.addAttribute("users", service.getList()) ; return "users/top"; } //top→[詳細]押下 select1件 @GetMapping("details/id={id}") public String details(@PathVariable("id") String id, Model model) { model.addAttribute("users", service.getUserOne(id)); return "users/details"; } //top→[新規作成]押下 th:hrefにより生成されたURLをGETで表示 @GetMapping("/register") public String registerUser(Model model, @ModelAttribute User u) { model.addAttribute("users", u); return "users/register"; } //register.html内の <form method="post"> で↓へ飛ぶ @PostMapping("/register") public String create(@Validated @ModelAttribute User u, BindingResult result) { if (result.hasErrors()) { return "users/register"; } service.insertOne(u); return "redirect:/users"; } //top→[変更]押下時にchange.htmlを表示するGET @GetMapping("change/id={id}") public String change(@PathVariable("id") String id, Model model) { model.addAttribute("users", service.getUserOne(id)); return "users/change"; } @PostMapping("change/id={id}") public String update(@ModelAttribute User u, Model model) { service.updateOne(u.getId(), u.getName(), u.getAge()); return "redirect:/users"; } //top→[削除]押下時 @PostMapping("delete/id={id}") public String delete(@PathVariable String id, @ModelAttribute User u) { service.deleteOne(u); return "redirect:/users"; } } 参考にさせていただいたQiita記事 前回から引き続き、下記記事を参考にさせていただきました。 ありがとうございました! https://qiita.com/sumichan/items/bdc2a0e909416ae55162
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む