[SpringBoot2.4.3] Thymeleaf リンク

	<p><a th:href="@{'/home/' + ${param.id[0]}}">link</a></p>

ん? なんかうまくいかんけど。。

@Controller
public class HelloController {
	
	@RequestMapping("/")
	public ModelAndView index(ModelAndView mav) {
		mav.setViewName("index");
		mav.addObject("msg", "current data.");
		DataObject obj = new DataObject(123, "hanako", "hanako@flower");
		mav.addObject("object",obj);
		return mav;
	}
}

class DataObject{
    
    private int id;
    private String name;
    private String value;
     
    public DataObject(int id, String name, String value) {
        super();
        this.id = id;
        this.name = name;
        this.value = value;
    }
     
    public int getId() {return id;}
    public void setId(int id) {this.id = id;}
     
    public String getName() {return name;}
    public void setName(String name) {this.name = name;}
     
    public String getValue() {return value;}
    public void setValue(String value) {this.value = value;}
}
	<h1>Helo page</h1>
	<p th:text="${msg}">message.</p>
	<table th:object="${object}">
		<tr><th>ID</th><td th:text="*{id}"></td></tr>
		<tr><th>NAME</th><td th:text="*{name}"></td></tr>
		<tr><th>MAIL</th><td th:text="*{value}"></td></tr>
	</table>

リテラル置換

	<div th:object="${object}">
		<p th:text="|my name is *{name}. mail address is *{value}.|">message.</p>
	</div>

http://localhost:8080/
my name is hanako. mail address is hanako@flower.

うおおおお、凄え

### htmlを出力

	@RequestMapping("/")
	public ModelAndView index(ModelAndView mav) {
		mav.setViewName("index");
		mav.addObject("msg", "message 1<hr/>message 2<hr/>message 3");
		return mav;
	}
	<p th:utext="${msg}">message.</p>

unescape

早くアプリ作りてえな

[SpringBoot2.4.3] Thymeleafを学習する

直書きもできる。

	<h1>Helo page</h1>
	<p th:text="${new java.util.Date().toString()}"></p>

util object

	<p th:text="${#dates.format(new java.util.Date(),'dd/MMM/yyyy HH:mm')}"></p>
	<p th:text="${#numbers.formatInteger(1234,7)}"></p>
	<p th:text="${#strings.toUpperCase('welcome to Spring!')}"></p>

28/2月/2021 13:03

0001234

WELCOME TO SPRING!
これはすぐわかるね。

<p th:text="'from parameter... id=' + ${param.id[0] +',name=' + param.name[0]}"></p>

http://localhost:8080/home?id=123&name=taro
from parameter… id=123,name=taro

### message
messages.properties

content.title=message sample page.
content.message=this is sample message from properties

Property or field ‘message’ cannot be found on null
at org.springframework.expression.spel.ast.PropertyOrFieldReference.readProperty(PropertyOrFieldReference.java:213) ~[spring-expression-5.3.4.jar:5.3.4]
at org.springframework.expression.spel.ast.PropertyOrFieldReference.getValueInternal(PropertyOrFieldReference.java:104) ~[spring-expression-5.3.4.jar:5.3.4]
at org.springframework.expression.spel.ast.PropertyOrFieldReference.access$000(PropertyOrFieldReference.java:51) ~[spring-expression-5.3.4.jar:5.3.4]

ん?
再起動したら行けた

なんかよーわからんなw

[SpringBoot2.4.3] ページ移動(フォワード/リダイレクト)

Controller

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class HelloController {
	
	@RequestMapping("/")
	public ModelAndView index(ModelAndView mav) {
		mav.setViewName("index");
		return mav;
	}
	@RequestMapping("/other")
	public String other() {
		return "redirect:/";
	}
	@RequestMapping("/home")
	public String home() {
		return "forward:/";
	}
}


forwardを使う用途がわからんが、実装方法はわかった。

[SpringBoot2.4.3] フォームコントロール

	<form method="post" action="/">
		<div>
			<input type="checkbox" id="check1" name="check1">
			<label for="check1">チェック</label>
		</div>
		<div>
			<input type="radio" id="radioA" name="radio1" value="male">
			<label for="radioA">男性</label>
		</div>
		<div>
			<input type="radio" id="radioB" name="radio1" value="femail">
			<label for="radioB">女性</label>
		</div>
		<div>
			<select id="select1" name="select1" size="4">
				<option value="Windows">Windows</option>
				<option value="Mac">Mac</option>
				<option value="Linux">Linux</option>
			</select>
		</div>
		<div>
			<select id="select2" name="select2" size="4" multiple="multiple">
				<option value="Android">Android</option>
				<option value="iphone">iPhone</option>
				<option value="Winfone">Windows Phone</option>
			</select>
		</div>
		<input type="submit" value="Click">
	</form>

Controller

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.RequestParam;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class HelloController {
	
	@RequestMapping(value="/", method=RequestMethod.GET)
	public ModelAndView index(ModelAndView mav) {
		mav.setViewName("index");
		mav.addObject("msg", "フォームを送信してください。");
		return mav;
	}
	
	@RequestMapping(value="/", method=RequestMethod.POST)
	public ModelAndView send(
			@RequestParam(value="check1",required=false) boolean check1,
			@RequestParam(value="radio1",required=false) String radio1,
			@RequestParam(value="select1",required=false) String select1,
			@RequestParam(value="select2",required=false) String[] select2,
			ModelAndView mav) {
		
		String res = "";
		try {
			res = "check:" + check1 + " radio:" + radio1 + " select:" + select1 + "\nselect2:";
		} catch(NullPointerException e) {}
		try {
			res += select2[0];
			for(int i = 1; i < select2.length; i++) 
				res += ", " + select2[i];
			} catch (NullPointerException e) {
				res += "null";
			}
		mav.addObject("msg", res);
		mav.setViewName("index");
		return mav;
	}
}

そこそこ来てる? 学習途中はどこら辺にいるかさっぱり見当がつかないなー

[SpringBoot2.4.3] thymeleafを使う

controller

package com.example.demo;

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

@Controller
public class HelloController {
	
	@RequestMapping("/")
	public String index() {
		return "index";
	}	
}

html

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Document</title>
	<style>
		h1 {
			font-size:18px;
			font-weight:bold;
			color:gray;
		}
		body {
			font-size:13px;
			color:gray;
			margin:5px 25px;
		}
	</style>
</head>
<body>
	<h1>Helo page</h1>
	<p class="msg">This is Thymeleaf sample page.</p>
</body>
</html>

<p class="msg" th:text="${msg}">This is Thymeleaf sample page.</p>
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.PathVariable;

@Controller
public class HelloController {
	
	@RequestMapping("/{num}")
	public String index(@PathVariable int num, Model model) {
		int res = 0;
		for(int i = 1; i <= num; i++)
			res += i;
		model.addAttribute("msg", "total: "+ res);
		return "index";
	}	
}

ModelはWebページで利用するデータを管理するためのクラス

### formを使う

<body>
	<h1>Helo page</h1>
	<p class="msg" th:text="${msg}">Please wait...</p>
	<form method="post" action="/">
		<input type="text" name="text1" th:value="${value}">
		<input type="submit" value="click">
	</form>
</body>
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.RequestParam;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class HelloController {
	
	@RequestMapping(value="/", method=RequestMethod.GET)
	public ModelAndView index(ModelAndView mav) {
		mav.setViewName("index");
		mav.addObject("msg", "お名前を書いて送信してください。");
		return mav;
	}
	
	@RequestMapping(value="/", method=RequestMethod.POST)
	public ModelAndView send(@RequestParam("text1")String str, ModelAndView mav) {
		mav.addObject("msg", "こんにちは、" + str + "さん!");
		mav.addObject("value", str);
		mav.setViewName("index");
		return mav;
	}
}

なるほどー

[SpringBoot2.4.3] RestControllerを利用する

RestControllerはビューを使わずコントローラーだけでアプリの基本部分を作成できる

package com.example.demo;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {
	
	@RequestMapping("/")
	public String index() {
		return "Hello Spring-Boot World!";
	}
}

http://localhost:8080/
Hello Spring-Boot World!

### パラメータを渡す

package com.example.demo;

import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {
	
	@RequestMapping("/{num}")
	public String index(@PathVariable int num) {
		int res = 0;
		for(int i = 1; i <= num; i++)
			res += i;
		return "total: " + res;
	}
}

http://localhost:8080/5
total: 15

おおお、一周回って基礎やると理解しやすいな。

### DataObject

package com.example.demo;

import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {
	
	String[] names = {"hpscript","hanako","taro","sachiko","ichiro"};
	String[] mails = {"info@hpscript.com", "hanako@gmail.com", "taro@gmail.com","sachiko@gmail.com","ichiro@gmail.com"};
	
	@RequestMapping("/{id}")
	public DataObject index(@PathVariable int id) {
		return new DataObject(id, names[id],mails[id]);
	}
	
}
class DataObject{
	
	private int id;
	private String name;
	private String value;
	
	public DataObject(int id, String name, String value) {
		super();
		this.id = id;
		this.name = name;
		this.value = value;
	}
	
	public int getId() {return id;}
	public void setId(int id) {this.id = id;}
	
	public String getName() {return name;}
	public void setName(String name) {this.name = name;}
	
	public String getValue() {return value;}
	public void setValue(String value) {this.value = value;}
}

http://localhost:8080/2
{“id”:2,”name”:”taro”,”value”:”taro@gmail.com”}
http://localhost:8080/0
{“id”:0,”name”:”hpscript”,”value”:”info@hpscript.com”}

おおお、なんか変に感傷的になるな〜

[SpringBoot2.4.3] テストアプリケーションを作る

gradleで作ります。

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
	implementation 'org.springframework.boot:spring-boot-starter-mustache'
	implementation 'org.springframework.boot:spring-boot-starter-web'
	implementation 'org.flywaydb:flyway-core'
	developmentOnly 'org.springframework.boot:spring-boot-devtools'
	runtimeOnly 'org.postgresql:postgresql'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

YAMLファイルの作成
src/main/resources/application.yml

spring:
  datasource:
    url:jdbc:postgresql://localhost:5432/test
    driverClassName:org.postgresql.Driver
    username:root
    password:
  mvc:
   favicon:
     enabled:false

ん? Nullにするとエラーになるな

V1__Create.sql

create table tsubuyaki (
	id serial primary key,
	txt varchar(100) not null,
	version integer not null default 0,
	updated_time timestamp not null default current_timestamp,
	created_time timestamp not null default current_timestamp
);

Model

package com.example.demo.model;

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

import org.hibernate.validator.constraints.NotEmpty;

@Entity
public class Tsubuyaki extends TimestampEntity {
	
	@Id @GeneratedValue(strategy=GenerationType.IDENTITY)
	public long id;
	
	@NotEmpty
	public String txt;
	
	@Version
	public long version;
}
package com.example.demo.model;

import java.sql.Timestamp;
import java.util.Date;

import javax.persistence.Column;
import javax.persistence.MappedSuperclass;
import javax.persistence.PrePersist;
import javax.persistence.PreUpdate;

@MappedSuperclass
public abstract class TimestampEntity {
	
	public Timestamp updatedTime;
	
	@Column(updatable=false)
	public Timestamp createdTime;
	
	@PrePersist
	public void prePersist() {
		Timestamp ts = new Timestamp((new Date()).getTime());
		this.createdTime = ts;
		this.updatedTime = ts;
	}
	
	@PreUpdate
	public void preUpdate() {
		this.updatedTime = new Timestamp((new Date()).getTime());
	}
}

Repository

package com.example.demo.repository;

import org.springframework.data.repository.CrudRepository;

import com.example.demo.model.Tsubuyaki;

public interface TsubuyakiRepository extends
CrudRepository<Tsubuyaki, Long>{
	Iterable<Tsubuyaki> findAllByOrderByUpdatedTimeDesc();
}

controller

package com.example.demo.controller;

import java.util.Collections;
import java.util.Map;

import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.example.demo.model.Tsubuyaki;
import com.example.demo.repository.TsubuyakiRepository;

@RestController @RequestMapping("/tsubuyaki")
public class TsubuyakiController {
	
	@Autowired TsubuyakiRepository repo;
	
	@RequestMapping(method=RequestMethod.POST)
	public Map<String, Tsubuyaki> create(
			@Valid @RequestBody Tsubuyaki tsubuyaki
			){
			return Collections.singletonMap(
					"tsubuyaki", repo.save(tsubuyaki));
		
	}
	@RequestMapping(method=RequestMethod.GET)
	public Map<String, Tsubuyaki> read(){
			return Collections.singletonMap(
					"tsubuyaki", repo.findAllByOrderByUpdatedTimeDesc());
		
	}
	@RequestMapping(path="/{id}", method=RequestMethod.PUT)
	public void update(
			@PathVariable Long id, @RequestParam String txt
			){
			Tsubuyaki tsubuyaki = repo.findOne(id);
			tsubuyaki.txt = txt;
			repo.save(tsubuyaki);
	}
	@RequestMapping(path="/{id}", method=RequestMethod.DELETE)
	public void delete(
			@PathVariable Long id
			){
			repo.delete(id);
	}
	
}

ぐぬぬぬ。。。

[SpringBoot2.4.3] よく使われるannotation

@Controller
画面遷移用のコントローラーに付与

@RestController
リクエストを受け付けるコントローラークラス

@RequestMapping(“path”)
マッピングするURLの接頭辞を設定

@GetMapping(“path”)
GETメソッドを受け取るメソッド

@PostMapping(“path”)
POSTメソッドを受け取る為のメソッドに付与

@Service
サービスクラス

@ComponentScan
特定のアノテーションが付与されたクラスのBeanをDIに登録

@Bean
DIコンテナに管理させたいBeanを生成するメソッドに付与

@Data
コンパイル時に、setter, getter, toString, equals, hashCodeなどのメソッド生成

@Autowired
特定のアノテーションを付与したクラスのインスタンスを使用できるようにする

@ModelAttribute
返り値は自動的にmodelに追加

@Validated
Bean Validationアノテーションが評価され、結果がBindingResultに格納

@PathVariable
Rest形式のパラメータを受け取る

@RequestParam
リクエストパラメータを受け取る

@Entity
JPAエンティティ

@Table(name=”table name”)
エンティティに対応するテーブル名を指定

@GeneratedValue
auto increment

@GeneratedValue(strategy = GenerationType.SEQUENCE, generator=”シーケンス名”)
SEQ_IDで自動採番

@Transactional
クラス内に付与するとDBのトランザクション制御

@AllArgsConstructor
全フィールドを引数にもつコンストラクタ生成

@NoArgsConstructor
引数がないコンストラクタ

@Column
カラムに名前や制約を設定

@Query(“JPQL”)
データへのアクセスを自作する際に使用

@NotNull, @NotEmpty, @NotBlank, @Size(min=,max), @Email, @AssertTrue, @AssertFalse, @Pattern, @DateTimeFormat

@SpringBootApplication
Spring Bootの様々な設定を自動的に有効にする

@EnableAutoConfiguration
Spring Bootの様々な設定を自動的に有効にする

@Configuration
JavaConfig用のクラスであることを示す

@Qualifier(“Bean name”)
同じ型のBeanがDIコンテナに複数登録されている場合に適用する

アノテーションをきちんと理解しないと、SpringBootは使いこなせんな。

[SpringBoot2.4.3] Scheduling

Controller

package com.example.demo;

import java.util.Date;
import java.text.SimpleDateFormat;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;

@SpringBootApplication
@EnableScheduling
public class HelloController {
	
	private static final SimpleDateFormat
	fmt = new SimpleDateFormat("HH:mm:ss");
	
	@Scheduled(fixedRate = 5000)
	public void reportTime() {
		System.out.println(fmt.format(new Date()));
	}
	
	public static void main(String[] args) {
		SpringApplication.run(HelloController.class, args);
	}
}

==========================
CONDITION EVALUATION DELTA
==========================

Positive matches:
—————–

TaskSchedulingAutoConfiguration#taskScheduler matched:
– @ConditionalOnBean (names: org.springframework.context.annotation.internalScheduledAnnotationProcessor; SearchStrategy: all) found bean ‘org.springframework.context.annotation.internalScheduledAnnotationProcessor’; @ConditionalOnMissingBean (types: org.springframework.scheduling.annotation.SchedulingConfigurer,org.springframework.scheduling.TaskScheduler,java.util.concurrent.ScheduledExecutorService; SearchStrategy: all) did not find any beans (OnBeanCondition)

Negative matches:
—————–

None

Exclusions:
———–

None

Unconditional classes:
———————-

None

16:02:28
16:02:33
16:02:38
16:02:43
16:02:48
16:02:53
16:02:58
16:03:03
16:03:08
16:03:13
16:03:18
16:03:23
16:03:28
16:03:33
16:03:38

なんやこれは、すげえ

[SpringBoot2.4.3] MessageSource

application.propertiesの設定
メッセージを messages_ja.properties で設定できるようにする
application.properties

spring.messages.basename=messages
spring.messages.cache-seconds=-1
spring.messages.encoding=UTF-8

messages_ja.properties

key=\u3053\u3093\u306B\u3061\u306F\u3002

Controller

String message = msg.getMessage("key",null,Locale.JAPAN);

@RequestMapping(value="/msg", method=RequestMethod.GET)
public Map<String, String> msg(Locale locale){
	String message = msg.getMessage("key", null, locale);
	return Collections.singletonMap("message", message);
}

なるほどー