Thymeleaf 3.1 release note
๐ก ์ด๋ฒ ํฌ์คํ ์์๋ ํ์๋ฆฌํ 3.1 ๋ฒ์ ์ ๋ณ๊ฒฝ์ฌํญ์ ๋ํด ์ ๋ฆฌํด ๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
Spring 6.0 ๊ทธ๋ฆฌ๊ณ Spring Boot๊ฐ 3.0 ๊ฐ๊ฐ ๋ฉ์ด์ ๋ฒ์ ์ด ์ฌ๋ผ๊ฐ์ ๋ฐ๋ผ ํ์๋ฆฌํ ๋ํ ํธํ์ฑ์ ๋ง์ถ๊ธฐ ์ํด ๋ฒ์ ์ 3.1๋ก ์ฌ๋ ธ์ต๋๋ค.
์์ธํ ๋ด์ฉ์ ๊ณต์ ๋ฌธ์๋ฅผ ์ฐธ๊ณ ํ์๋ฉด ์ข์ ๊ฒ ๊ฐ์ต๋๋ค.
๋จผ์ ์ 3๊ฐ์ ๋ณ๊ฒฝ ์ฌํญ์ Spring๊ณผ ๊ด๋ จ์ด ์๋ ๋ถ๋ถ์
๋๋ค. Spring์์ 6.0์์ ํธํ์ฑ์ ๋ง์ถ๊ธฐ ์ํด javax.\*
ํจํค์ง ๋์ jakarta.\*
ํจํค์ง๊ฐ ์ฌ์ฉ๋๊ณ , Spring Security 5.X ์์๋ ํ์๋ฆฌํ์ ์ฐ๋ํ๊ธฐ ์ํด thymeleaf-extras-springsecurity5
์์กด์ฑ์ ์ฌ์ฉํ๋๋ฐ ์ด์ thymeleaf-extras-springsecurity6
์์กด์ฑ์ ์ฌ์ฉํด์ผ ํ๋ค๊ณ ํฉ๋๋ค.
// before - Spring Security 5.X
implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5'
// after - Spring Security 6.X
implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity6'
๊ทธ๋ฆฌ๊ณ thymeleaf-extras-java8time
์ด๋ผ๋ ๋ณ๋์ ๋ชจ๋์ด ์ด์ thymeleaf ์ฝ์ด์ ์ถ๊ฐ๋จ์ผ๋ก์จ #temporals
๋ผ๋ ํํ์์ ๊ธฐ๋ณธ์ ์ผ๋ก ์ฌ์ฉํ ์ ์๋ค๊ณ ํฉ๋๋ค.
Spring 6๋ถํฐ JDK 17์ด ์ต์ ์๊ตฌ์ฌํญ์ผ๋ก ๋ณ๊ฒฝํจ์ ๋ฐ๋ผ ํ์๋ฆฌํ๋ 3.1 ์ดํ๋ถํฐ๋ JDK 17 ์ด์์ด ์๊ตฌ๋ฉ๋๋ค.
3.1๋ถํฐ๋ ๋ณด์์ ๋ ๊ฐํํ๊ธฐ ์ํ ์ด์ ๋ก ๋ ์ด์ web ๊ธฐ๋ฐ์ ์ ํธ ๊ฐ์ฒด๋ค์ ์ฌ์ฉํ ์ ์๋ค๊ณ ํฉ๋๋ค. ์ด์ ๋ ์ฌ์ฉํ๋ ค๋ ๊ฐ๋ค์ ์๋ ๋ง์ด๊ทธ๋ ์ด์
๊ฐ์ด๋์ ๊ฐ์ด ์ง์ @ModelAttribute
๋ฅผ ํตํด ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌํด์ผ ํฉ๋๋ค.
@ModelAttribute("contextPath")
public String contextPath(final HttpServletRequest request) {
return request.getContextPath();
}
ํํ์์์ ํด๋์ค ์ฌ์ฉ์ ๋ํด ๋ ์๊ฒฉํ๊ฒ ์ ํ์ ๋์๋ค๊ณ ํฉ๋๋ค. ์ด ํญ๋ชฉ์ ์ฌ์ค ์ค์ ๋ก ์ฌ์ฉํด ๋ณธ ์ ์ด ์์๋ ๊ฒ ๊ฐ์์ ์ ํํ ์ด๋ค ๋ด์ฉ์ธ์ง ํ์ ์ด ์ ๋ฉ๋๋ค.
๐ข ์ด ๋ถ๋ถ์ ์ถํ ์๊ฒ ๋๋ฉด ์ถ๊ฐํด ๋๊ฒ ์ต๋๋ค.
th:include
๊ฐ deprecated ๋์์ต๋๋ค. ๋์ th:insert
๋ฅผ ์ฌ์ฉํด์ผ ํฉ๋๋ค.
๊ทธ๋ฆฌ๊ณ fragment ๋ฌธ๋ฒ์ ์ฌ์ฉํ ๋ ~{}
๋ก ๊ฐ์ธ์ค์ผ ํฉ๋๋ค.
// code
<div id="main" th:include="~{::frag}">...</div>
...
<p th:fragment="frag" class="content">
something
</p>
// result
<div id="main">
something
</div>
// code
<div id="main" th:insert="~{::frag}">...</div>
...
<p th:fragment="frag" class="content">
something
</p>
// result
<div id="main">
<p class="content">
something
</p>
</div>
th:include
๋ฅผ ์ฌ์ฉํ๊ฒ ๋๋ฉด fragment ์์ ๋ด์ฉ๋ง ์ถ๊ฐ๋๋๋ฐ, th:insert
๋ฅผ ์ฌ์ฉํ๊ฒ ๋๋ฉด fragment์ ํ๊ทธ๊น์ง ์ ๋ถ ์ถ๊ฐ๋ฉ๋๋ค.
์ด์ ๋ th:insert
๋ฅผ ์ฌ์ฉํด์ผ ํ๋๋ฐ ๋ง์ฝ ํ๊ทธ ๋ด์ฉ๊น์ง ์ถ๊ฐ๋๋ ๊ฒ์ด ์ซ๋ค๋ฉด th:remove
์ ํจ๊ป ์ฌ์ฉํ๊ฑฐ๋ fragment์ ํ๊ทธ๋ฅผ th:block
์ผ๋ก ์ค์ ํ๋ฉด th:include
์ ๊ฐ์ ๊ฒฐ๊ณผ๋ฅผ ๋ผ ์ ์์ต๋๋ค.
// code
<div id="main" th:insert="~{::frag}">...</div>
...
<p th:fragment="frag" th:remove="tag" class="content">
something
</p>
// result
<div id="main">
something
</div>
// code
<div id="main" th:insert="~{::frag}">...</div>
...
<th:block th:fragment="frag">
something
</th:block>
// result
<div id="main">
something
</div>
๊ทธ๋ฆฌ๊ณ ์์์ ์ด๋ฏธ ์์ฑํ์ง๋ง fragment ๋ฌธ๋ฒ์ ์ฌ์ฉํ ๋ ~{}
๋ฅผ ์ฌ์ฉํด์ ๊ฐ์ธ์ค์ผ ํฉ๋๋ค.
// before
<div id="top" th:insert="common :: header">...</div>
// after
<div id="top" th:insert="~{common :: header}">...</div>