目的
コントローラからViewの表示を行うだけの状態から、
コントローラからサービスを呼び出し、
DB操作を行い、
結果をViewに返すまでの流れを実現するサンプルを作成する
環境
IDE STS
Spring Boot 1.3.0
Java 8
テンプレートエンジン Thymeleaf
Spring Data JPA
O/Rマッパー Hibernate
手順
前回の状態
・コントローラ
customersへマッピングされたlistメソッドを用意
customersへリクエストを受けると、
addAttributeメソッドにて"msg"に”サンプルメッセージ!”という文字列がひも付けられ、Viewに渡される。
viewは、resources/templates以下の、
test/test.htmlが呼び出される
package com.example.web;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
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 com.example.domain.Customer;
import com.example.service.CustomerService;
@Controller
@RequestMapping("customers")
public class CustomerController {
@RequestMapping(method = RequestMethod.GET)
public String list(Model model) {
model.addAttribute("msg","サンプルメッセージ!");
return "test/test";
}
}
・テンプレート
html xmlns:th="http://www.thymeleaf.org"をヘッダにて呼び出し
th属性を使うための名前空間を指定する
th:text="${msg}"で、パラメータを取り出し、text型でセットする 文字列として表示される
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>top page</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
test
<p th:text="${msg}" />
</body>
</html>
・pom
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>webAppTest_version1.3</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
</properties>
<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>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
今回の作業
pomに以下の依存性を追加
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
<dependency>
<groupId>org.lazyluke</groupId>
<artifactId>log4jdbc-remix</artifactId>
<version>0.2.7</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.14.0</version>
<scope>provided</scope>
</dependency>
サービスの追加
JPAクラスによるCLUD操作をcustomerRepository.findAll()等で実行している
このCLUD操作に関するメソッドは、customerRepositoryに実装されているのではなく、その継承元で定義されている。
package com.example.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.example.domain.Customer;
import com.example.repository.CustomerRepository;
@Service
@Transactional
public class CustomerService {
@Autowired
CustomerRepository customerRepository;
public Customer save(Customer customer){
return customerRepository.save(customer);
}
public List<Customer> findAll(){
return customerRepository.findAll();
}
public Page<Customer> findAll(Pageable pageable){
return customerRepository.findAllOrderByName(pageable);
}
public Customer findOne(Integer id){
return customerRepository.findOne(id);
}
public Customer create(Customer custmer){
return customerRepository.save(custmer);
}
public Customer update(Customer customer){
return customerRepository.save(customer);
}
public void delete(Integer id){
customerRepository.delete(id);
}
}
DB操作
エンティティ
@EntityアノテーションでJPAエンティティであることを定義
@TableアノテーションでTable名とのひも付け
@Dataアノテーションにて、各フィールドのアクセッサ、toString equals hashCodeメソッドを生成する。(Lombok)
@NoArgsConstructor @AllArngConstructor コンストラクタを生成
@Id主キーを指定
@GeneratedValue 主キーをDBで自動採番する
package com.example.domain;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Entity
@Table(name = "customers")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Customer {
@Id
@GeneratedValue
private Integer id;
@Column(nullable = false)
private String firstName;
@Column(nullable = false)
private String lastName;
}
repository
RDBMS操作を行う
JpaRepositoryクラスを継承したInterfaceを作成する
CLUDの基本的な操作はすでに定義されているため、Interfaceを定義するだけで
findOne
findAll
save
delete
メソッドが使える
@Queryアノテーションにより、JPQLによる処理も可能
package com.example.repository;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import com.example.domain.Customer;
@Repository
@Transactional
public interface CustomerRepository extends JpaRepository<Customer, Integer>{
@Query("SELECT x FROM Customer x ORDER BY x.firstName, x.lastName")
Page<Customer> findAllOrderByName(Pageable pageable);
}
初期データの取り込み
resourceにsqlファイルを配置すると、実行前に実行してくれる。
DBの
INSERT INTO customers(first_name, last_name) VALUES('中野', '西口');
INSERT INTO customers(first_name, last_name) VALUES('中野', '坂上');
INSERT INTO customers(first_name, last_name) VALUES('東', '中野');
INSERT INTO customers(first_name, last_name) VALUES('中野', '富士見町');
※そもそもDBの設定はどうなっているのか
h2を利用しているため、デフォルトの設定でインメモリで動いている。mysqlとかを利用する場合は設定ファイルが別途必要
Table定義は@Dataのエンティティから自動的に生成されている(
JPAによって)・・・のはず
上記のサービスをControllerから呼び出す
Controllerからサービスを呼び出し、結果をViewへ渡す
customerServiceのfindAll()メソッドから、検索を行う
addAttributeで"customers"というキーにcustomersオブジェクトをひもづける
テンプレートcustomers/listを表示する
package com.example.web;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
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 com.example.domain.Customer;
import com.example.service.CustomerService;
@Controller
@RequestMapping("customers")
public class CustomerController {
@Autowired
CustomerService customerService;
@RequestMapping(method = RequestMethod.GET)
String list(Model model) {
List<Customer> customers = customerService.findAll();
model.addAttribute("customers", customers);
return "customers/list";
}
/*
@RequestMapping(method = RequestMethod.GET)
public String list(Model model) {
model.addAttribute("msg","サンプルメッセージ!");
return "customers/list";
}
*/
}
Viewの表示
addAttrivuteで渡されたパラメータじゃ${customer}で取り出せる
もともとcustomerはList型で渡されていたため、
th:each にて繰り返し取得できる
customer:${customers}
にて、右のりすとからひとつづつcustomerオブジェクトを読み出し、列記できる
※Formの方は一旦表示だけまで
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>top page</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<table>
<tr th:each="customer : ${customers}">
<td th:text="${customer.id}"></td>
<td th:text="${customer.lastName}"></td>
<td th:text="${customer.firstName}"></td>
<td>
<from method="get">
<input type="submit" name="from" value="編集" />
<input type="hidden" name="id" th:value="${customer.id}" />
</from>
</td>
<td>
<from method="post">
<input type="submit" value="削除" />
<input type="hidden" value="id" th:value="${customer.id}" />
</from>
</td>
</tr>
</table>
</body>
</html>
表示を確認
http://localhost:8080/test
よりブラウザで表示
データが表示されました
参考文献
・[工学社はじめてのSpring Boot 第1版:槙俊明(平成27年1月10日)]
本書のSpring Bootは、バージョンが1.1.8.RELEASEを前提としていたため、
最新(僕の場合は1.3.0.RELEASE)のプロジェクトでそのままサンプルを実行すると正常に動かなかった。
一旦、別の情報をもとに1.3.0でThymeleafによるView表示を実現するところまでやった上で、サービスを1個づつ追記し、とりあえずこのようにしたら問題なく動いた。
(ただ、DBのログが出せていない。)
・Spring BootではじめるSpring MVCアプリケーション高速開発入門:http://libro.tuyano.com/index3?id=8486003&page=2