들어가기에 앞서
실제 프로젝트 진행했던 코드 내용 및 세부 내용은 일부만 업로드하였습니다.
resource > templates > new directory 'articles' > new HTML 'index.html'
semantic tag
사용, 초기 뼈대 구상<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>게시판 페이지</title>
</head>
<body>
<header>
header 삽입부
<hr>
</header>
<main>
검색창
테이블
내비게이션 바
</main>
<footer>
<hr>
footer 삽입부
</footer>
</body>
</html>
ctrl + d
한줄 복사@RequestMapping("/articles")
@Controller
public class ArticleController {
@GetMapping
public String articles(ModelMap map) {
map.addAttribute("articles", List.of());
return "articles/index";
}
}
contentType
> contentTypeCompatibleWith
로 변경 (호환되는 타입도 포함)contentType
은 완전히 일치해야 통과를 시키는데, 테스트 페이지가 UTF-8이 포함되어 있어 HTML과 완전히 일치하지 않는다고 판단함.contentTypeCompatibleWith
로 변경 @DisplayName("[VIEW][GET] 게시글 리스트 (게시판 페이지 - 정상 호출")
@Test
public void givenNothing_whenRequestingArticlesView_thenReturnsArticlesView() throws Exception {
// Given
// When & Then
mvc.perform(get("/articles"))
.andExpect(status().isOk()) // 정상 호출인지
.andExpect(content().contentTypeCompatibleWith(MediaType.TEXT_HTML)) // HTML 파일의 컨텐츠인지 (호환되는 컨텐츠 포함)
.andExpect(view().name("articles/index")) // 뷰 이름 검사
.andExpect(model().attributeExists("articles")); // 내부에 값이 있는지 (이름을 articles로 지정)
}
ctrl+shift+f9
로 변경된 내용 바로 반영ctrl+shift+f9
와 구글 LiveReload
활용 시 변경된 내용이 새로고침을 하지 않아도 실시간으로 반영됨 <nav>
<table>
<tr>
<td>previous</td>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
<td>next</td>
</tr>
</table>
</nav>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<header th:replace="header :: header"></header>
<footer> <header th:replace="footer :: footer"></header></footer>
tree appearance
에서 compact middle package
해제 후 제작<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Header template</title>
</head>
<body>
<header>
header 삽입부
<hr>
</header>
</body>
</html>
<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Footer template</title>
</head>
<body>
<footer>
<hr>
footer 삽입부
</footer>
</body>
</html>
@ConfigurationPropertiesScan
추가 @RequiredArgsConstructor
@Getter
@ConstructorBinding
@ConfigurationProperties("spring.thymeleaf3")
public static class Thymeleaf3Properties {
private final boolean decoupledLogic;
thymeleaf3.decoupled-logic: true
spring initializr > spring configuration processor
<header id="header"></header>
<footer id="footer"></footer>
<?xml version="1.0"?>
<thlogic>
<attr sel="#header" th:replace="header :: header" />
<attr sel="#footer" th:replace="footer :: footer" />
</thlogic>
@GetMapping("/{articleId}")
public String article(@PathVariable Long articleId, ModelMap map) {
map.addAttribute("article", "article"); // TODO : 실제 데이터 구현할 때 여기에 넣어야 함
map.addAttribute("articleComments", List.of());
return "articles/detail";
}
<?xml version="1.0"?>
<thlogic>
<attr sel="#header" th:replace="header :: header" />
<attr sel="#footer" th:replace="footer :: footer" />
</thlogic>