標題の通り、検索アプリを作成しました。
##使用環境
・Windows10 (64bit)
・spring-boot:2.2.6
・Eclipse:4.9.0
・H2
#完成画面
ジャンル、著者、タイトルのいずれかまたは、すべて入力した際に
画面の下部にある内容を引っ張ってきます。
#Entity
BookData.java
import javax.persistence.Entity;
import javax.persistence.Id;
@Entity
public class BookData {
@Id
private long isbn;
private String genre;
private String author;
private String title;
private int stock;
private Boolean status;
public long getIsbn() {
return isbn;
}
public void setIsbn(long isbn) {
this.isbn = isbn;
}
public String getGenre() {
return genre;
}
public void setGenre(String genre) {
this.genre = genre;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public int getStock() {
return stock;
}
public void setStock(int stock) {
this.stock = stock;
}
public Boolean getStatus() {
return status;
}
public void setStatus(Boolean status) {
this.status = status;
}
}
#Dao
ジャンル、著者、タイトルで検索するためDaoクラスを用意します。
BookDataDao.java
import java.io.Serializable;
import java.util.List;
public interface BookDataDao extends Serializable {
public List<BookData> search(String genre, String author, String title);
}
#Repository
Daoクラスを実装したBookDataDaoImplを作成します。
各記述の内容はコメントを参照ください。
BookDataDaoImpl.java
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
@Repository
public class BookDataDaoImpl implements BookDataDao {
//Entityを利用するために必要な機能を提供する
@Autowired
private EntityManager entityManager;
public BookDataDaoImpl() {
super();
}
public BookDataDaoImpl(EntityManager manager) {
this();
entityManager = manager;
}
//Daoクラスで用意したsearchメソッドをオーバーライドする
@SuppressWarnings("unchecked")
@Override
public List<BookData> search(String genre, String author, String title) {
//StringBuilderでSQL文を連結する
StringBuilder sql = new StringBuilder();
sql.append("SELECT b From BookData b WHERE ");
boolean genreFlg = false;
boolean authorFlg = false;
boolean titleFlg = false;
boolean andFlg = false;
//genreがブランクではなかった場合、sql変数にappendする
//フラグをtrueにしとく
if(!"".equals(genre)) {
sql.append("b.genre LIKE :genre");
genreFlg = true;
andFlg = true;
}
//authorがブランクではなかった場合、sql変数にappendする
//フラグをtrueにしとく
if(!"".equals(author)) {
if (andFlg) sql.append(" AND ");
sql.append("b.author LIKE :author");
authorFlg = true;
andFlg = true;
}
//titleがブランクではなかった場合、sql変数にappendする
//フラグをtrueにしとく
if(!"".equals(title)) {
if (andFlg) sql.append(" AND ");
sql.append("b.title LIKE :title");
titleFlg = true;
andFlg = true;
}
/*
QueryはSQLでデータを問い合わせるためのクエリ文に相当する機能を持つ
entityManagerのcreateQueryメソッドを使用する
sql変数を引数に渡す
*/
Query query = entityManager.createQuery(sql.toString());
//上記のif文でtrueになった場合は、各変数に値をセットする
//今回、あいまい検索したいのでlike句を使用する
if (genreFlg) query.setParameter("genre", "%" + genre + "%");
if (authorFlg) query.setParameter("author", "%" + author + "%");
if (titleFlg) query.setParameter("title", "%" + title + "%");
return query.getResultList();
}
}
#BookDataRepository
BookDataRepository.java
import org.springframework.data.jpa.repository.JpaRepository;
public interface BookDataRepository extends JpaRepository<BookData, Long> {
}
#Service
BookService.java
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class BookService {
@Autowired
private BookDataRepository bookDataRepository;
@Autowired
private BookDataDaoImpl bookDataDaoImpl;
//全件検索
public List<BookData> findAll(){
return bookDataRepository.findAll();
}
//該当のID見つける
public Optional<BookData> findById(long isbn) {
return bookDataRepository.findById(isbn);
}
//保存
public BookData save(BookData bookData) {
return bookDataRepository.saveAndFlush(bookData);
}
//検索
public List<BookData> search(String genre, String author, String title){
List<BookData> result = new ArrayList<BookData>();
//すべてブランクだった場合は全件検索する
if ("".equals(genre) && "".equals(author) && "".equals(title)){
result = bookDataRepository.findAll();
}
else {
//上記以外の場合、BookDataDaoImplのメソッドを呼び出す
result = bookDataDaoImpl.search(genre, author, title);
}
return result;
}
}
#Controller
StockController.java
import java.util.List;
import java.util.Optional;
import javax.annotation.PostConstruct;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/book")
public class StockController {
@Autowired
private BookService bookService;
@PersistenceContext
EntityManager entityManager;
//一覧表示処理
@GetMapping
public String index(Model model,@ModelAttribute("formModel") BookData bookdata) {
model.addAttribute("msg", "在庫管理");
model.addAttribute("msg2", "検索条件を入力してください");
List<BookData> books = bookService.findAll();
model.addAttribute("books", books);
return "index";
}
//検索結果の受け取り処理
//@ModelAttributeでformからformModelを受け取り、
//その型(BookData)と変数(bookdata)を指定する
@PostMapping
public String select(@ModelAttribute("formModel") BookData bookdata, Model model) {
model.addAttribute("msg", "検索結果");
//bookdataのゲッターで各値を取得する
List<BookData> result = bookService.search(bookdata.getGenre(),bookdata.getAuthor(), bookdata.getTitle());
model.addAttribute("books", result);
return "index";
}
//詳細画面処理
//@PathVariableでURLから受け取った値を取得する
@GetMapping("detail/{isbn}")
public String detail(@PathVariable long isbn, Model model) {
model.addAttribute("msg", "参照画面");
Optional<BookData> data = bookService.findById(isbn);
//Optionalを使用する際、値はget()で取得する
model.addAttribute("form", data.get());
return "detail";
}
//初期化処理
@PostConstruct
public void init() {
BookData d1 = new BookData();
d1.setAuthor("夏目漱石");
d1.setTitle("こころ");
d1.setGenre("文学");
d1.setIsbn(11111);
d1.setStock(100);
d1.setStatus(false);
bookService.save(d1);
BookData d2 = new BookData();
d2.setAuthor("大野次郎");
d2.setTitle("Spring入門");
d2.setGenre("技術");
d2.setIsbn(22222);
d2.setStock(1);
d2.setStatus(false);
bookService.save(d2);
BookData d3 = new BookData();
d3.setAuthor("田中太郎");
d3.setTitle("ネットワークのしくみ");
d3.setGenre("技術");
d3.setIsbn(33333);
d3.setStock(20);
d3.setStatus(false);
bookService.save(d3);
BookData d4 = new BookData();
d4.setAuthor("吉川量");
d4.setTitle("泥の銃弾");
d4.setGenre("ミステリー");
d4.setIsbn(44444);
d4.setStock(99);
d4.setStatus(false);
bookService.save(d4);
BookData d5 = new BookData();
d5.setAuthor("夏目漱石");
d5.setTitle("草枕");
d5.setGenre("文学");
d5.setIsbn(55555);
d5.setStock(40);
d5.setStatus(false);
bookService.save(d5);
BookData d6 = new BookData();
d6.setAuthor("テスト敏郎");
d6.setTitle("連続殺人事件簿");
d6.setGenre("ミステリー");
d6.setIsbn(66666);
d6.setStock(40);
d6.setStatus(false);
bookService.save(d6);
BookData d7 = new BookData();
d7.setAuthor("蛇場太郎");
d7.setTitle("Java入門");
d7.setGenre("技術");
d7.setIsbn(77777);
d7.setStock(40);
d7.setStatus(false);
bookService.save(d7);
}
}
#index.html
index.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>初期画面</title>
<style>
h1 {font-size:18pt; font-weight:bold; color:gray;}
body {font-size:13pt; font-weight:bold; color:gray; margin:5px 25px;}
tr {margin:5px;}
th {padding:5px;color:white; background:darkgray;}
td {padding:5px;color:black; background:#f0f0f0;}
</style>
</head>
<body>
<h1 th:text="${msg}"></h1>
<p th:text="${msg2}"></p>
<!--入力した値をth:object="${formModel}"に詰める -->
<!--th:valueで初期値が入るようにする -->
<form method="post" th:action="@{/book}" th:object="${formModel}">
<label>ジャンル:</label>
<input type="text" name="genre" th:value="*{genre}"><p>
<label>著者 :</label>
<input type="text" name="author" th:value="*{author}"><p>
<label>タイトル:</label>
<input type="text" name="title" th:value="*{title}"><p>
<input type="submit" value="検索">
</form>
<table>
<tr>
<th>ISBN</th>
<th>タイトル</th>
<th>著者名</th>
<th>在庫数</th>
<th>ジャンル</th>
</tr>
<tr th:each="obj:${books}" th:object="${obj}">
<!--th:hrefでリンク設定 -->
<td><a th:href="@{/book/detail/{isbn}(isbn=*{isbn})}" th:text="*{isbn}"></a></td>
<td th:text="*{title}"></td>
<td th:text="*{author}"></td>
<td th:text="*{stock}"></td>
<td th:text="*{genre}"></td>
</tr>
</table>
</body>
</html>
#処理パターン1
ジャンルに「文学」と入力して、検索ボタン押下。
検索結果画面に遷移すると、前のページで入力した値を保持して、画面に表示。
検索結果のISBNリンクをクリックすると、参照画面に遷移。
#最後に
簡易的なアプリを作成してみました。
「もっとこうした方が良い!」などのご意見があればご教示頂ければ幸いです。