VsCodeでspring boot

VsCodeでspring bootで開発してみる

spring bootとは

昨年の新人研修でこれからはspring bootですよと言っていた生徒がいましたが、まったく手つかずでした。 今年もVscCodeでmavenとかやってましたが、もう少し開発が楽にならないかとspring bootをやってみることにしました

Springは多数のフレームワークから構成されているようで、spring Frameworkをベースとしたアプリケーション構築のためのフレームワークだそうです。 Springで開発するときのスターターキットのようなもので、この機能が欲しいから別のフレームワークを追加して、今度はこれと、自分で選んで追加できます。

Spring frameworkの基盤の上に、WebとSecurityを追加して、ログイン機能を作るような感じでできるようです。

構成要素

Spring Framework
Springの中核。この上に各フレームワークが乗る
Spring Boot
Springを使ってアプリケーションを高速開発するためのもの。いろいろなスターターパッケージがあるので、その中から似たものを選んでひな形を作る。
Spring Web(Spring Web MVC)
MVCアーキテクチャを使ったアプリケーション開発のフレームワーク
Spring WebFlux
1リクエストで1スレッド生成で返事を待つのではなく、並列処理できるリアクティブWeb開発ができる
Spring Data
データベースアクセスのフレームワーク。Spring Data JPAやSpring Data JDBCがある
Spring Security
Webのセキュリティ機能を提供する

spring bootをVsCodeでやってみる

例によって、VsCodeでやってみようと思います。実はその前にEclipseでもやってみましたが、同じことがVsCodeでできたので こちらでやることにしました

すでにVsCodeはインストール済みとしてMavenまで入れておきましょう。VsCode MavenでJavaを参考にしてください。

Vscodeの左の列の拡張機能からspringを検索して「Spring boot extension pack」を選んでインストールします。必要な4つほどの物が自動でインストールされます。VsCodeを再起動するのがいいでしょう。

install spring boot extension pack

また前述のようにMavenまたはgradleが使える環境にしておいてください。これから使用するSpring initializrはこの両方のコンパイル環境を作ってくれます。

Mavenの解説をします。Mavenでは「src」フォルダーと「target」フォルダー以下にそれぞれのファイルがまとめられます。最初はsrcの配下にソースを入れて、compileすることでtargetにclassやjarが出来ていきます。

またどのようなライブラリーを使用するのかを、srcやtargetの上のフォルダーにpom.xmlファイルを宣言して置いておきます。この中身はウイザードに答えると自動で生成されます。

今度作る予定のアプリ

Webなしのコマンドプロンプトアプリ
まずは単純にコマンドプロンプトにメッセージを出力するだけのもの
Modelを使用する
パラメータの受け渡しにModelを使うWeb
ModelAndViewを使用する
パラメータの受け渡しにModelAndViewを使うWeb
@Validを使ってみる
入力値の検査をクラスで行う実験
ログイン画面の実験
Spring Securityを使ってみる

Webなしのコマンドプロンプトアプリ

まずは単純なコマンドプロンプトを使ったアプリを作ります。

「CTRL+SHIFT+P」を押してコマンドパレットを表示します。Spring initializr:Create a Maven projectを選びます。

spring initilizr

適当なバージョンを選びます。(2024/6/25現在 3.3.1)。

spring initilizr:maven

今回はjavaでいきます

spring initilizr:maven

groupidをドメインの逆さまを小文字で入力します

spring initilizr:maven

artifactIdはプロジェクトの認識名でこれもスペースなしの小文字で入れます

spring initilizr:maven

パッケージで作製するものを選びます。今回はjarにします。複数のクラスができても一つにまとめてくれます。

spring initilizr:maven

javaのバージョンを入れます。17以降であればなんでも、結局eclipseのjavaが使用されました。

spring initilizr:maven

最後にspringのどの機能を追加するのか決めますが、今回はなんにも使わないので0selectをクリックしましょう。

spring initilizr:maven

自分できめたworkspaceの中にフォルダーを作成して、「select folder」します。

spring initilizr:maven

フォルダー群が自動で作成され、画面右下に色々質問が流れてきますが、私は全部「Yes」「Open」「Enable」で受け入れました。そうすると実行環境ができます。

spring initilizr:maven spring initilizr:maven

「src」フォルダー以下を展開していくとjavaのソースファイルが見えます。

src/main/java/com/example/springcmd/SpringcmdApplication.java
	package com.example.springcmd;

	import org.springframework.boot.SpringApplication;
	import org.springframework.boot.autoconfigure.SpringBootApplication;
	
	@SpringBootApplication
	public class SpringcmdApplication {
	
		public static void main(String[] args) {
			SpringApplication.run(SpringcmdApplication.class, args);
		}
	
	}

これがspringで生成されるデフォルトのソースファイルです。これをただのprintlnに変更します。

mainモジュール
		public static void main(String[] args) {
			System.out.println("Hello spring world!");
		}

これではspringではありませんが、まずは開発の流れの確認です。

左下にあるMavenのメニューから自分のプロジェクトを右クリックして「run maven command」でinstallをします

maven install

下にメッセージが出て止まるまで待ちます

maven install

同様にcompileしてBUILD SUCCESSが出るまで待ちます

maven install

mainのすぐ上にある「run」をクリックします。

run

結果が出ます

run

packageまでするとtargetの下にjarファイルができるので、コマンドプロンプトで実行もできます

run

Modelを使用する

次にservletからhtmlへパラメータを渡すサンプルを作ります。まずはModelクラスとThymeleaf(タイムリーフ)テンプレートを使います。

Thymeleafを使うとjspファイルのようにhtmlとjavaを混在したものが書けますが、jspと違ってパラメータの受け取り部分などを書く必要がなく、直接表示できるような記述が可能です。

そこに向けて変数をパラメータ渡しするのにModelクラスを使用します。jspではタグのコンテンツ部分に<%= md.getSmemo() %>のように変数や関数を記述しますが、 thymeleafでは、タグの属性(attribute)として特殊な記述をします。<p th:text="${message}"></p>とすると、コンテンツとしてmessage変数の内容が表示されます。

作り始めはコマンドプロンプトの時と同じで「CTRL+SHIFT+P」で「spring init」からspring initializr:create a maven projectを選択します。

そして「select dependencies」のところで「Spring Web web」と「Thymeleaf template engines」を選択しておきます。

model dependencies

このようにしてプロジェクトを作成するとそれなりのpom.xmlができます。

springmodetest/pom.xml抜粋
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

ウィザードでwebとthymeleafを追加したのでそれらが入っています。また-testはすべてに追加されています。

ところでいつものようにBootstrap5を入れたいのですが、springでも対応しているので次のdependencyを追加してください。

spring対応のbootsrapの追加 pom.xml抜粋
	<dependency>
		<groupId>org.webjars</groupId>
		<artifactId>bootstrap</artifactId>
		<version>5.3.0</version>
	</dependency>

さて、これで準備ができたので、ソースを作ってきます。今回作るのは、日付を指定して、その前後の日付を計算するという簡単なアプリです。

では、index.htmlを作っていきましょう。jspではありません。thymeleafではhtmlで作成します。

resources配下のtempletes配下に新しいファイルを追加します。名前はindex.htmlとします。

index.html

内容としては、input type="date"で入力したsdate変数とinput type="number"で入力したdplus変数を受け取って、結果を計算して次のresult.htmlのmessageに渡すというものです。

resources/templetes/index.html
	<!doctype html>
	<html lang="ja" xmlns:th="http://www.thymeleaf.org">
	  <head>
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width, initial-scale=1.0">
		<title>Bootstrap demo</title>
		<link th:href="@{/webjars/bootstrap/5.3.0/css/bootstrap.min.css}" rel="stylesheet">
	  </head>
	  <body>
		<div class="container">
		  <main>
			<div class="py-5 text-center">
			  <h2>Model test</h2>
			  <p class="lead" th:text="${message}"></p>
			</div>
			<div class="text-center">
			  <h4 class="mb-3">日付計算</h4>
			  <form class="needs-validation" th:action="@{/result}" method="POST">
				  <div class="row g-12">
					<div class="col-sm-6">
					  <label for="sdate" class="form-label">日付</label>
					  <input type="date" class="form-control" id="sdate" name="sdate" placeholder="yyyy-MM-ddで日付を記述してください" value="" required>
					</div>
		
					<div class="col-sm-6">
					  <label for="dplus" class="form-label">前後日付</label>
					  <input type="number" class="form-control" id="dplus" name="dplus" placeholder="+ -付きで日付を入力してください" value="" required>
					</div>
				  </div>
		
				  <hr class="my-4">
		
				  <button class="w-100 btn btn-primary btn-lg" type="submit">計算実行</button>
			  </form>
			</div>
		  </main>
		
		  <footer class="my-5 pt-5 text-body-secondary text-center text-small">
			<p class="mb-1">© 2024 Etlab</p>
		  </footer>
		</div>
		<script th:src="@{/webjars/bootstrap/5.3.0/js/bootstrap.min.js}"></script>
	  </body>
	</html>

最初に、index.htmlの先頭でthymeleafの宣言をしています。またbootstrapはwebjarsフォルダー以下にインストール済みなので、それを利用します。bootstrapで画面を作成しています。

index.html画面

この画面が呼ばれるのがリクエストが localhost:8080/ の時です。そこで呼び出しの部分を作成します。

パッケージのspmodeltestフォルダーで右クリックして、「new java file」 「class」で「DateController.java」を作ります。

クラス作成

先に作ってあった「SpmodeltestApplication.java」ソースは何も触りません。触らなくても@アノテーションを付けることによって自動的に検索して連動してくれるようになります。

main/java/jp/co/etlab/spmodeltest/DateController.java
	package jp.co.etlab.spmodeltest;

	import org.springframework.stereotype.Controller;
	import org.springframework.ui.Model;
	import org.springframework.web.bind.annotation.RequestMapping;
	import org.springframework.web.bind.annotation.RequestMethod;
	import org.springframework.web.bind.annotation.RequestParam;
	
	
	@Controller
	public class DateController {
		@RequestMapping(value="/", method=RequestMethod.GET)
		public String index(Model model) {
			model.addAttribute("message", "日付の計算を行います。日付と差分を入力してください。");
			return "index";
		}
	}

クラスにつけた@Controllerアノテーションを付けることで、このクラスがMVC機能のコントローラー機能を持つことになります。 そして@RequestMappingアノテーションでどのURLの時にどのモジュールが呼ばれるかを指定します。今回はindex()関数がGETでリクエストを受けた時のエントリーポイントとなります。

関数名はなんでも構いません。そして今回の目的であるModelクラスを引数に記述します。オブジェクトのmodelにaddAttributeする形でmessage変数に文字列を代入しています。これが先ほどのindex.htmlの@{message]に渡ります。

そしてreturnがString型のhtmlファイル名になります。htmlは省略できるので、"index"で大丈夫です。

これでindex.htmlを呼び出して入力画面を出すところまでできました。

続いて、index.htmlでsubmitボタンが押された時の行先の設定の部分のプログラムをこのクラスの後方に連続して記述します。

DateController.java さきほどの続き
    @RequestMapping(value="/result", method=RequestMethod.POST)
    public String datecalc(@RequestParam("sdate") String ssdate,
                        @RequestParam("dplus") String splusd, Model model) {
        DateModel dm = new DateModel();
        dm.setSdate(ssdate);
        dm.setDplus(splusd);
        //計算
        dm.calcDate();
        model.addAttribute("message", dm.getSdate() + " の" + Math.abs(dm.getDplus()) +
            "日" + (dm.getDplus()>0 ? "後" : "前") + "は " + dm.getCdate() + "です");
        return "result";
    }

index()関数の兄弟としてdatecalc()関数を記述します。@RequestMappingアノテーションの働きにより、URL localhost:8080/result のPOSTの時に起動されるように指定されます。

datecalc()関数の引き数として、@RequestParamアノテーションでsdateとdplusが指定されています。これによってindex.htmlで入力された値はここで受信されます。そしてここにもModelクラスがあり、result.htmlへのパラメータ渡し用に準備されています。

ここで少しこのソースから離れて、今回必須ではないDateModel.javaに関して説明します。これがなくてもパラメータのやり取りはできます。ただ今後の流れの関係でここで宣言しています。

このDateModelクラスに受け渡しする変数と計算を入れておきます。さきほどDateController.javaファイルを作ったのと同じ流れでDateModel.javaを追加してください。

spmodeltest/DateModel.java
	package jp.co.etlab.spmodeltest;

	import java.time.LocalDate;
	import java.time.format.DateTimeFormatter;
	
	public class DateModel {
		DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd");
	
		/* 日付 */
		private LocalDate sdate;
	
		/* 前後日数 */
		private int dplus;
	
		/* 計算日付 */
		private LocalDate cdate;
	
		public LocalDate getSdate() {
			return sdate;
		}
	
		public void setSdate(LocalDate sdate) {
			this.sdate = sdate;
		}
		public void setSdate(String ssdate) {
			this.sdate = LocalDate.parse(ssdate,fmt);
		}
	
		public int getDplus() {
			return dplus;
		}
	
		public void setDplus(int dplus) {
			this.dplus = dplus;
		}
		public void setDplus(String sdplus) {
			this.dplus = Integer.parseInt(sdplus);
		}
	
		public LocalDate getCdate() {
			return cdate;
		}
		public String getScdate() {
			return this.cdate.format(fmt);
		}
	
		/* 日付計算 */
		public void calcDate() {
			LocalDate tmp = this.sdate.plusDays(this.dplus);
			this.cdate = tmp;
		}
		
	}

このクラスのオブジェクトをdatecalc()関数で作成し、パラメータを格納し、計算しています。計算ができたらresult.htmlへmessage変数として送っています。

さて今度はそのresult.htmlです

templetes/result.html
	<!doctype html>
	<html lang="ja" xmlns:th="http://www.thymeleaf.org">
	  <head>
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width, initial-scale=1.0">
		<title>Bootstrap demo</title>
		<link th:href="@{/webjars/bootstrap/5.3.0/css/bootstrap.min.css}" rel="stylesheet">
	  </head>
	  <body>
		<div class="container">
		  <main>
			<div class="py-5 text-center">
			  <h2>Model test</h2>
			  <p class="lead">日付計算の結果です</p>
			  <p class="my-5" th:text="${message}"></p>
			  <hr class="my-4">
			  <a href="/" class="btn btn-outline-primary" role="button">再計算</a>
			</div>
		  </main>
		
		  <footer class="my-5 pt-5 text-body-secondary text-center text-small">
			<p class="mb-1">© 2024 Etlab</p>
		  </footer>
		</div>
		<script th:src="@{/webjars/bootstrap/5.3.0/js/bootstrap.min.js}"></script>
	  </body>
	</html>

では、これをコンパイルしていきましょう。mavenを使用します。先ほどコマンドプロンプトでやったのと同じ手法でinstall,compileを行ってください。

実行方法が少し違います。今度はWebになりますので、springで起動するとserverが起動されてそこに今作成したアプリが登録されます。

mainの上のrunをクリックして起動してください。

tomcat起動

このようにtomcatにspmodeltestが登録されます。そしてブラウザを起動してurlを入力します。

8080起動

日付と差分を入力して、計算実行をクリックすると、

result起動

計算結果がresult.htmlで表示されます。「再計算」をクリックすれば、GETで/に飛んでいくのでまた計算できます。

最後に終了の仕方です。tomcatが起動されてますが、これはプログラムの実行とは関係なく動いています。 なので、tomcatは別に止める必要があります。

tomcat停止

停止ボタンで留めるとtomcatが停止します。