From 47947636a1cba2e5776a57a00dcc6607e8d9752e Mon Sep 17 00:00:00 2001 From: o-matsuda <26-o-matsuda-stellatecnica@it-college.co.jp> Date: Mon, 26 Oct 2026 15:14:09 +0900 Subject: [PATCH 1/2] =?UTF-8?q?=E6=9B=B8=E7=B1=8D=E5=90=8D=E3=82=88?= =?UTF-8?q?=E3=81=BF=E3=81=A8=E7=A4=BE=E5=93=A1=E5=90=8D=E3=82=88=E3=81=BF?= =?UTF-8?q?=E3=81=AE=E3=83=90=E3=83=AA=E3=83=86=E3=83=BC=E3=82=B7=E3=83=A7?= =?UTF-8?q?=E3=83=B3=E5=AE=8C=E4=BA=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../demo/service/BookAdminService.java | 4 +- .../example/demo/service/EmployeeService.java | 268 ++++++++++-------- 2 files changed, 148 insertions(+), 124 deletions(-) diff --git a/book-rent/src/main/java/com/example/demo/service/BookAdminService.java b/book-rent/src/main/java/com/example/demo/service/BookAdminService.java index 17f56d1..126fc2b 100644 --- a/book-rent/src/main/java/com/example/demo/service/BookAdminService.java +++ b/book-rent/src/main/java/com/example/demo/service/BookAdminService.java @@ -32,8 +32,10 @@ public class BookAdminService { else if (f.getIsbn().length() > 13) e.add("ISBNは13文字以内で入力してください。"); if (f.getNmBook().isEmpty()) e.add("書籍名を入力してください。"); else if (f.getNmBook().length() > 50) e.add("書籍名は50文字以内で入力してください。"); - if (f.getKnBook().length() > 100) e.add("書籍名よみは100文字以内で入力してください。"); + if(!f.getKnBook().matches("^[\\u3040-\\u309F]+$")) e.add("書籍名よみはひらがなで入力してください"); + else if (f.getKnBook().length() > 100) e.add("書籍名よみは100文字以内で入力してください。"); if (f.getPublisher().length() > 50) e.add("出版社は50文字以内で入力してください。"); + return e; } diff --git a/book-rent/src/main/java/com/example/demo/service/EmployeeService.java b/book-rent/src/main/java/com/example/demo/service/EmployeeService.java index 0587add..80dfaa4 100644 --- a/book-rent/src/main/java/com/example/demo/service/EmployeeService.java +++ b/book-rent/src/main/java/com/example/demo/service/EmployeeService.java @@ -20,145 +20,167 @@ import com.example.demo.repository.EmployeeRepository; /** EMP-01:社員登録、EMP-02:社員編集 */ @Service public class EmployeeService { - private static final Pattern MAIL = Pattern.compile("^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$"); - private static final String MSG_DUP = "このメールアドレスは既に登録されています。"; + private static final Pattern MAIL = Pattern.compile("^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$"); + private static final String MSG_DUP = "このメールアドレスは既に登録されています。"; - private final EmployeeRepository employeeRepository; + private final EmployeeRepository employeeRepository; - public EmployeeService(EmployeeRepository employeeRepository) { - this.employeeRepository = employeeRepository; - } + public EmployeeService(EmployeeRepository employeeRepository) { + this.employeeRepository = employeeRepository; + } - // ---------- 検索 ---------- + // ---------- 検索 ---------- - @Transactional(readOnly = true) - public Optional findByMail(String mail) { - return employeeRepository.findByMailAddress(mail == null ? "" : mail.trim()); - } + @Transactional(readOnly = true) + public Optional findByMail(String mail) { + return employeeRepository.findByMailAddress(mail == null ? "" : mail.trim()); + } - @Transactional(readOnly = true) - public Employee find(Integer id) { - return employeeRepository.findById(id) - .orElseThrow(() -> new BusinessException("対象の社員が見つかりません。")); - } + @Transactional(readOnly = true) + public Employee find(Integer id) { + return employeeRepository.findById(id) + .orElseThrow(() -> new BusinessException("対象の社員が見つかりません。")); + } - /** 編集画面の初期値(パスワードは空:管理者は変更時のみ入力) */ - public EmployeeForm toForm(Employee e) { - EmployeeForm f = new EmployeeForm(); - f.setIdEmployee(e.getIdEmployee()); - f.setNmEmployee(e.getNmEmployee()); - f.setKnEmployee(e.getKnEmployee()); - f.setMailAddress(e.getMailAddress()); - f.setFlgAdmin(e.getFlgAdmin()); - f.setFlgRetirement(e.getFlgRetirement()); - return f; - } + /** 編集画面の初期値(パスワードは空:管理者は変更時のみ入力) */ + public EmployeeForm toForm(Employee e) { + EmployeeForm f = new EmployeeForm(); + f.setIdEmployee(e.getIdEmployee()); + f.setNmEmployee(e.getNmEmployee()); + f.setKnEmployee(e.getKnEmployee()); + f.setMailAddress(e.getMailAddress()); + f.setFlgAdmin(e.getFlgAdmin()); + f.setFlgRetirement(e.getFlgRetirement()); + return f; + } - // ---------- 入力チェック ---------- + // ---------- 入力チェック ---------- - /** 社員登録:社員名・よみ・メール・管理者フラグ。パスワードは初期値で登録する。 */ - public List validateRegist(EmployeeForm f) { - f.trim(); - List e = new ArrayList<>(); - checkBasic(f, e); - checkMail(f, null, e); - checkFlag(f.getFlgAdmin(), "管理者フラグ", e); - return e; - } + /** 社員登録:社員名・よみ・メール・管理者フラグ。パスワードは初期値で登録する。 */ + public List validateRegist(EmployeeForm f) { + f.trim(); + List e = new ArrayList<>(); + checkBasic(f, e); + checkMail(f, null, e); + checkFlag(f.getFlgAdmin(), "管理者フラグ", e); + return e; + } - /** 管理者による編集:全項目。パスワードは空なら変更しない。 */ - public List validateUpdateByAdmin(EmployeeForm f) { - f.trim(); - List e = new ArrayList<>(); - checkBasic(f, e); - checkMail(f, f.getIdEmployee(), e); - checkFlag(f.getFlgAdmin(), "管理者フラグ", e); - checkFlag(f.getFlgRetirement(), "退職フラグ", e); - if (f.getPassword().length() > 256) e.add("パスワードは256文字以内で入力してください。"); - return e; - } + /** 管理者による編集:全項目。パスワードは空なら変更しない。 */ + public List validateUpdateByAdmin(EmployeeForm f) { + f.trim(); + List e = new ArrayList<>(); + checkBasic(f, e); + checkMail(f, f.getIdEmployee(), e); + checkFlag(f.getFlgAdmin(), "管理者フラグ", e); + checkFlag(f.getFlgRetirement(), "退職フラグ", e); + if (f.getPassword().length() > 256) + e.add("パスワードは256文字以内で入力してください。"); + return e; + } - /** 一般ユーザーによる編集:パスワードのみ(必須)。 */ - public List validateUpdateBySelf(EmployeeForm f) { - f.trim(); - List e = new ArrayList<>(); - if (f.getPassword().isEmpty()) e.add("パスワードを入力してください。"); - else if (f.getPassword().length() > 256) e.add("パスワードは256文字以内で入力してください。"); - return e; - } + /** 一般ユーザーによる編集:パスワードのみ(必須)。 */ + public List validateUpdateBySelf(EmployeeForm f) { + f.trim(); + List e = new ArrayList<>(); + if (f.getPassword().isEmpty()) + e.add("パスワードを入力してください。"); + else if (f.getPassword().length() > 256) + e.add("パスワードは256文字以内で入力してください。"); + return e; + } - private void checkBasic(EmployeeForm f, List e) { - if (f.getNmEmployee().isEmpty()) e.add("社員名を入力してください。"); - else if (f.getNmEmployee().length() > 50) e.add("社員名は50文字以内で入力してください。"); - // ※社員名よみの文字種(ひらがなのみ等)は設計で確定する。現状は文字数のみチェック - if (f.getKnEmployee().isEmpty()) e.add("社員名よみを入力してください。"); - else if (f.getKnEmployee().length() > 100) e.add("社員名よみは100文字以内で入力してください。"); - } + private void checkBasic(EmployeeForm f, List e) { + if (f.getNmEmployee().isEmpty()) + e.add("社員名を入力してください。"); + else if (f.getNmEmployee().length() > 50) + e.add("社員名は50文字以内で入力してください。"); + // ※社員名よみの文字種(ひらがなのみ等)は設計で確定する。現状は文字数のみチェック + if (f.getKnEmployee().isEmpty()) + e.add("社員名よみを入力してください。"); + else if (f.getKnEmployee().length() > 100) + e.add("社員名よみは100文字以内で入力してください。"); + else if (!f.getKnEmployee().matches("^[\\u3040-\\u309F]+$")) + e.add("社員名よみはひらがなで入力してください"); + } - private void checkMail(EmployeeForm f, Integer selfId, List e) { - String m = f.getMailAddress(); - if (m.isEmpty()) { e.add("メールアドレスを入力してください。"); return; } - if (m.length() > 256) { e.add("メールアドレスは256文字以内で入力してください。"); return; } - if (!MAIL.matcher(m).matches()) { e.add("メールアドレスの形式が正しくありません。"); return; } - Optional dup = employeeRepository.findByMailAddress(m); - if (dup.isPresent() && !dup.get().getIdEmployee().equals(selfId)) e.add(MSG_DUP); - } + private void checkMail(EmployeeForm f, Integer selfId, List e) { + String m = f.getMailAddress(); + if (m.isEmpty()) { + e.add("メールアドレスを入力してください。"); + return; + } + if (m.length() > 256) { + e.add("メールアドレスは256文字以内で入力してください。"); + return; + } + if (!MAIL.matcher(m).matches()) { + e.add("メールアドレスの形式が正しくありません。"); + return; + } + Optional dup = employeeRepository.findByMailAddress(m); + if (dup.isPresent() && !dup.get().getIdEmployee().equals(selfId)) + e.add(MSG_DUP); + } - private static void checkFlag(String v, String label, List e) { - if (!"0".equals(v) && !"1".equals(v)) e.add(label + "が正しくありません。"); - } + private static void checkFlag(String v, String label, List e) { + if (!"0".equals(v) && !"1".equals(v)) + e.add(label + "が正しくありません。"); + } - // ---------- 登録・更新 ---------- + // ---------- 登録・更新 ---------- - @Transactional - public Integer register(EmployeeForm f, LoginUser admin) { - raise(validateRegist(f)); - Employee e = new Employee(); - e.setNmEmployee(f.getNmEmployee()); - e.setKnEmployee(f.getKnEmployee()); - e.setMailAddress(f.getMailAddress()); - e.setPassword(Const.DEFAULT_PASSWORD); - e.setFlgAdmin(f.getFlgAdmin()); - e.setFlgRetirement(Const.RETIRE_NO); - e.setIdUpdate(admin.getIdEmployee()); - e.setDateUpdate(LocalDateTime.now()); - try { - return employeeRepository.saveAndFlush(e).getIdEmployee(); - } catch (DataIntegrityViolationException ex) { - throw new BusinessException(MSG_DUP); // 同時登録によるUNIQUE制約違反 - } - } + @Transactional + public Integer register(EmployeeForm f, LoginUser admin) { + raise(validateRegist(f)); + Employee e = new Employee(); + e.setNmEmployee(f.getNmEmployee()); + e.setKnEmployee(f.getKnEmployee()); + e.setMailAddress(f.getMailAddress()); + e.setPassword(Const.DEFAULT_PASSWORD); + e.setFlgAdmin(f.getFlgAdmin()); + e.setFlgRetirement(Const.RETIRE_NO); + e.setIdUpdate(admin.getIdEmployee()); + e.setDateUpdate(LocalDateTime.now()); + try { + return employeeRepository.saveAndFlush(e).getIdEmployee(); + } catch (DataIntegrityViolationException ex) { + throw new BusinessException(MSG_DUP); // 同時登録によるUNIQUE制約違反 + } + } - @Transactional - public void updateByAdmin(EmployeeForm f, LoginUser admin) { - raise(validateUpdateByAdmin(f)); - Employee e = find(f.getIdEmployee()); - e.setNmEmployee(f.getNmEmployee()); - e.setKnEmployee(f.getKnEmployee()); - e.setMailAddress(f.getMailAddress()); - if (!f.getPassword().isEmpty()) e.setPassword(f.getPassword()); - e.setFlgAdmin(f.getFlgAdmin()); - e.setFlgRetirement(f.getFlgRetirement()); - e.setIdUpdate(admin.getIdEmployee()); - e.setDateUpdate(LocalDateTime.now()); - try { - employeeRepository.saveAndFlush(e); - } catch (DataIntegrityViolationException ex) { - throw new BusinessException(MSG_DUP); - } - } + @Transactional + public void updateByAdmin(EmployeeForm f, LoginUser admin) { + raise(validateUpdateByAdmin(f)); + Employee e = find(f.getIdEmployee()); + e.setNmEmployee(f.getNmEmployee()); + e.setKnEmployee(f.getKnEmployee()); + e.setMailAddress(f.getMailAddress()); + if (!f.getPassword().isEmpty()) + e.setPassword(f.getPassword()); + e.setFlgAdmin(f.getFlgAdmin()); + e.setFlgRetirement(f.getFlgRetirement()); + e.setIdUpdate(admin.getIdEmployee()); + e.setDateUpdate(LocalDateTime.now()); + try { + employeeRepository.saveAndFlush(e); + } catch (DataIntegrityViolationException ex) { + throw new BusinessException(MSG_DUP); + } + } - /** 一般ユーザー:自分自身(セッションの社員ID)のパスワードのみ更新する。 */ - @Transactional - public void updateBySelf(EmployeeForm f, LoginUser self) { - raise(validateUpdateBySelf(f)); - Employee e = find(self.getIdEmployee()); - e.setPassword(f.getPassword()); - e.setIdUpdate(self.getIdEmployee()); - e.setDateUpdate(LocalDateTime.now()); - } + /** 一般ユーザー:自分自身(セッションの社員ID)のパスワードのみ更新する。 */ + @Transactional + public void updateBySelf(EmployeeForm f, LoginUser self) { + raise(validateUpdateBySelf(f)); + Employee e = find(self.getIdEmployee()); + e.setPassword(f.getPassword()); + e.setIdUpdate(self.getIdEmployee()); + e.setDateUpdate(LocalDateTime.now()); + } - private static void raise(List errors) { - if (!errors.isEmpty()) throw new BusinessException(String.join(" ", errors)); - } + private static void raise(List errors) { + if (!errors.isEmpty()) + throw new BusinessException(String.join(" ", errors)); + } } From 2687c00f35b6846c099d6e0389f0813727c91ef7 Mon Sep 17 00:00:00 2001 From: "h.hein" <26-h-kyaw-sakuracommunication@it-college.co.jp> Date: Tue, 27 Oct 2026 09:34:55 +0900 Subject: [PATCH 2/2] Login Desing Html Css --- .../src/main/resources/static/css/style.css | 179 ++++++++------- .../src/main/resources/templates/login.html | 216 +++++++++--------- 2 files changed, 206 insertions(+), 189 deletions(-) diff --git a/book-rent/src/main/resources/static/css/style.css b/book-rent/src/main/resources/static/css/style.css index bfebba8..056edc5 100644 --- a/book-rent/src/main/resources/static/css/style.css +++ b/book-rent/src/main/resources/static/css/style.css @@ -1,90 +1,113 @@ -body -{font-family: - "Meiryo","Hiragino Sans",sans-serif; - margin:0;color:#222; - background:#f6f7f9} -header.top -{display:flex; - justify-content:space-between; - align-items:center; - background:#176a78;color:#fff; - padding:10px 20px +/* ---------------------------------------------------- + Login Layout & Animation Styles (Updated) +---------------------------------------------------- */ +body { + font-family: "Meiryo", "Hiragino Sans", sans-serif; + margin: 0; + color: #222; + background: #f6f7f9; } -header.top form -{display:inline; - margin:0} -header.top .user -{margin-right:12px +header.top { + display: flex; + justify-content: space-between; + align-items: center; + background: #176a78; + color: #fff; + padding: 10px 20px; } -main -{max-width:960px; - margin:24px auto; - padding:0 16px +header.top form { display: inline; margin: 0; } +header.top .user { margin-right: 12px; } +main { max-width: 960px; margin: 24px auto; padding: 0 16px; } +h1 { font-size: 20px; } +.card { background: #fff; border: 1px solid #dde; border-radius: 6px; padding: 20px; margin-bottom: 16px; } +label { display: block; margin: 10px 0 4px; font-weight: bold; } +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; background: #176a78; color: #fff; border: 0; border-radius: 4px; padding: 7px 16px; cursor: pointer; text-decoration: none; font-size: 14px; } +button.sub, .btn.sub { background: #6b7b80; } +.error { background: #fdecea; color: #b3261e; border: 1px solid #f5c2be; padding: 8px 12px; border-radius: 4px; margin-bottom: 12px; } +.info { background: #e8f4ea; color: #1b5e20; border: 1px solid #bfdcc3; padding: 8px 12px; border-radius: 4px; margin-bottom: 12px; } +table { border-collapse: collapse; width: 100%; background: #fff; } +th, td { border: 1px solid #dde; padding: 6px 8px; text-align: left; font-size: 14px; } +th { background: #eaf4f6; } +.menu a { display: block; margin: 8px 0; } + +/* Flexbox Layout: ဘယ်ဘက် Icon နှင့် ညာဘက် Login အချက်အလက်များ ဘေးချင်းယှဉ်ရန် */ +.login-container-flex { + display: flex; + align-items: flex-start; + gap: 35px; /* Icon နှင့် Form ကြား အကွာအဝေး */ } -h1 -{font-size:20px + +/* ဘယ်ဘက်ခြမ်း Icon Box Styling */ +.avatar-box { + flex-shrink: 0; + width: 90px; + height: 90px; + background: #eaf4f6; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.4s ease; + cursor: pointer; + margin-top: 5px; } -.card -{background:#fff; - border:1px solid #dde; - border-radius:6px; - padding:20px; - margin-bottom:16px + +.avatar-box:hover { + transform: scale(1.08); + background: #d5edf1; } -label -{display:block; - margin:10px 0 4px; - font-weight:bold + +/* ညာဘက်ခြမ်း Form Area ကို အပြည့်အသုံးပြုရန် */ +.form-content-area { + flex-grow: 1; } -input[type=text],input[type=password],input[type=email] -{width:100%; - max-width:360px; - padding:6px; - box-sizing:border-box + +/* 1. FALSE / ERROR State (တုန်ခါမည်) */ +.card.shake { + animation: shake 0.4s ease-in-out; } -button,.btn -{display:inline-block; - background:#176a78; - color:#fff;border:0; - border-radius:4px; - padding:7px 16px; - cursor:pointer; - text-decoration:none; - font-size:14px + +.avatar-box.error-state { + background: #fdecea !important; + animation: pulseError 0.4s ease-in-out; } -button.sub,.btn.sub -{background:#6b7b80 + +@keyframes shake { + 0%, 100% { transform: translateX(0); } + 20%, 60% { transform: translateX(-8px); } + 40%, 80% { transform: translateX(8px); } } -.error -{background:#fdecea;color:#b3261e; - border:1px solid #f5c2be; - padding:8px 12px; - border-radius:4px; - margin-bottom:12px + +@keyframes pulseError { + 0% { transform: scale(1); } + 50% { transform: scale(1.15); } + 100% { transform: scale(1); } } -.info -{background:#e8f4ea; - color:#1b5e20; - border:1px solid #bfdcc3; - padding:8px 12px; - border-radius:4px; - margin-bottom:12px + +/* 2. TRUE / SUCCESS State (အောင်မြင်မှု Animation) */ +.avatar-box.success-state { + background: #e8f4ea !important; + animation: successFly 0.6s ease-in-out forwards; } -table -{border-collapse:collapse; - width:100%; - background:#fff -} -th,td -{border:1px solid #dde; - padding:6px 8px; - text-align:left; - font-size:14px -} -th -{background:#eaf4f6 -} -.menu a -{display:block; - margin:8px 0 + +@keyframes successFly { + 0% { transform: scale(1); } + 40% { transform: scale(1.2) translateY(-8px); } + 100% { transform: scale(0.9) translateY(-20px); opacity: 0.8; } } + +/* 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; + } +} \ No newline at end of file diff --git a/book-rent/src/main/resources/templates/login.html b/book-rent/src/main/resources/templates/login.html index 26aaa40..5452d9d 100644 --- a/book-rent/src/main/resources/templates/login.html +++ b/book-rent/src/main/resources/templates/login.html @@ -1,123 +1,117 @@ - - - ログイン - + + ログイン + + + + + - -
-

書籍貸出管理システム

-
-

ログイン

-
-
- - - - -

-
-
-
+
+

書籍貸出管理システム

+
+ + + + +
+
+ + - - - - - - - - - - - - - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + - \ No newline at end of file +