[SpringBoot2.4.3] Thymeleafインライン・レイアウト2

### th:each
controller

	@RequestMapping("/{month}")
	public ModelAndView index(ModelAndView mav) {
		mav.setViewName("index");
		ArrayList<String[]> data = new ArrayList<String[]>();
		data.add(new String[] {"taro","taro@yamada","090-999-999"});
		data.add(new String[] {"hanako","hanako@sato","080-888-888"});
		data.add(new String[] {"sachiko","sachiko@saito","080-888-888"});
		mav.addObject("data",data);
		return mav;
	}
	<table>
		<tr>
			<th>NAME</th>
			<th>MAIL</th>
			<th>TEL</th>
		</tr>
		<tr th:each="obj:${data}">
			<td th:text="${obj[0]}"></td>
			<td th:text="${obj[1]}"></td>
			<td th:text="${obj[2]}"></td>
		</tr>
	</table>

### プリプロセッシング
-> 式の一部を事前に評価させ、その結果を元に変数式を実行する
概念がイマイチよくわからんが。。

	@RequestMapping("/{num}")
	public ModelAndView index(@PathVariable int num, ModelAndView mav) {
		mav.setViewName("index");
		mav.addObject("num",num);
		if (num > 0) {
			mav.addObject("check","num >= data.size() ? 0 : num");
		} else {
			mav.addObject("check", "num <= data.size() * -1 ? 0 : num * -1");
		}
		ArrayList<DataObject> data = new ArrayList<DataObject>();
		data.add(new DataObject(0, "taro","taro@yamada"));
		data.add(new DataObject(1, "hanako","hanako@sato"));
		data.add(new DataObject(2, "sachiko","sachiko@saito"));
		mav.addObject("data",data);
		return mav;
	}

html

	<p th:text="|expression[ ${check} ]|"></p>
	<table th:object="${data.get(__${check}__)}">
		<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>


ん? 意味がわからん。

### インライン処理
th:inline=”text”と書くと、そのタグの内部のみインライン処理が可能になる

	@RequestMapping("/")
	public ModelAndView index(ModelAndView mav) {
		mav.setViewName("index");
		ArrayList<DataObject> data = new ArrayList<DataObject>();
		data.add(new DataObject(0, "taro","taro@yamada"));
		data.add(new DataObject(1, "hanako","hanako@sato"));
		data.add(new DataObject(2, "sachiko","sachiko@saito"));
		mav.addObject("data",data);
		return mav;
	}

html

	<table th:inline="text">
		<tr>
			<th>ID</th>
			<th>NAME</th>
			<th>MAIL</th>
		</tr>
		<tr th:each="obj: ${data}">
			<td>[[${obj.id}]]</td>
			<td>[[${obj.name}]]</td>
			<td>[[${obj.value}]]</td>
		</tr>
	</table>

#### jsのインライン処理

	@RequestMapping("/{tax}")
	public ModelAndView index(@PathVariable int tax, ModelAndView mav) {
		mav.setViewName("index");
		mav.addObject("tax",tax);
		return mav;
	}
	<h1>Helo page</h1>
	<p id="msg"></p>
	<input type="text" id="text1">
	<button onclick="action()">click</button>
	<script th:inline="javascript">
	function action(){
		var val = document.getElementById("text1").value;
		var res = parseInt(val * ((100 + /*[[${tax}]]*/) /100 ));
		document.getElementById("msg").innerHTML = "include tax: " + res;
	}
	</script>

js側に渡せるってこと?
よくわからんが凄え。

[SpringBoot2.4.3] Thymeleafインライン・レイアウト1

controller

	@RequestMapping("/{id}")
	public ModelAndView index(@PathVariable int id, ModelAndView mav) {
		mav.setViewName("index");
		mav.addObject("id", id);
		mav.addObject("check", id % 2 == 0);
		mav.addObject("trueVal", "Even number!");
		mav.addObject("falseVal", "Odd number...");
		return mav;
	}
	<p th:text="${id} + ' is '+ (${check} ? ${trueVal} : ${falseVal})"></p>


thymeleaf側で計算すると不思議な感じするなー

	@RequestMapping("/{id}")
	public ModelAndView index(@PathVariable int id, ModelAndView mav) {
		mav.setViewName("index");
		mav.addObject("id", id);
		mav.addObject("check", id  >= 0);
		mav.addObject("trueVal", "POSITIVE!");
		mav.addObject("falseVal", "negative...");
		return mav;
	}
	<p th:if="${check}" th:text="${id} + ' is ' + ${trueVal}">message.</p>
	<p th:unless="${check}" th:text="${id} + ' is ' + ${falseVal}">message.</p>

なんやこれ

	@RequestMapping("/{month}")
	public ModelAndView index(@PathVariable int month, ModelAndView mav) {
		mav.setViewName("index");
		int m = Math.abs(month) % 12;
		m = m == 0 ? 12 : m;
		mav.addObject("month", m);
		mav.addObject("check", Math.floor(m / 3));
		return mav;
	}
	<p th:if="${check}" th:text="${id} + ' is ' + ${trueVal}">message.</p>
	<div th:switch="${check}">
		<p th:case="0" th:text="|${month} - Winter|"></p>
		<p th:case="1" th:text="|${month} - Spring|"></p>
		<p th:case="2" th:text="|${month} - Summer|"></p>
		<p th:case="3" th:text="|${month} - Autumn|"></p>
		<p th:case="4" th:text="|${month} - Winter|"></p>
		<p th:case="*">...?</p>
	</div>

なんやこれは。。。普段きちんとコーディングしているかどうか一発でわかるな。ビビるわ。

[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] フォームコントロール

	<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.2] URLのパスを取得してjdbcTemplateでedit画面を作成する

まずtemplates に edit.html を作ります。

<div class="form-group">
	    <label class="control-label col-md-2">名前</label>
	    <div class="col-md-4">
	        <input type="text" class="form-control" name="name" th:value="${name}">
	    </div>
	</div>
	<div class="form-group">
        <label class="control-label col-md-2">所属部署</label>
        <div class="col-md-4">
            <input type="text" class="form-control" name="department" th:value="${department}">
        </div>
    </div>

続いて、indexからeditへのリンク。これは、/edit/${userId}とします。

<td th:text="${list.id}"></td><td th:text="${list.name}">狩野 良平</td><td th:text="${list.department}">営業部</td><td><a th:href="'/edit/' + ${list.id}"><button type="button" class="btn btn-secondary">編集</button></a></td><td><a th:href="'/delete/' + ${list.id}"><button type="button" class="btn btn-danger" onclick="location.href='/delete_complete.html'">削除</button></a></td>

UsersRepository.java
L jdbcTemplate.queryForMapで取得する

public Users selectOne(Long id) throws DataAccessException {
        // SQL文を作成
        String sql = ""
            + "SELECT"
                + " *"
            + " FROM"
                + " users"
            + " WHERE"
                + " id = ?";
        Map<String, Object> users = jdbcTemplate.queryForMap(sql, id);

        // Userオブジェクトに格納する。
        Users user = new Users();
        user.setName((String)users.get("name"));
		user.setDepartment((String)users.get("department"));
        return user;
    }

MainController.java

	@GetMapping("edit/{userId}")
	public String editForm(@PathVariable("userId") long userId, Model model) {
		Users user = usersRepository.selectOne(userId);
        model.addAttribute("name", user.getName());
        model.addAttribute("department", user.getDepartment());
        return "test1/edit";
	}

まじかよ、これ作るの3時間半くらいかかったんだけど。。。

[SpringBoot2.4.2] thymeleafの入力データをpostgresにINSERTする

pom.xml

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jdbc</artifactId>
		</dependency>
		
		<dependency>
			<groupId>org.postgresql</groupId>
			<artifactId>postgresql</artifactId>
			<scope>runtime</scope>
		</dependency>

application.properties

spring.jpa.database=POSTGRESQL
spring.datasource.url=jdbc:postgresql://localhost:5432/test
spring.datasource.username=root
spring.datasource.password=

### データ格納用のDBテーブル作成
$ psql -U root test
psql: error: could not connect to server: No such file or directory
Is the server running locally and accepting
connections on Unix domain socket “/tmp/.s.PGSQL.5432”?
ん?
$ postgres -D /usr/local/var/postgres
$ brew services restart postgresql
test=> \d
test=> CREATE TABLE users (
id SERIAL NOT NULL,
name varchar(255),
department varchar(255),
PRIMARY KEY(id)
);

### Repository
Users.java

package com.example.demo;

public class Users {
	private Integer id;
	private String name;
	private String department;

	public Integer getId() {
		return id;
	}
	public String getName() {
		return name;
	}
	public String getDepartment() {
		return department;
	}
	public void setName(String name) {
		this.name = name;
	}
	public void setDepartment(String department) {
		this.department = department;
	}
}

UsersRepository.java

package com.example.demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

@Repository
public class UsersRepository {
	
	private final JdbcTemplate jdbcTemplate;
	
	@Autowired
	public UsersRepository(JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	}
	
	public void insertUsers(Users users) {
		jdbcTemplate.update("INSERT INTO users(name,department) Values (?,?)",
				users.getName(), users.getDepartment());
	}
}

MainController.java

package com.example.demo;
import org.springframework.stereotype.Controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
@RequestMapping("/test1")
public class MainController {
	@Autowired
	private UsersRepository usersRepository;
	
	
	@GetMapping("input")
	public String input1() {
		return "test1/input";
	}
	
	@GetMapping("inputconfirm")
	public String output1(
			@RequestParam(name = "name") String name,
			@RequestParam(name = "department") String department,
			Model model) {
			model.addAttribute("name", name);
			model.addAttribute("department", department);
			return "test1/input_confirm";
	}
	
	@GetMapping("inputcomplete")
	public String output2(
			@RequestParam(name = "name") String name,
			@RequestParam(name = "department") String department,
			Model model) {
		    Users users = new Users();
		    users.setName(name);
		    users.setDepartment(department);
		    usersRepository.insertUsers(users);
		    
			model.addAttribute("name", name);
			model.addAttribute("department", department);
			return "test1/input_complete";
	}
	
}

view

postgres側
test=> select * from users;
id | name | department
—-+———-+————
1 | 山田太郎 | 営業部
(1 row)

test=> select * from users;
id | name | department
—-+————+————
1 | 山田太郎 | 営業部
2 | 佐藤 祐一 | 経理部
(2 rows)

入力できてるーーーーーーーーーーーーーーーーー
ぎゃあああああああああああああああああああああああああああああ
😇😇😇😇😇😇😇😇😇😇😇😇😇

なんとなくServiceとRepositoryとControllerとthymeleafの関係性がわかってきたああああああああああ

[Spring Boot2.4.2] Thymeleafで共通レイアウトを使用する

src/main/resources/templates/test1/partial1.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<header th:fragment="header1">
<p style="background:yellow;">ヘッダーです</p>
</header>
<footer th:fragment="footer1">
<p style="background:yellow;">フッターです</p>
</footer>
</html>

src/main/resources/templates/test1/index.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
  <head>
    <meta charset="utf-8" />
    <title>Check</title>
  </head>
  <body>
    <div th:replace="text1/partial1::header1"></div>
    <p>テスト</p>
    <div th:replace="text1/partial1::footer1"></div>
  </body>
</html>

MainController.java

package com.example.demo;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/test1")
public class MainController {
	
	@GetMapping
	public String index() {
		return "test1/index";
	}
}

ほう、中々面白い

地道にやってくのが手堅いか。。

### Bootstrapを追加
pom.xml

		<dependency>
			<groupId>org.webjars</groupId>
			<artifactId>bootstrap</artifactId>
			<version>4.5.2</version>
		</dependency>

index.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
  <head>
    <meta charset="utf-8" />
    <link rel="stylesheet" th:href="@{/webjars/bootstrap/4.5.2/css/bootstrap.min.css}">
    <title>Check</title>
  </head>
  <body>
    <span class="badge badge-primary">Primary</span>
<span class="badge badge-secondary">Secondary</span>
<span class="badge badge-success">Success</span>
<span class="badge badge-danger">Danger</span>
<span class="badge badge-warning">Warning</span>
<span class="badge badge-info">Info</span>
<span class="badge badge-light">Light</span>
<span class="badge badge-dark">Dark</span>
  </body>
</html>

pom.xmlの反映は、コンパイルし直さないといけない。

[Spring Boot2.4.2] フォームの値のバリデーション

pom.xml

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

src/main/resources/templates/test1/index.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<title>submit</title>
</head>
<body >
<form method="post" action="#" th:action="@{/test1/testform}" th:object="${test1Form}">
<p><input type="text" id="id" name="id" th:field="*{id}"/></p>
<div th:if="${#fields.hasErrors('id')}" th:errors="*{id}"></div>

<p><input type="text" id="name" name="name" th:field="*{name}"></p>
<div th:if="${#fields.hasErrors('name')}" th:errors="*{name}"></div>
<p><input type="submit" value="送信ボタン"></p>
</form>
</body>
</html>

MainController.java

package com.example.demo;
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.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@Controller
@RequestMapping("/test1")
public class MainController {
	
    @GetMapping
    public String disp1(
    		Model model) {
    	model.addAttribute("test1Form", new Test1Form());
        return "test1/index";
    }
    @PostMapping("/testform")
	public String disp2(@Validated Test1Form test1Form
			,BindingResult br) {
		        if (br.hasErrors()) {
		        	return "test1/index";
		        }
			return "test1/testform";
		}
}

Test1Form.java

package com.example.demo;

import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

public class Test1Form {
	@NotNull(message="必須項目です")
	private Integer id;
	
	@Size(min=3, max=6, message="3文字から6文字で入力して下さい")
	private String name;
	
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
}

src/main/resources/templates/test1/testform.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<title>submit</title>
</head>
<body >

<p>OK</p>

</body>
</html>

やべええええええええええええ
SpringBoot面白いかも。