게시판에 사용할 폼 만들기
https://getbootstrap.com/docs/5.2/forms/form-control/
form 태그 안에 코드 추가
<div class="mb-3">
<label for="exampleFormControlInput1" class="form-label">Email address</label>
<input type="email" class="form-control" id="exampleFormControlInput1" placeholder="name@example.com">
</div>
<div class="mb-3">
<label for="exampleFormControlTextarea1" class="form-label">Example textarea</label>
<textarea class="form-control" id="exampleFormControlTextarea1" rows="3"></textarea>
</div>
form.html
<!doctype html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head th:replace="fragments/common :: head('게시판')">
</head>
<body class="d-flex flex-column h-100">
<header th:replace="fragments/common :: menu('board')">
</header>
<!-- Begin page content -->
<main class="flex-shrink-0">
<div class="container">
<h2>게시판</h2>
<div class="mb-3">
<label for="title" class="form-label">제목</label>
<input type="email" class="form-control" id="title" >
</div>
<form>
<div class="mb-3">
<label for="content" class="form-label">내용</label>
<textarea class="form-control" id="content" rows="3"></textarea>
</div>
</form>
</main>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-A3rJD856KowSb7dwlZdYEkO39Gagi7vIsF0jrRAoQmDKKtQBHUuLZ9AsSv4jD4Xa" crossorigin="anonymous"></script>
</body>
</html>
취소, 확인 버튼 추가
form.html
<!doctype html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head th:replace="fragments/common :: head('게시판')">
</head>
<body class="d-flex flex-column h-100">
<header th:replace="fragments/common :: menu('board')">
</header>
<!-- Begin page content -->
<main class="flex-shrink-0">
<div class="container">
<h2>게시판</h2>
<div class="mb-3">
<label for="title" class="form-label">제목</label>
<input type="email" class="form-control" id="title" >
</div>
<form>
<div class="mb-3">
<label for="content" class="form-label">내용</label>
<textarea class="form-control" id="content" rows="3"></textarea>
</div>
<div class="text-end">
<a type="button" class="btn btn-primary" th:href="@{/board/list}">취소</a>
<button type="submit" class="btn btn-primary">확인</button>
</div>
</form>
</div>
</main>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-A3rJD856KowSb7dwlZdYEkO39Gagi7vIsF0jrRAoQmDKKtQBHUuLZ9AsSv4jD4Xa" crossorigin="anonymous"></script>
</body>
</html>
list.html
<!doctype html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head th:replace="fragments/common :: head('게시판')">
</head>
<body class="d-flex flex-column h-100">
<header th:replace="fragments/common :: menu('board')">
</header>
<!-- Begin page content -->
<main class="flex-shrink-0">
<div class="container">
<h2>게시판</h2>
<div>총 건수 : <span th:text="${#lists.size(boards)}"></span></div>
</div>
<table class="table">
<thead>
<tr>
<th scope="col">번호</th>
<th scope="col">제목</th>
<th scope="col">작성자</th>
</tr>
</thead>
<tbody>
<tr th:each="board : ${boards}">
<td th:text="${board.id}">Mark</td>
<td th:text="${board.title}">Otto</td>
<td>홍길동</td>
</tr>
</tbody>
</table>
<div class="text-end">
<a type="button" class="btn btn-primary" th:href="@{/board/form}">쓰기</a>
</div>
</div>
</main>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-A3rJD856KowSb7dwlZdYEkO39Gagi7vIsF0jrRAoQmDKKtQBHUuLZ9AsSv4jD4Xa" crossorigin="anonymous"></script>
</body>
</html>
form 전송하기
https://spring.io/guides/gs/handling-form-submission/
package com.toy.board.web;
import com.toy.board.domain.Board;
import com.toy.board.reopsitory.BoardRepository;
import lombok.RequiredArgsConstructor;
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.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.List;
@Controller
@RequestMapping("/board")
public class BoardController {
@Autowired
private BoardRepository boardRepository;
@GetMapping("/list")
public String list(Model model) {
List<Board> boards = boardRepository.findAll();
model.addAttribute("boards", boards);
return "/board/list";
}
@GetMapping("/form")
public String form(Model model) {
model.addAttribute("board", new Board());
return "/board/form";
}
@PostMapping("/form")
public String form(@ModelAttribute Board board) {
boardRepository.save(board);
return "redirect:/board/list";
}
}
form.html
<!doctype html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head th:replace="fragments/common :: head('게시판')">
</head>
<body class="d-flex flex-column h-100">
<header th:replace="fragments/common :: menu('board')">
</header>
<!-- Begin page content -->
<main class="flex-shrink-0">
<div class="container">
<h2>게시판</h2>
<form action="#" th:action="@{/board/form}" th:object="${board}" method="post">
<div class="mb-3">
<label for="title" class="form-label">제목</label>
<input type="text" class="form-control" id="title" th:field="*{title}">
</div>
<div class="mb-3">
<label for="content" class="form-label">내용</label>
<textarea class="form-control" id="content" rows="3" th:field="*{content}"></textarea>
</div>
<div class="text-end">
<a type="button" class="btn btn-primary" th:href="@{/board/list}">취소</a>
<button type="submit" class="btn btn-primary" >확인</button>
</div>
</form>
</div>
</main>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-A3rJD856KowSb7dwlZdYEkO39Gagi7vIsF0jrRAoQmDKKtQBHUuLZ9AsSv4jD4Xa" crossorigin="anonymous"></script>
</body>
</html>
제목을 링크로 form 작성 페이지로 이동하기
https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html
@GetMapping("/form")
public String form(Model model, @RequestParam(required = false) Long id) {
if (id == null) {
model.addAttribute("board", new Board());
} else {
Optional<Board> board = boardRepository.findById(id);
model.addAttribute("board", board);
}
return "/board/form";
}
list.html
<!doctype html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head th:replace="fragments/common :: head('게시판')">
</head>
<body class="d-flex flex-column h-100">
<header th:replace="fragments/common :: menu('board')">
</header>
<!-- Begin page content -->
<main class="flex-shrink-0">
<div class="container">
<h2>게시판</h2>
<div>총 건수 : <span th:text="${#lists.size(boards)}"></span></div>
</div>
<table class="table">
<thead>
<tr>
<th scope="col">번호</th>
<th scope="col">제목</th>
<th scope="col">작성자</th>
</tr>
</thead>
<tbody>
<tr th:each="board : ${boards}">
<td th:text="${board.id}">Mark</td>
<td><a th:text="${board.title}" th:href="@{/board/form(id=${board.id})}">Otto</a></td>
<td>홍길동</td>
</tr>
</tbody>
</table>
<div class="text-end">
<a type="button" class="btn btn-primary" th:href="@{/board/form}">쓰기</a>
</div>
</div>
</main>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-A3rJD856KowSb7dwlZdYEkO39Gagi7vIsF0jrRAoQmDKKtQBHUuLZ9AsSv4jD4Xa" crossorigin="anonymous"></script>
</body>
</html>
수정 기능 넣기
form.html
<!doctype html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head th:replace="fragments/common :: head('게시판')">
</head>
<body class="d-flex flex-column h-100">
<header th:replace="fragments/common :: menu('board')">
</header>
<!-- Begin page content -->
<main class="flex-shrink-0">
<div class="container">
<h2>게시판</h2>
<form action="#" th:action="@{/board/form}" th:object="${board}" method="post">
<input type="hidden" th:field="*{id}">
<div class="mb-3">
<label for="title" class="form-label">제목</label>
<input type="text" class="form-control" id="title" th:field="*{title}">
</div>
<div class="mb-3">
<label for="content" class="form-label">내용</label>
<textarea class="form-control" id="content" rows="3" th:field="*{content}"></textarea>
</div>
<div class="text-end">
<a type="button" class="btn btn-primary" th:href="@{/board/list}">취소</a>
<button type="submit" class="btn btn-primary" >확인</button>
</div>
</form>
</div>
</main>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-A3rJD856KowSb7dwlZdYEkO39Gagi7vIsF0jrRAoQmDKKtQBHUuLZ9AsSv4jD4Xa" crossorigin="anonymous"></script>
</body>
</html>
form.html 파일에 코드 추가
<input type="hidden" th:field="*{id}">
form 데이터 검사하기
https://spring.io/guides/gs/validating-form-input/
validation 의존성 추가
implementation 'org.springframework.boot:spring-boot-starter-validation'
board.java
package com.toy.board.domain;
import lombok.Data;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
@Entity
@Data
public class Board {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NotNull
@Size(min=2, max=30)
private String title;
private String content;
}
@NotNull, @Size 어노테이션을 사용한다.
@PostMapping("/form")
public String form(@Valid Board board, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
return "board/form";
}
boardRepository.save(board);
return "redirect:/board/list";
}
@ModelAttribute 대신 @Valid를 사용, BindingResult 를 통해 데이터를 검증한다.
에러 표시는 Bootstrap 을 이용한다.
https://getbootstrap.com/docs/5.2/forms/validation/#server-side
from.html
<!doctype html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head th:replace="fragments/common :: head('게시판')">
</head>
<body class="d-flex flex-column h-100">
<header th:replace="fragments/common :: menu('board')">
</header>
<!-- Begin page content -->
<main class="flex-shrink-0">
<div class="container">
<h2>게시판</h2>
<form action="#" th:action="@{/board/form}" th:object="${board}" method="post">
<input type="hidden" th:field="*{id}">
<div class="mb-3">
<label for="title" class="form-label">제목</label>
<input type="text" class="form-control" th:classappend="${#fields.hasErrors('title')} ? 'is-invalid'"
id="title" th:field="*{title}">
<div class="invalid-feedback" th:if="${#fields.hasErrors('title')}" th:errors="*{title}">
제목 에러 메시지
</div>
</div>
<div class="mb-3">
<label for="content" class="form-label">내용</label>
<textarea class="form-control" th:classappend="${#fields.hasErrors('content')} ? 'is-invalid'"
id="content" rows="3" th:field="*{content}"></textarea>
<div class="invalid-feedback" th:if="${#fields.hasErrors('content')}" th:errors="*{content}">
내용 에러 메시지
</div>
</div>
<div class="text-end">
<a type="button" class="btn btn-primary" th:href="@{/board/list}">취소</a>
<button type="submit" class="btn btn-primary" >확인</button>
</div>
</form>
</div>
</main>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-A3rJD856KowSb7dwlZdYEkO39Gagi7vIsF0jrRAoQmDKKtQBHUuLZ9AsSv4jD4Xa" crossorigin="anonymous"></script>
</body>
</html>
th:classappend="${#fields.hasErrors('title')} ? 'is-invalid'"
<div class="invalid-feedback" th:if="${#fields.hasErrors('title')}" th:errors="*{title}">
제목 에러 메시지
</div>
위 코드들 추가
validator 커스텀 하기
BoardValidator.java
package com.toy.board.validator;
import com.toy.board.domain.Board;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
@Component
public class BoardValidator implements Validator {
@Override
public boolean supports(Class<?> clazz) {
return Board.class.equals(clazz);
}
@Override
public void validate(Object obj, Errors errors) {
Board b = (Board) obj;
if (StringUtils.isEmpty(b.getContent())) {
errors.rejectValue("content", "key", "내용을 입력하세요.");
}
}
}
erros.rejectValue : 첫 번째 파리미터 field 값, 두 번째 "error code", 세 번째 defaultMessage
Board.java
package com.toy.board.domain;
import lombok.Data;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
@Entity
@Data
public class Board {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NotNull
@Size(min=2, max=30, message = "제목은 2자이상 30자 이하입니다.")
private String title;
private String content;
}
@Size 어노테이션 세 번째 파라미터에 message 값 넣기
'Bootstrap' 카테고리의 다른 글
Bootstrap - table, button (0) | 2022.09.07 |
---|---|
Bootstrap - starter (0) | 2022.09.06 |
Bootstrap - Spring Boot에 적용하기 (0) | 2022.09.02 |