検索欄が1つのときのあいまい検索を実装してみました。検索するテーブルは1つですけど...それではいってみましょー。
・Spring Data JPA でのクエリー実装方法まとめ - Qiita
⇧ 上記サイト様の説明にありますように、
といろいろな方法がありますが、今回は「CriteriaAPI」ですかね。
Spring Bootでプロジェクトの作成
何はともあれ、プロジェクトを作っていきましょう。
Eclipseを起動し、「ファイル(F)」>「新規(N)」>「Spring スターター・プロジェクト」を選択。

「名前」を入力し、「次へ(N)>」をクリック。

「コア」>「Lombok」、「SQL」>「JPA」、「SQL」>「MySQL」、「テンプレート・エンジン」>「Thymeleaf」、「Web」>「Web」を選択し、「次へ(N)>」をクリック。

「完了(F)」をクリック。

ファイルを作成
こんな感じの構成になるようにフォルダ、ファイルを作成していきます。

まずは、フォルダ作成。「src/main/java」直下のフォルダを選択した状態で右クリックし、「新規(W)」>「フォルダー」を選択。

「フォルダー名(N):」を入力し、「完了(F)」をクリック。

同じ流れで、フォルダを作成し、「controller」「entity」「repository」「service」の4つのフォルダを用意します。
フォルダを作り終わったら、まずは「controller」ふぁおるだを選択し、「新規(W)」>「クラス」を選択します。

「名前(M):」を入力し、「完了(F)」。

続いて、「entity」フォルダーを選択した状態で右クリックし、「新規(W)」>「クラス」を選択します。

「名前(M):」を入力し、「インターフェイス(I):」の「追加(A)...」をクリック。

「一致する項目(M):」から「Serializable - java.io」を選択し、「OK」。

インターフェースが追加されているのを確認し、「完了(F)」。

続いて、「repository」フォルダを選択した状態で右クリックし、「新規(W)」>「インターフェース」をクリック。

「名前(M):」を入力し、「拡張インターフェイス(I):」の「追加(A)....」を選択します。

「一致する項目(M):」から「JpaRepository」「JpaSpecificationExcutor」を選択します。(「Ctrl」キーを押しながらクリックで複数選択できます。)

「インターフェース」が追加されたのを確認し、「完了(F)」。(今回は、Specificationというものを使うので、「JpaSpecificationExcutor」というものも追加しています。)コード上でエラーが出た状態になりますが、後で編集していきます。

続いて、「service」フォルダを選択した状態で右クリックし、「新規(W)」>「クラス」を選択。

「名前(M):」を入力し、「完了(F)」。

今回、Specificationを利用するので、「service」フォルダにもう1つファイルを作成します。

「名前(M):」を入力し、「完了(F)」。

Javaファイルができたので、画面表示側を担うHTMLファイルを作っていきます。場所が変わって、「src/main/resources」>「templates」を選択した状態で右クリックし、「新規(W)」>「その他(O)...」を選択します。

「Web」>「HTMLファイル」を選択し「次へ(N)>」。

「ファイル名(M):」を入力し、「次へ(N)」。

「完了(F)」をクリック。

データベースを用意
ファイルの編集の前に、データベースを用意します。コマンドプロンプトで MySQLに接続(ログイン)します。
mysql -u root -p

データベース一覧
SHOW DATABASES;

今回は既に作成していた、「sample」データベースを使用することにします。
USE sample; SHOW TABLES

「member」というテーブルを作成します。(複数形「members」にしたほうが良かったかな...)
CREATE TABLE member( id int(11) NOT NULL auto_increment, last_name VARCHAR(20) NOT NULL, first_name VARCHAR(20) NOT NULL, last_name_kana VARCHAR(30) NOT NULL, first_name_kana VARCHAR(30) NOT NULL, email VARCHAR(255) NOT NULL, tel VARCHAR(12) NOT NULL, address_level01 VARCHAR(30) NOT NULL, address_level02 VARCHAR(30) NOT NULL, address_line01 VARCHAR(50) NOT NULL, address_line02 VARCHAR(50) NOT NULL, PRIMARY KEY(id) );

データを入れておきます。
INSERT INTO member (last_name, first_name, last_name_kana, first_name_kana, email, tel, address_level01, address_level02, address_line01, address_line02) VALUES('佐藤', '健', 'サトウ', 'タケル', 'takeru@gmail.com', '00087260000', '東京都', '第九地区', 'ドンジャラ市0-22-39', 'ライオンズコーポ102');
INSERT INTO member (last_name, first_name, last_name_kana, first_name_kana, email, tel, address_level01, address_level02, address_line01, address_line02) VALUES('鈴木', 'イチロー', 'スズキ', 'イチロー', 'ichiro@gmail.com', '01041567800', '大阪府', 'ゴメス市', 'セバスティック州2-12-32', '松庵202');
INSERT INTO member (last_name, first_name, last_name_kana, first_name_kana, email, tel, address_level01, address_level02, address_line01, address_line02) VALUES('高田', '善衛', 'タカダ', 'ゼンエイ', 'zennei@gmail.com', '12039860210', '沖縄県', 'ウーマ区', '救世観音市8-21-7', 'シーサーマンション101');

MySQLのユーザー一覧を確認。
SELECT Host, User FROM mysql.user;

ユーザーを追加してみます。
CREATE USER 'member_admin'@'localhost' IDENTIFIED BY 'Password$';
「member_admin」ユーザーが「sample」データベースを利用できるように権限の設定を行います。
GRANT ALL PRIVILEGES ON sample.* TO 'member_admin'@'localhost' IDENTIFIED BY 'Password$';

ユーザーも追加されています。
Eclipse側で、今回のプロジェクトの「src/main/resources」>「application.properties」 ファイルにデータベースの設定を記述していきます。(自分で、YAMLファイルを作っていれば、そちらに記述していっても問題ないと思われます。)
・テックノート – Spring BootでMySQLに接続してJPAを使う方法
⇧ yamlファイルでの接続設定は上記サイト様を参考にしてください
spring.datasource.url=jdbc:mysql://localhost:3306/sample spring.datasource.username=member_admin spring.datasource.password=Password$ spring.datasource.driver-class-name=com.mysql.jdbc.Driver
保存して、データベースの接続設定などが準備できました。
ファイルの編集
それでは、作成していたJavaファイルのほうから編集していきます。
まずは、entityクラスである「Member.java」から。
package com.example.demo.entity;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
@Table(name="member")
public class Member implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name="id", nullable=false)
private Integer id;
@Column(name="last_name", nullable=false)
private String lastName;
@Column(name="first_name", nullable=false)
private String firstName;
@Column(name="last_name_kana", nullable=false)
private String lastNameKana;
@Column(name="first_name_kana", nullable=false)
private String firstNameKana;
@Column(name="email", nullable=false)
private String email;
@Column(name="tel", nullable=false)
private String tel;
@Column(name="address_level01", nullable=false)
private String addressLevel01;
@Column(name="address_level02", nullable=false)
private String addressLevel02;
@Column(name="address_line01", nullable=false)
private String addressLine01;
@Column(name="address_line02", nullable=false)
private String addressLine02;
}
続いて、repositoryインターフェース「MemberRepository.java」を編集。
package com.example.demo.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import com.example.demo.entity.Member;
@Repository
public interface MemberSpecification extends JpaRepository<Member, Integer>, JpaSpecificationExecutor<Member> {
}
続いて、serviceクラス「MemberSpecification.java」を編集。
package com.example.demo.service;
import org.springframework.data.jpa.domain.Specification;
import com.example.demo.entity.Member;
@Service
public class SpecificationService {
/**
* あいまい検索
* @param String searchTerm
* @return Specification<member> Predicate
*/
public static Specification<member> FuzzySearch(String searchTerm) {
// ラムダ式で記述すると、引数のデータ型の指定が省略できる
return (root, query, cb) -> {
String containsLikePattern = getContainsLikePattern(searchTerm);
return cb.or(
cb.like(cb.lower(root.get("lastName")), containsLikePattern),
cb.like(cb.lower(root.get("firstName")), containsLikePattern),
cb.like(cb.lower(root.get("lastNameKana")), containsLikePattern),
cb.like(cb.lower(root.get("firstNameKana")), containsLikePattern),
cb.like(cb.lower(root.get("email")), containsLikePattern),
cb.like(cb.lower(root.get("tel")), containsLikePattern),
cb.like(cb.lower(root.get("addressLevel01")), containsLikePattern),
cb.like(cb.lower(root.get("addressLevel02")), containsLikePattern),
cb.like(cb.lower(root.get("addressLine01")), containsLikePattern),
cb.like(cb.lower(root.get("addressLine02")), containsLikePattern)
);
};
}
/**
* 検索文字列が入力されたとき、されなかったときで調整
* @param String searchTerm
* @return String 調整された文字列
*/
private static String getContainsLikePattern(String searchTerm) {
if(searchTerm == null || searchTerm.isEmpty()) {
return "%";
} else {
return "%" + searchTerm.toLowerCase() + "%";
}
}
}
実際に処理を行う「MemberService.java」を編集
package com.example.demo.service;
import static com.example.demo.service.SpecificationService.*;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.domain.Specifications;
import org.springframework.stereotype.Service;
import com.example.demo.entity.Member;
import com.example.demo.repository.MemberRepository;
@Service
public class MemberService {
@Autowired
MemberRepository repository;
public List<member> findMembers(String target) {
return repository.findAll(Specifications
.where(fuzzySearch(target)));
}
}
「MemberController.java」でデータの受け取りや画面遷移を記述。
package com.example.demo.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
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;
import com.example.demo.entity.Member;
import com.example.demo.service.MemberService;
@Controller
public class MemberController {
@Autowired
MemberService service;
// 初期表示
@RequestMapping(value="/", method=RequestMethod.GET)
public String index() {
return "index";
}
// 検索処理
@RequestMapping(value="/", method=RequestMethod.POST )
public ModelAndView search(ModelAndView mov, @RequestParam(name="search", required=false) String search) {
mov.setViewName("index");
List<member> members = service.findMembers(search);
mov.addObject("members", members);
return mov;
}
}
最後に、index.htmlを編集
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8" />
<title>あいまい検索</title>
</head>
<body>
<form th:action="@{/}" method="POST">
<input type="text" name="search" value="" />
<input type="submit" value="検索" />
</form>
<table border="1" th:if="${members !=null}">
<thead>
<tr>
<th>ID</th><th>名前</th><th>Email</th><th>TEL</th><th>住所</th>
</tr>
</thead>
<tbody>
<tr th:each="member : ${members}">
<td th:text="${member.id}"></td>
<td>
<div>
<span th:text="${member.lastNameKana}"></span>
<span th:text="${member.firstNameKana}"></span>
</div>
<div>
<span th:text="${member.lastName}"></span>
<span th:text="${member.firstName}"></span>
</div>
</td>
<td>
<span th:text="${member.email}"></span>
</td>
<td>
<span th:text="${member.tel}"></span>
</td>
<td>
<span th:text="${member.addressLevel01}"></span>
<span th:text="${member.addressLevel02}"></span>
<span th:text="${member.addressLine01}"></span>
<span th:text="${member.addressLine02}"></span>
</td>
</tr>
</tbody>
</table>
</body>
</html>
サーバーを起動。プロジェクトを選択した状態で右クリックし、「実行(R)」>「Spring Boot アプリケーション」を選択。

ブラウザで表示。「http://localhost:8080」にアクセス。

「沖縄」で検索。

「スズキ」で検索。

「区」で検索。

何も入力しないで検索すると全部取得されます。

ただ、複数キーワード検索はできてません。

検索ムズイっす....。
・Spring Data JPA の Specificationでらくらく動的クエリー - Qiita
・Spring Data JPA Tutorial: Creating Database Queries With the JPA Criteria API