LoginSignup
4
7

More than 3 years have passed since last update.

Spring Bootで簡易検索アプリ作成

Last updated at Posted at 2020-05-28

標題の通り、検索アプリを作成しました。

使用環境

・Windows10 (64bit)
・spring-boot:2.2.6
・Eclipse:4.9.0
・H2

完成画面

ジャンル、著者、タイトルのいずれかまたは、すべて入力した際に
画面の下部にある内容を引っ張ってきます。
image.png

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リンクをクリックすると、参照画面に遷移。
image.png

image.png

image.png

処理パターン2

著者に「太」を入力して、検索ボタン押下。
image.png

image.png

最後に

簡易的なアプリを作成してみました。
「もっとこうした方が良い!」などのご意見があればご教示頂ければ幸いです。

参考

Spring Boot 2 プログラミング入門

Spring徹底入門

4
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
7