Controller를 만들어 CRUD의 C(Create)를 구현할 것이다.
BoardController를 만들고 초기 화면과 게시글 작성 화면을 만들어보자.
BoardController
@Controller
@RequiredArgsConstructor
public class BoardController {
private final BoardService boardService;
@GetMapping("/")
public String boardList(Model model){
List<Board> boards = boardService.findBoards();
model.addAttribute("boardList", boards);
return "board/boardList";
}
@GetMapping("/boardForm")
public String boardForm(){
return "board/boardForm";
}
@PostMapping("/boardForm")
public String boardSummit(@ModelAttribute("board") Board board){
boardService.save(board);
return "redirect:/";
}
}
@GetMapping("/")
데이터베이스의 모든 데이터를 List로 받아 model에 넘겨 출력시켜줍니다.
@GetMapping("/boardForm")
게시글 양식을 화면에 출력합니다.
@PostMapping("/boardForm")
입력받은 정보로 게시글을 만들어 저장합니다.
부트스트랩에서 복사해온 html 파일에 겹치는 부분은 header, bodyHeader로 관리하여 중복을 줄이자
header.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head th:fragment="header">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="">
<meta name="author" content="Mark Otto, Jacob Thornton, and Bootstrap contributors">
<meta name="generator" content="Hugo 0.98.0">
<title>Headers · Bootstrap v5.2</title>
<link rel="canonical" href="https://getbootstrap.com/docs/5.2/examples/headers/">
<link href="/css/bootstrap.min.css" rel="stylesheet">
<style>
.bd-placeholder-img {
font-size: 1.125rem;
text-anchor: middle;
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
}
@media (min-width: 768px) {
.bd-placeholder-img-lg {
font-size: 3.5rem;
}
}
.b-example-divider {
height: 3rem;
background-color: rgba(0, 0, 0, .1);
border: solid rgba(0, 0, 0, .15);
border-width: 1px 0;
box-shadow: inset 0 .5em 1.5em rgba(0, 0, 0, .1), inset 0 .125em .5em rgba(0, 0, 0, .15);
}
.b-example-vr {
flex-shrink: 0;
width: 1.5rem;
height: 100vh;
}
.bi {
vertical-align: -.125em;
fill: currentColor;
}
.nav-scroller {
position: relative;
z-index: 2;
height: 2.75rem;
overflow-y: hidden;
}
.nav-scroller .nav {
display: flex;
flex-wrap: nowrap;
padding-bottom: 1rem;
margin-top: -1px;
overflow-x: auto;
text-align: center;
white-space: nowrap;
-webkit-overflow-scrolling: touch;
}
</style>
<!-- Custom styles for this template -->
<link href="/css/headers.css" rel="stylesheet">
</head>
bodyHeader.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<div class="header" th:fragment="bodyHeader">
<header class="d-flex flex-wrap align-items-center justify-content-center justify-content-md-between py-3 mb-4 border-bottom">
<a href="/" class="d-flex align-items-center col-md-3 mb-2 mb-md-0 text-dark text-decoration-none">
<svg class="bi me-2" width="40" height="32" role="img" aria-label="Bootstrap">
<use xlink:href="#bootstrap"></use>
</svg>
</a>
<ul class="nav col-12 col-md-auto mb-2 justify-content-center mb-md-0">
<li><a href="#" class="nav-link px-2 link-secondary">Home</a></li>
<li><a href="#" class="nav-link px-2 link-dark">Features</a></li>
<li><a href="#" class="nav-link px-2 link-dark">Pricing</a></li>
<li><a href="#" class="nav-link px-2 link-dark">FAQs</a></li>
<li><a href="#" class="nav-link px-2 link-dark">About</a></li>
</ul>
<div class="col-md-3 text-end">
<button type="button" class="btn btn-outline-primary me-2">Login</button>
<button type="button" class="btn btn-primary">Sign-up</button>
</div>
</header>
</div>
원래 header나 bodyHeader 부분은 다음과 같이 대체할 수 있다.
//fragments디렉토리에 header파일로 대체
<head th:replace="fragments/header :: header" />
//fragments디렉토리에 bodyHeader파일로 대체
<div th:replace="fragments/bodyHeader :: bodyHeader"/>
이렇게 하여 코드가 훨씬 깔끔해지고 화면 구성에 집중할 수 있다.
BoardList.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head th:replace="fragments/header :: header" />
<body>
<main>
<div class="container">
<div th:replace="fragments/bodyHeader :: bodyHeader"/>
</div>
</main>
<div class = "container">
<table class="table">
<thead>
<tr>
<th>글 번호</th>
<th>제목</th>
<th>작성자</th>
<th>조회</th>
</tr>
</thead>
<tbody>
<tr th:each = "board : ${boardList}">
<td th:text="${board.id}"></td>
<td th:text="${board.title}"></td>
<td th:text="${board.writer}"></td>
<td th:text="${board.view}"></td>
</tr>
</tbody>
</table>
<a href="#" th:href="@{/boardForm}" class="btn btn-primary" role="button">글쓰기</a>
</div>
<script src="/js/bootstrap.bundle.min.js"></script>
</body>
</html>
BoardForm.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head th:replace="fragments/header :: header" />
<body>
<main>
<div class="container">
<div th:replace="fragments/bodyHeader :: bodyHeader"/>
</div>
</main>
<div class = "container">
<div class = "row">
<div class = "col-sm-12">
<form th:action="@{/boardForm}" method = "post">
<div class = "form-group">
<label th:for="title">제목</label>
<input type="text" id = "title" name = "title" class = "form-control" placeholder="제목을 입력하세요">
</div>
<div class = "form-group">
<label th:for="writer">작성자</label>
<input type="text" id = "writer" name = "writer" class = "form-control" placeholder="작성자를 입력하세요">
</div>
<div class = "form-group">
<label th:for="content">내용</label>
<textarea id = "content" name = "content" class = "form-control"></textarea>
</div>
<button type = "submit" class="btn btn-primary">글쓰기</button>
</form>
</div>
</div>
</div>
<script src="/js/bootstrap.bundle.min.js"></script>
</body>
</html>
Test는 MockMvc 객체를 사용하여 진행합니다.
BoardControllerTest
@ExtendWith(SpringExtension.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
@AutoConfigureMockMvc
class BoardControllerTest {
@Autowired
MockMvc mockMvc;
@Autowired
BoardService boardService;
@Before
public void setUp() {
mockMvc = MockMvcBuilders
.standaloneSetup(new BoardController(boardService))
.build();
}
@Test
void 초기화면() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/"))
.andExpect(MockMvcResultMatchers.status().isOk());
}
@Test
void 게시글_작성() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.post("/boardForm")
.param("title","hi")
.param("writer","lee")
.param("content","hello"))
.andExpect(MockMvcResultMatchers.status().is3xxRedirection());
}
@Test
void 게시글_출력() throws Exception{
mockMvc.perform(MockMvcRequestBuilders.get("/"))
.andExpect(MockMvcResultMatchers.model().attributeExists("boardList"))
.andExpect(MockMvcResultMatchers.status().isOk());
}
}

처음 사용해본 MockMvc테스트라 잘했는지 모르겠다..
테스트를 완료하고 실제로 화면을 띄워보자


다음에는 게시글을 읽는 기능을 구현하여 보자
'Spring' 카테고리의 다른 글
| 스프링부트 게시판 만들기 - 4 (BootStrap) (0) | 2022.06.29 |
|---|---|
| 스프링부트 게시판 만들기 - 3 (Board Entity, Repository, Service, Test) (0) | 2022.06.28 |
| 스프링부트 게시판 만들기 - 2 (H2 데이터베이스와 연결) (0) | 2022.06.28 |
| 스프링부트 게시판 만들기 - 1 (초기 세팅) (0) | 2022.06.28 |