Thymeleaf

Thymeleaf 3.1 release note

Soono991 2023. 4. 16. 17:09

๐Ÿ’ก ์ด๋ฒˆ ํฌ์ŠคํŒ…์—์„œ๋Š” ํƒ€์ž„๋ฆฌํ”„ 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>