# Conflicts:
#	book-rent/src/main/resources/static/css/style.css
This commit is contained in:
2026-10-27 14:47:24 +09:00
10 changed files with 340 additions and 241 deletions

View File

@@ -43,7 +43,8 @@ public class AdminBookController {
@PostMapping(NEW + "/confirm")
public String newConfirm(@ModelAttribute("form") BookForm form, Model model) {
List<String> errors = bookAdminService.validate(form);
if (!errors.isEmpty()) return input(form, errors, "書籍登録", NEW, model);
if (!errors.isEmpty())
return input(form, errors, "書籍登録", NEW, model);
return confirm("書籍登録", NEW, model);
}
@@ -87,7 +88,8 @@ public class AdminBookController {
@PostMapping(EDIT + "/confirm")
public String editConfirm(@ModelAttribute("form") BookForm form, Model model) {
List<String> errors = bookAdminService.validate(form);
if (!errors.isEmpty()) return input(form, errors, "書籍編集", EDIT, model);
if (!errors.isEmpty())
return input(form, errors, "書籍編集", EDIT, model);
return confirm("書籍編集", EDIT, model);
}

View File

@@ -1,18 +1,17 @@
package com.example.demo.controller;
import java.util.List;
import java.util.stream.IntStream;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import com.example.demo.entity.BookCollection;
import com.example.demo.service.BookService;
/** BOOK-01:書籍検索(bookList.html) */
@Controller
public class BookController {
@@ -27,8 +26,16 @@ public class BookController {
public String list(@RequestParam(defaultValue = "") String nmBook,
@RequestParam(defaultValue = "") String publisher,
@RequestParam(defaultValue = "") String note,
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size,
Model model) {
model.addAttribute("books", bookService.searchLendable(nmBook, publisher, note));
Page<BookCollection> bookPage = bookService.searchLendable(nmBook, publisher, note, page, size);
List<Integer> pageNumbers = IntStream.range(0, bookPage.getTotalPages()).boxed().toList();
model.addAttribute("books", bookPage);
model.addAttribute("bookPage", bookPage);
model.addAttribute("pageNumbers", pageNumbers);
// 検索条件を保持
model.addAttribute("nmBook", nmBook);
model.addAttribute("publisher", publisher);

View File

@@ -46,7 +46,8 @@ public class EmployeeController {
}
@PostMapping(NEW + "/confirm")
public String registConfirm(@ModelAttribute("form") EmployeeForm form, Model model) {
public String registConfirm(@ModelAttribute("form") EmployeeForm form,
Model model) {
List<String> errors = employeeService.validateRegist(form);
if (!errors.isEmpty())
return registView(form, errors, model);

View File

@@ -1,5 +1,7 @@
package com.example.demo.form;
/** 社員登録・編集フォーム */
public class EmployeeForm {
private Integer idEmployee;

View File

@@ -1,8 +1,9 @@
package com.example.demo.repository;
import java.time.LocalDateTime;
import java.util.List;
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.Modifying;
import org.springframework.data.jpa.repository.Query;
@@ -22,10 +23,12 @@ public interface BookCollectionRepository extends JpaRepository<BookCollection,
+ "and (:publisher = '' or b.publisher like concat('%', :publisher, '%') escape '!') "
+ "and (:note = '' or b.note like concat('%', :note, '%') escape '!') "
+ "order by b.idBook")
List<BookCollection> search(@Param("lending") String lending,
Page<BookCollection> search(
@Param("lending") String lending,
@Param("nm") String nm,
@Param("publisher") String publisher,
@Param("note") String note);
@Param("note") String note,
Pageable pageable);
/**
* 貸出フラグを from → to に更新する(現在値が from のときだけ更新)。

View File

@@ -1,7 +1,7 @@
package com.example.demo.service;
import java.util.List;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -20,14 +20,16 @@ public class BookService {
/** 貸出可の蔵書を検索する。全て未入力なら全件。 */
@Transactional(readOnly = true)
public List<BookCollection> searchLendable(String nmBook, String publisher, String note) {
return bookRepository.search(Const.LENDING_OK, normalize(nmBook), normalize(publisher), normalize(note));
public Page<BookCollection> searchLendable(String nmBook, String publisher, String note, int page, int size) {
return bookRepository.search(Const.LENDING_OK, normalize(nmBook), normalize(publisher), normalize(note),
PageRequest.of(page, size));
}
/** 前後の空白除去+LIKE特殊文字(! % _)のエスケープ(エスケープ文字は '!') */
static String normalize(String s) {
if (s == null) return "";
if (s == null)
return "";
return s.trim().replace("!", "!!").replace("%", "!%").replace("_", "!_");
}
}
}

View File

@@ -1,90 +1,153 @@
body
{font-family:
body {
font-family:
"Meiryo", "Hiragino Sans", sans-serif;
margin:0;color:#222;
background:#f6f7f9}
header.top
{display:flex;
margin: 0;
color: #222;
background: #f6f7f9
}
header.top {
display: flex;
justify-content: space-between;
align-items: center;
background:#176a78;color:#fff;
background: #176a78;
color: #fff;
padding: 10px 20px
}
header.top form
{display:inline;
margin:0}
header.top .user
{margin-right:12px
header.top form {
display: inline;
margin: 0
}
main
{max-width:960px;
header.top .user {
margin-right: 12px
}
main {
max-width: 960px;
margin: 24px auto;
padding: 0 16px
}
h1
{font-size:20px
h1 {
font-size: 20px
}
.card
{background:#fff;
.card {
background: #fff;
border: 1px solid #dde;
border-radius: 6px;
padding: 20px;
margin-bottom: 16px
}
label
{display:block;
label {
display: block;
margin: 10px 0 4px;
font-weight: bold
}
input[type=text],input[type=password],input[type=email]
{width:100%;
input[type=text],
input[type=password],
input[type=email] {
width: 100%;
max-width: 360px;
padding: 6px;
box-sizing: border-box
}
button,.btn
{display:inline-block;
button,
.btn {
display: inline-block;
background: #176a78;
color:#fff;border:0;
color: #fff;
border: 0;
border-radius: 4px;
padding: 7px 16px;
cursor: pointer;
text-decoration: none;
font-size: 14px
}
button.sub,.btn.sub
{background:#6b7b80
button.sub,
.btn.sub {
background: #6b7b80
}
.error
{background:#fdecea;color:#b3261e;
.error {
background: #fdecea;
color: #b3261e;
border: 1px solid #f5c2be;
padding: 8px 12px;
border-radius: 4px;
margin-bottom: 12px
}
.info
{background:#e8f4ea;
.info {
background: #e8f4ea;
color: #1b5e20;
border: 1px solid #bfdcc3;
padding: 8px 12px;
border-radius: 4px;
margin-bottom: 12px
}
table
{border-collapse:collapse;
table {
border-collapse: collapse;
width: 100%;
background: #fff
}
th,td
{border:1px solid #dde;
th,
td {
border: 1px solid #dde;
padding: 6px 8px;
text-align: left;
font-size: 14px
}
th
{background:#eaf4f6
th {
background: #eaf4f6
}
.menu a
{display:block;
.menu a {
display: block;
margin: 8px 0
}
/* Responsive (ဖုန်းစခရင်သေးများတွင် အောက်သို့ ဆင်းသွားစေရန်) */
@media (max-width: 600px) {
.login-container-flex {
flex-direction: column;
align-items: center;
text-align: center;
}
.form-content-area {
width: 100%;
}
input[type=text],
input[type=password],
input[type=email] {
max-width: 100% !important;
}
}
/* ページネーション */
.page-number {
display: inline-block;
background: #eaf4f6;
color: #176a78;
border: 1px solid #d4e3e6;
border-radius: 4px;
padding: 7px 12px;
margin: 2px;
text-decoration: none;
font-size: 14px;
}
.page-number:hover {
background: #d5edf1;
}

View File

@@ -1,10 +1,12 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>書籍情報入力</title>
<link rel="stylesheet" th:href="@{/css/style.css}">
</head>
<body>
<div th:replace="~{fragments/header :: header}"></div>
<main>
@@ -21,14 +23,17 @@
<input type="text" id="nmBook" name="nmBook" th:value="${form.nmBook}" maxlength="50">
<label for="knBook">書籍名よみ(100文字以内)</label>
<input type="text" id="knBook" name="knBook" th:value="${form.knBook}" maxlength="100">
<!-- <span th:errors="${form.knBook}"></span>-->
<label for="publisher">出版社(50文字以内)</label>
<input type="text" id="publisher" name="publisher" th:value="${form.publisher}" maxlength="50">
<label for="note">特記事項</label>
<input type="text" id="note" name="note" th:value="${form.note}">
<p><button type="submit" th:text="${title} + '確認'">確認</button>
<a class="btn sub" th:href="@{/books}">書籍一覧に戻る</a></p>
<a class="btn sub" th:href="@{/books}">書籍一覧に戻る</a>
</p>
</form>
</div>
</main>
</body>
</html>

View File

@@ -29,8 +29,8 @@
<div class="card">
<h2>検索結果</h2>
<p th:if="${#lists.isEmpty(books)}">該当する書籍はありません。</p>
<table th:unless="${#lists.isEmpty(books)}">
<p th:if="${bookPage.isEmpty()}">該当する書籍はありません。</p>
<table th:unless="${bookPage.isEmpty()}">
<thead>
<tr>
<th>蔵書ID</th>
@@ -60,8 +60,21 @@
</tr>
</tbody>
</table>
<a class="page-number"
th:if="${bookPage.hasPrevious()}"
th:href="@{/books(page=${bookPage.number-1}, nmBook=${nmBook}, publisher=${publisher}, note=${note})}">前へ</a>
<span th:each="pageNum : ${pageNumbers}">
<a class="page-number"
th:href="@{/books(page=${pageNum}, nmBook=${nmBook}, publisher=${publisher}, note=${note})}"
th:text="${pageNum + 1}"></a>
</span>
<a class="page-number"
th:if="${bookPage.hasNext()}"
th:href="@{/books(page=${bookPage.number+1}, nmBook=${nmBook}, publisher=${publisher}, note=${note})}">次へ</a>
</div>
</main>
</body>
</html>

View File

@@ -37,6 +37,7 @@
<div>
<label for="knEmployee">社員名よみ</label>
<input type="text" id="knEmployee" th:field="*{knEmployee}">
<span th:errors="*{knEmployee}"></span>
</div>
<!-- メールアドレス -->