【Javaお勉強日記】springbootを使ってサンプルアプリ-3・springJPAを使ってCRUD出来るアプリを作ったりthymeleaf使ったり
サラッと流したかったんですけど、書いておかないと忘れそうで
thymeleafを使って共通部品を外出しする
依存関係に追加
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
個別ページがわ↓
<!DOCTYPE html>
<html lang='ja' xmlns='http://www.thymeleaf.org'>
<head>
<meta charset='UTF-8'>
<th:block th:insert="base :: header"></th:block>
</head>
<body id="page-top">
<div id = "wrapper">
<th:block th:insert="sidebar :: sidebar "></th:block>
</div>
</body>
共通部品側↓
<!-- base.html -->
<!DOCTYPE html>
<html lang='ja' xmlns='http://www.thymeleaf.org'>
<head>
<meta charset='UTF-8'>
<th:block th:fragment="header">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>社員情報アプリ</title>
<link rel='stylesheet' th:href='@{/webjars/bootstrap/4.3.1/css/bootstrap.min.css}'>
</th:block>
</head>
<!-- 略 -->
1:共通部品にしたい箇所を
<th:block th:fragment="FRAGMENT-NO-NAMAE"></th:block>
で囲む
2:共通部品を入れたい箇所に
<th:block th:insert="PART-PAGE-NO-NAMAE :: FRAGMENT-NO-NAMAE"></th:block>
を入れておく。パーツページ側の名前は、フォルダに入ってる場合フォルダ名/ページ名(.htmlは不要)
これで別ファイルで定義した共通パーツを各ページへ入れられる。
(PHPでincludeするみたいなかんじ)
JPA+H2 Databaseでデータの出し入れを試してみる
H2 Databaseを使えるようにする
build.gradleの依存関係に追加
runtimeOnly 'com.h2database:h2'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
※Lombokとかvalidationとかの依存関係は入っているものとする
application.propertiesに以下を記述
spring.h2.console.enabled=true
spring.datasource.url=jdbc:h2:mem:testdb
spring.jpa.hibernate.ddl-auto=create
spring.jpa.show-sql=true
spring.datasource.username=admin
spring.datasource.password=password
これで起動時にjdbc:h2:mem:testdbという設定のDBが作られる。
spring.h2.console.enabled=trueで、コンソール画面にアクセス出来る。
コンソール画面はhttp://localhost:8080/h2-consoleでアクセスできる。
データベースに突っ込むデータのモデルを作る
// Hoge.java
// import略
@Getter
@Setter
@Entity
public class Hoge {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NotBlank
private String name;
// 色んなnameのデータが1つのtypeに紐付くよ、の意
@ManyToOne
private Type type; // Typeクラスのインスタンスが入る
}
// Type.java
// import略
@Getter
@Setter
@Entity
public class Type {
@Id
@GeneratedValue
private Long id;
@NotBlank
@Size(max = 40)
private String name;
// 一つのtypeに複数のhogeが紐付くよ
@OneToMany(mappedBy = "type")
// Hogeクラスのtypeフィールドに入ってるインスタンスのidで照合する
private List<Hoge> hoges;
}
INSERT文を書く
resourcesフォルダ内に、data.sqlファイルを作成して、
INSERT INTO type(id, name)
VALUES (1,'あれ'),(2,'これ'),(3,'それ'),(4,'どれ');
と書いておく。これでbootrun時に自動的にDBが生成されて、値が入る。
DB周り以外の部分のコードを書く
リポジトリを作る
import com.example.craddemo.model.Hoge;
import org.springframework.data.jpa.repository.JpaRepository;
public interface HogeRepository extends JpaRepository<Hoge, Long> {
}
JpaRepositoryを継承(implementsじゃない)して作ったHogeRepositoryインターフェイスを作っておく。継承するので、中身の処理はもう全部作られてるからoverrideは不要。自身はインターフェイスとして作る事に注意。
同様にTypeRepositoryも用意しておく。
コントローラを作る
// HogeController.java
//import 略
@RequiredArgsConstructor
@Controller
public class HogeController {
private final HogeRepository hogeRepository;
@GetMapping("/list")
public String showList(Model model){
model.addAttribute("hoges", hogeRepository.findAll());
return "index";
}
@GetMapping("/add")
public String addHoge(@ModelAttribute Hoge hoge){
return "form";
}
@PostMapping("/process")
public String process(@Validated @ModelAttribute Hoge hoge, BindingResult result) {
if(result.hasErrors()){
return "form";
}
repository.save(hoge);
return "redirect:/list";
}
@GetMapping("/edit/{id}")
public String editHoge(@PathVariable Long id, Model model){
model.addAttribute("hoge", hogeRepository.findById(id));
return "form";
}
@GetMapping("/delete/{id}")
public String deleteHoge(@PathVariable Long id){
hogeRepository.deleteById(id);
return "redirect:/list";
}
}
データ追加・編集用のフォームを表示するときには
(@ModelAttribute Hoge hoge)
を引数にとって、フォーム側(HTML)で正しくidを設定すれば、フォームで送った内容が自動的にhogeの中に入る。
編集用フォームを表示する時は
@GetMapping("/edit/{id}")
アノテーションを付けて、フォーム側の遷移先として{id}を付けた/edit/idを設定する。で、idを取得したら
model.addAttribute("hoges", hogeRepository.findById(id));
してやれば、hogeRepositoryを経由してidをキーにして取得してきたデータを、hogesフィールドの中身としてmodelに追加して画面へ渡せる。
で、編集を実行する時は
(@Validated @ModelAttribute Hoge hoge, BindingResult result)
を引数にとって、
hogeRepository.save(hoge)
するだけで自動的にレコードがなければ新規作成、あれば上書きされる。削除も同様にhogeRepository.deleteById(id);すれば消える。DB内でどうこうする処理は書かなくて良い。簡単!
HTMLを用意する
<!-- index.html -->
<!DOCTYPE html>
<html lang='ja' xmlns='http://www.thymeleaf.org'>
<head>
<meta charset='UTF-8'>
<th:block th:insert="base :: header"></th:block>
</head>
<body id="page-top">
<div id = "wrapper">
<th:block th:insert="sidebar :: sidebar "></th:block>
<div>
<!-- hogesフィールドの要素数が0ならここを表示 -->
<div th:if="${hoges.size() == 0}">
該当データがありません
</div>
<!-- hogesフィールドの要素数が1以上ならここを表示 -->
<table class="table table-borderd" th:if="${employees.size() > 0}">
<thead>
<tr>
<th>#</th>
<th>NAME</th>
<th>TYPE</th>
<th></th>
</tr>
</thead>
<tbody>
<tr th:each="hoge : ${hoges}" th:object = "${hoge}">
<td th:text = "*{id}"></td>
<td th:text = "*{name}"></td>
<td th:text = "*{type.name}"></td>
<!-- ↑typeにはtype型オブジェクトが入っているので.nameで名称を取得する -->
<td>
<a th:href="@{/edit/{id}(id=*{id})}" class="btn">
<span class="text">編集</span>
</a>
<a th:href="@{/delete/{id}(id=*{id})}" class="btn">
<span class="text">削除</span>
</a>
</td>
</tr>
</tbody>
</table>
</div>
<th:block th:insert="base :: scripts"></th:block>
</body>
</html>
<!-- form.html -->
<!DOCTYPE html>
<html lang='ja' xmlns='http://www.thymeleaf.org'>
<head>
<meta charset='UTF-8'>
<th:block th:insert="base :: header"></th:block>
</head>
<body>
<div>
<form th:action="@{/process}" th:object="${hoge}" method="POST">
<input type="hidden" th:field="*{id}">
<div class="form-group">
<label for="name">NAME</label>
<input type="text" th:errorclass="is-invalid" th:field="*{name}">
<div th:errors="*{name}"></div>
</div>
<div>
<label for="type">TYPE</label>
<select class="form-control" th:field="*{type}">
<!-- typeテーブルのデータを持ってきて選択肢として表示する -->
<th:block th:each="type : ${@typeRepository.findAll()}">
<option th:value="${type.id}" th:text="${type.name}"></option>
</th:block>
</select>
</div>
<button class="btn"><span class="text">保存</span></button>
</form>
</div>
</body>
</html>
これで一通り、Create、Read、Update、Deleteが出来るようになる。
こうやって見ると長々しいけど、実際やってみるとバリデーションとかマッピングとかややこしいことは全部アノテーション任せで、ちょちょいのちょいで作れる感じ。
この記事が気に入ったらサポートをしてみませんか?