Tiny Bunny
๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐Ÿ’ป/SpringBoot

[Thymeleaf] Thymeleaf ์ดˆ๊ธฐ ์„ค์ • , ๋ทฐ ํ…œํ”Œ๋ฆฟ ์‚ฌ์šฉ

by soonybutter 2024. 12. 14.
728x90

 
 

 

ํƒ€์ž„ ๋ฆฌํ”„์˜ ํŠน์ง•์€ ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • *.html ํ™•์žฅ์ž๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
  • ๋ณ„๋„์˜ ๋ ˆ์ด์•„์›ƒ ํ”„๋ ˆ์ž„์›Œํฌ์˜ ๋„์›€ ์—†์ด ๋ ˆ์ด์•„์›ƒ์„ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์Šคํฌ๋ฆฝํŠธ๋ฆฟ์ด ์•„๋‹Œ HTML ๋ฌธ๋ฒ•์œผ๋กœ JAVA ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

์ƒ์‚ฐ์„ฑ ํ•˜๋‚˜์— ์—„์ฒญ๋‚˜๊ฒŒ ๊ณต์„ ๋“ค์ธ ๋Š๋‚Œ์ด ๋‚ฉ๋‹ˆ๋‹ค.
ํƒ€์ž„ ๋ฆฌํ”„์—์„œ๋Š” JSP์˜ ์Šคํฌ๋ฆฝํŠธ๋ฆฟ์€ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๊ณ , ๋Œ€์‹  ๊ฐ™์€ ๊ธฐ๋Šฅ์„ ํ•˜๋Š” ${}๊ณผ ๊ฐ™์€ ํ‘œํ˜„์‹์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
ํ•˜์ง€๋งŒ ์Šคํฌ๋ฆฝํŠธ๋ฆฟ๊ณผ๋Š” ๋‹ค๋ฅด๊ฒŒ HTML ์ฝ”๋“œ์˜ ์‹ฌ๋ฏธ์„ฑ์„ ํฌ๊ฒŒ ํ•ด์น˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
๊ฐ์„คํ•˜๊ณ , ๊ทธ๋Ÿผ ์ด thymeleaf๋ฅผ Spring Boot ํ”„๋กœ์ ํŠธ์—์„œ ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•˜๋Š”์ง€ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.
 
1. Thymeleaf prefix, suffix ์ •์˜
๋จผ์ €, Thymeleaf ํŒŒ์ผ์„ ์–ด๋””์„œ ๊ด€๋ฆฌํ•  ๊ฒƒ์ธ์ง€ application.properties์— ์ •์˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
์•„๋ž˜์˜ ๋‚ด์šฉ์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

# ์ •์  ๋ฆฌ์†Œ์Šค์— ๋ณ€ํ™”๊ฐ€ ์žˆ์„ ๋•Œ ๋ฐ”๋กœ ๋ฐ˜์˜ํ•œ๋‹ค.
spring.devtools.livereload.enabled=true


# thymeleaf ์ฐธ์กฐ ๊ฒฝ๋กœ
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html

# thymeleaf์— ๋Œ€ํ•œ ์บ์‹œ๋ฅผ ๋‚จ๊ธฐ์ง€ ์•Š๋Š”๋‹ค. cache=false ์„ค์ •(์šด์˜์‹œ๋Š” true)
spring.thymeleaf.cache=false
# templates ๋””๋ ‰ํ† ๋ฆฌ์— ํŒŒ์ผ์ด ์žˆ๋Š”์ง€ ์—†๋Š”์ง€ ์ฒดํฌ, ์—†์œผ๋ฉด ์—๋Ÿฌ๋ฅผ ๋ฐœ์ƒ์‹œํ‚จ๋‹ค.
spring.thymeleaf.check-template-location=true

 
์„ค์ •์„ ๋ณด๋ฉด ํด๋ž˜์Šค ํŒจ์Šค templates/๋ผ๊ณ  ์ •์˜ํ–ˆ๋Š”๋ฐ, ์ด์ œ๋ถ€ํ„ฐ๋Š” ์ด templates์—์„œ ํƒ€์ž„๋ฆฌํ”„๋ฅผ ๊ด€๋ฆฌํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.
๊ทธ๋ฆฌ๊ณ  suffix๋กœ๋Š” html ํ™•์žฅ์ž ์ง€์ •ํ•ด, ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ํƒ€์ž„๋ฆฌํ”„ ๋ทฐ๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ ํ™•์žฅ์ž๋ฅผ ๋ถ™์ด์ง€ ์•Š์•„๋„ ์ธ์‹ํ•˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.
๊ทธ ์™ธ์—๋Š” ๊ฐœ๋ฐœ ์‹œ์— ํ•„์š”ํ•œ ์ž์ž˜ํ•œ ์„ค์ •์ž…๋‹ˆ๋‹ค.
 
2. ๋ ˆ์ด์•„์›ƒ ์ •์˜

 

 

src/main/reslources์˜ templates ํŒจํ‚ค์ง€ ์•ˆ์— ๋ทฐ ํŒŒ์ผ์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
์ฐธ๊ณ ๋กœ ์•„๋ž˜ ์Šคํƒœํ‹ฑ ํด๋”์—๋Š” js, css๋“ฑ๊ณผ ๊ฐ™์ด ๋ณ€ํ•˜์ง€ ์•Š๋Š” ํŒŒ์ผ๋“ค์„ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
๋จผ์ € ๋‹ค๋ฅธ view๋“ค์ด ๊ณต์œ ํ•  ๋ ˆ์ด์•„์›ƒ์„ ์ •์˜ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.
 

 

 

templates ํŒจํ‚ค์ง€ ์•ˆ์— layout์ด๋ผ๋Š” ํŒจํ‚ค์ง€๋ฅผ ๋งŒ๋“ค๊ณ , ๊ทธ ์•ˆ์— default_layour.html์ด๋ผ๋Š” ํŒŒ์ผ์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
๊ทธ๋ฆฌ๊ณ  default_layout.html์˜ ๋‚ด์šฉ์„ ์ง€์šฐ๊ณ  ์•„๋ž˜์˜ ๋‚ด์šฉ์„ ์ž…๋ ฅํ•ฉ๋‹ˆ๋‹ค.
 

<html lang="ko"
	xmlns:th="http://www.thymeleaf.org"
    xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">

    <!--/* ์ด๊ณณ์— ๊ฐ view๊ฐ€ ์œ„์น˜ํ•ฉ๋‹ˆ๋‹ค. */-->    
    <th:block layout:fragment="head"></th:block>
    
    <div>
        <div layout:fragment="header"></div>
		
        <div layout:fragment="content"></div>

        <div layout:fragment="footer"></div>
    </div>
</html>

 
๋ ˆ์ด์•„์›ƒ์€ head, header, content, footer๋กœ ์ด๋ฃจ์–ด์ง€๋„๋ก ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.
head์—๋Š” title ํƒœ๊ทธ, css ๋“ฑ์„ ํฌํ•จํ•  ์˜ˆ์ •์ž…๋‹ˆ๋‹ค.
์—ฌ๊ธฐ์„œ html ํƒœ๊ทธ์— xmlns ์†์„ฑ์— ์ฃผ๋ชฉํ•ด์ฃผ์„ธ์š”.
xmlns์˜ ์ •์˜๊ฐ€ ์—†์œผ๋ฉด ํƒ€์ž„๋ฆฌํ”„ ๋ฌธ๋ฒ•์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์œผ๋‹ˆ ๋ฐ˜๋“œ์‹œ ๋„ฃ์–ด์ค๋‹ˆ๋‹ค.
 
์ด๊ฒƒ์œผ๋กœ ๋ ˆ์ด์•„์›ƒ ์ •์˜๋Š” ์™„๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
๊ธฐ์กด์˜ Spring์—์„œ์˜ tiles ํ”„๋ ˆ์ž„์›Œํฌ ๊ฐ™์€ ๋ณต์žกํ•œ ์ ˆ์ฐจ๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
์ด์ œ ๊ณตํ†ต์œผ๋กœ ์‚ฌ์šฉ๋  header์™€ footer ํŒŒ์ผ์„ ์ •์˜ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.
 
3. ๊ณตํ†ต ๋ ˆ์ด์•„์›ƒ ์š”์†Œ ์ •์˜
2๋ฒˆ์—์„œ ๋ ˆ์ด์•„์›ƒ์„ ์ •์˜ํ•  ๋•Œ header์™€ footer๋ฅผ ์‚ฝ์ž…ํ•˜๋Š” ๊ตฌ๋ฌธ์ด ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.
๋ณธ ์˜ˆ์ œ์—์„œ๋Š” header์™€ footer ํŒŒ์ผ์„ templates์˜ fragmants ํŒจํ‚ค์ง€์—์„œ ๊ด€๋ฆฌํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.
 

 

 
templates ํŒจํ‚ค์ง€์— fragments ํŒจํ‚ค์ง€๋ฅผ ์ƒ์„ฑํ•˜๊ณ  header.html, footer.html ํŒŒ์ผ ์ƒ์„ฑ ํ›„ ์•„๋ž˜์˜ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.

# header.html

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
    <div class="header">
        <h2>Header</h2>
    </div>
</html>

 

# footer.html

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
    <div class="footer">
        <h2>Footer</h2>
    </div>
</html>

 
 

4. content ์ž‘์„ฑ
 

 
templates์— content๋ผ๋Š” ํŒจํ‚ค์ง€๋ฅผ ๋งŒ๋“ค๊ณ  ๊ทธ ์•ˆ์— home.html ํŒŒ์ผ์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
๊ทธ๋ฆฌ๊ณ  ์•„๋ž˜์˜ ๋‚ด์šฉ์„ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.
 

# home.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org"
      xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
      layout:decorate="~{layout/default_layout}">
    
    <th:block layout:fragment="head">
    	<title>Spring Boot</title>
		
        <!--/* css */-->
        <link th:href="@{/css/common.css}" rel="stylesheet" />
    </th:block>
    <body>
        <th:block layout:fragment="header" th:include="@{/fragments/header}"></th:block>
		
        <div layout:fragment="content" class="content">
            <h2>This is Content</h2>
        </div>
        
        <th:block layout:fragment="footer" th:include="@{/fragments/footer}"></th:block>	
    </body>
</html>

 
์œ„ ์ฝ”๋“œ์—์„œ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ๋ถ€๋ถ„์€ html ํƒœ๊ทธ์˜ layout:decorate ์š”์†Œ์ž…๋‹ˆ๋‹ค.
๋ ˆ์ด์•„์›ƒ ์†Œ์Šค์ฝ”๋“œ๋ฅผ ์–ด๋–ค ๊ฒƒ์œผ๋กœ ์ง€์ •ํ•  ๊ฒƒ์ธ์ง€๋ฅผ ์ •์˜ํ•˜๋Š” ์š”์†Œ๋กœ, ๋ณธ ์˜ˆ์ œ์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๋ ˆ์ด์•„์›ƒ ํŒŒ์ผ์€ layout ํด๋”์˜ defaout_layout ํŒŒ์ผ์ด๋ฏ€๋กœ layout/default_layout์ด๋ผ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค.
 
๋ ˆ์ด์•„์›ƒ์—์„œ ์ •์˜ํ•œ head, header, content, footer์— ๋Œ€ํ•œ ์ •์˜๋ฅผ <th:block layout:fragment="์š”์†Œ ๋ช…"></th:block> ํ˜•ํƒœ๋กœ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.
 
header์™€ footer๋Š” fragments์—์„œ ์ •์˜ํ•œ ํŒŒ์ผ๋“ค์„ inlcude ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
 
์ด์ œ ์ปจํŠธ๋กค๋Ÿฌ์—์„œ home.html๋ฅผ ์š”์ฒญํ•˜๋ฉด default_layout.html์—์„œ ์ •์˜ํ•œ ํ˜•ํƒœ๋กœ view๊ฐ€ ๋ Œ๋”๋ง๋˜์–ด ๋ธŒ๋ผ์šฐ์ €์— ์ถœ๋ ฅ๋ฉ๋‹ˆ๋‹ค.
๊ทธ์ „์—, ์˜ˆ์ œ์—์„œ ์ •์˜ํ•œ ๊ฐ ๋ ˆ์ด์•„์›ƒ ์š”์†Œ๋“ค์„ ๊ตฌ๋ณ„ํ•˜๊ธฐ ์‰ฝ๊ฒŒ ๊ฐ„๋‹จํ•œ css ํŒŒ์ผ์„ ์ถ”๊ฐ€ํ•˜๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.
 
 

 
static ํด๋”์— css ํด๋”๋ฅผ ์ƒ์„ฑํ•˜๊ณ  common.css๋ผ๋Š” ์ด๋ฆ„์˜ ํŒŒ์ผ์„ ์ƒ์„ฑํ•˜๊ณ  ์•„๋ž˜์˜ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.
 

body, html {
    height: 100%;
}

.header {
    background-color: Gray;
    height: 20%
}

.content {
    height:60%;
}

.footer {
    background-color: yellow;
    height: 20%
}

 
5. Controller ์ˆ˜์ •
์ด์ „ ํฌ์ŠคํŒ…์—์„œ ์ž‘์„ฑํ•œ HomeController์˜ ๋‚ด์šฉ์„ ์•„๋ž˜์™€ ๊ฐ™์ด ์ˆ˜์ •ํ•ฉ๋‹ˆ๋‹ค.
 

// HomeController.java

@Controller
public class HomeController {
	@RequestMapping(value = "/home", method=RequestMethod.GET)
	public String goHome(HttpServletRequest request) {
		return "content/home";
	}
}

 
ํŽ˜์ด์ง€๋ฅผ ํ‘œ์‹œํ•  ๊ฒƒ์ด๋ฏ€๋กœ ์ด์ „ ํฌ์ŠคํŒ…์—์„œ ์ž‘์„ฑ๋˜์–ด์žˆ๋˜ @ResponseBody ์–ด๋…ธํ…Œ์ด์…˜์„ ์ œ๊ฑฐํ•ด์ฃผ๊ณ  goHome ๋ฉ”์„œ๋“œ์—์„œ return ๊ฐ’์œผ๋กœ "content/home"์„ ์ง€์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.
์ด๋Š” application.properties์—์„œ ํ”„๋ฆฌํ”ฝ์Šค๋กœ ์ง€์ •ํ•œ ํด๋ž˜์Šค ํŒจ์Šค templates์•ˆ์˜ content ์•ˆ์— home.html์„ ๋ฐ˜ํ™˜ํ•˜๊ฒ ๋‹ค๋Š” ์˜๋ฏธ์ž…๋‹ˆ๋‹ค.
 
์ด์ œ localhost:8080/home์œผ๋กœ ์ ‘์†ํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ ํ™”๋ฉด์„ ์ถœ๋ ฅํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
 

 
 
 
6. Controller์—์„œ ๊ฐ’์„ ๋ฐ›์•„ Thymeleaf์— ํŒŒ์‹ฑ ํ•˜๊ธฐ
๋ณธ ํฌ์ŠคํŒ…์—์„œ๋Š” thymeleaf์˜ ๋ชจ๋“  ํ‘œํ˜„์‹์„ ๋‹ค ๋‹ค๋ฃจ์ง€๋Š” ๋ชปํ•˜๊ณ , ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ๋ณด๋‚ด์˜ค๋Š” list ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ˜๋ณต๋ฌธ์„ ์‚ฌ์šฉํ•ด์„œ ํŽ˜์ด์ง€์— ํŒŒ์‹ฑ ํ•ด์ฃผ๋Š” ์ž‘์—…๊นŒ์ง€ ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.
๋จผ์ €, ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ์ˆ˜์ •ํ•ด์„œ ๊ฐ„๋‹จํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์ค€๋น„ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.
 

//HomeController.java

@Controller
public class HomeController {
	@RequestMapping(value = "/home", method=RequestMethod.GET)
	public ModelAndView goHome(HttpServletRequest request) {
		ModelAndView mav = new ModelAndView();
		List<String> resultList = new ArrayList<String>();
		
		resultList.add("AAA");
		resultList.add("BBB");
		resultList.add("CCC");
		resultList.add("DDD");
		resultList.add("EEE");
		resultList.add("FFF");
		
		mav.addObject("resultList",resultList);
		mav.setViewName("content/home");
		
		return mav;
	}
}

 
๋ฐ์ดํ„ฐ์™€ ๋ทฐ ์ •๋ณด๋ฅผ ๊ฐ™์ด ๋ฐ˜ํ™˜ํ•ด์ฃผ์–ด์•ผ ํ•˜๋ฏ€๋กœ ๊ธฐ์กด์˜ goHome ๋ฉ”์„œ๋“œ์˜ ๋ฐ˜ํ™˜ํ˜•์„ String์—์„œ ModelAndView๋กœ ๋ฐ”๊ฟ”์ค๋‹ˆ๋‹ค.
๊ทธ๋ฆฌ๊ณ  List <String> ํƒ€์ž…์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณต์ˆ˜๊ฐœ ์ถ”๊ฐ€ํ•ด์ฃผ๊ณ  ModelAndView ๊ฐ์ฒด์— ๋‹ด์•„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
 
์ด์ œ home.html ํŒŒ์ผ์„ ์—ด๊ณ  ์•„๋ž˜์™€ ๊ฐ™์ด ์ˆ˜์ •ํ•ด์ค๋‹ˆ๋‹ค.
 

# home.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org"
      xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
      layout:decorate="~{layout/default_layout}">
    
    <th:block layout:fragment="head">
    	<title>Spring Boot</title>
		
        <!--/* ์ด ์˜์—ญ์— ๊ณตํ†ต์œผ๋กœ ์‚ฌ์šฉํ•  css, js library๋ฅผ ์„ ์–ธํ•œ๋‹ค. */-->
        <link th:href="@{/css/common.css}" rel="stylesheet" />
    </th:block>
    <body>
        <th:block layout:fragment="header" th:include="@{/fragments/header}"></th:block>
		
        <div layout:fragment="content" class="content">
            <h2>This is Content</h2>
            <hr>
            <!-- ์•„๋ž˜์˜ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ ํ•ฉ๋‹ˆ๋‹ค.-->
            <table border="1">
                <tr>
                    <th>TEXT</th>
                </tr>
                <th:block th:each="rl : ${resultList}">
                    <tr>
                        <td th:text="${ rl }"></td>
                    </tr>
                </th:block>
            </table>
            
        </div>
        <th:block layout:fragment="footer" th:include="@{/fragments/footer}"></th:block>	
    </body>
</html>

 
ํƒ€์ž„๋ฆฌํ”„์—์„œ๋Š” th:each๋ฅผ ์ด์šฉํ•ด ๋ฐ˜๋ณต ๊ฐ€๋Šฅํ•œ ๋ณ€์ˆ˜๋ฅผ ์ˆœํšŒํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. JSTL์—์„œ์˜ c:foreach์™€ ๋™์ผํ•œ ์—ญํ• ์„ ํ•˜์ง€๋งŒ, ํƒ€์ž„๋ฆฌํ”„์—์„œ๋Š” ๋ฐ˜๋ณต๋ฌธ์„ html ํƒœ๊ทธ์— ์ง์ ‘ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ํŠน์ง•์ด ์žˆ์Šต๋‹ˆ๋‹ค.
 
์ด์ œ localhost:8080/home์œผ๋กœ ์ ‘์†ํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ์ œ๋Œ€๋กœ ๋ฐ›์•„์˜ค๊ณ  ์žˆ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
 
 

 
์ปจํŠธ๋กค๋Ÿฌ์—์„œ ๋ฐ›์•„์˜จ ๋ฐ์ดํ„ฐ๋ฅผ ์ •์ƒ์ ์œผ๋กœ ์ถœ๋ ฅํ•ด ์ฃผ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

 
 
 

728x90

TOP

Designed by ํ‹ฐ์Šคํ† ๋ฆฌ