[Thymeleaf] 기초

2025. 4. 18. 18:04·Web

타임리프.properties

#Thymeleaf 환경설정 : .jsp .html .htm => Spring-boot
#JSTL => Thymeleaf

#템플렛 캐쉬를 비활성화 함 : 소스 수정시 새로고침을 자동으로 하게 해서 변경된 소스가 반영됨 
spring.thymeleaf.cache=false

#템플렛 View를 이용하여 resource에 디렉토리를 활성화함 
spring.thymeleaf.check-template-location=true

#Thymeleaf 기본적으로 사용함 
spring.thymeleaf.enabled=true

#src/main/resources => templates 디렉토리를 활성화함 
spring.thymeleaf.prefix=classpath:/templates/

#View 파일 속성명 (html과 jsp 속성 파일을 함께 사용시 상위 속성을 입력해야함)
#jsp가 html보다 상위라서 아랫줄에 html쓰면 jsp사용 불가능 html보다 하위인 애들만 쓸 수 있게 됨 
spring.thymeleaf.suffix=.jsp

#View 파일을 Controller에서 로드할 수 있도록 함 
spring.thymeleaf.mode=html

#view-names : Thymeleaf와 JSTL, JSP를 구분하여 사용하겠다는 뜻
spring.thymeleaf.view-names=/*
#윗 줄 세팅안하면 기존의
#spring.mvc.view.prefix=/
#spring.mvc.view.suffix=.jsp
#이것들과 충돌이 날 수 있음 

#spring.thymeleaf.view-names=WEB-INF/views/*
#이렇게 안해도 되는 이유
#spring.thymeleaf.prefix=classpath:/templates/
#이 줄로 이미 보안을 걸었음

 

all_DTO.java

package kr.co.koo.thymeleaf;

import java.util.ArrayList;

import org.springframework.stereotype.Repository;

import lombok.Data;

//Database와 관계없이 AOP와 Controller에서 서로 상호작용을 하기 위한 DTO
@Data
@Repository("all_DTO")
public class all_DTO {
	ArrayList<String> menus;

}

 

index.html (템플릿)

<!DOCTYPE html>
<html lang="ko" xmlns:th="https://www.thymeleaf.org">
<head th:fragment="title">
<meta charset="UTF-8">
<meta http-equiv="X-UA-compatible" content="IE=Edge,chrome=1">
<meta name="viewport" content="width=device, initial-scale=1.0">
<title>쿠팡 쇼핑몰 리뉴얼</title>


<link
	href="https://fonts.googleapis.com/css2?family=Nanum+Pen+Script&display=swap"
	rel="stylesheet">
<!--Regular 400-->
<link
	href="https://fonts.googleapis.com/css2?family=Nanum+Gothic:wght@400;700&family=Noto+Sans+KR:wght@100;300;400;900&display=swap"
	rel="stylesheet">
<link rel="stylesheet" type="text/css" href="./index.css?v=7">
<link rel="stylesheet" type="text/css" href="./top.css?v=6">
<link rel="stylesheet" type="text/css" href="./menu.css?v=6">
<link rel="stylesheet" type="text/css" href="./banner.css?v=3">
<link rel="stylesheet" type="text/css" href="./product.css?v=4">
<link rel="stylesheet" type="text/css" href="./bottom.css?v=2">
<script src="./js/jq.js"></script>
</head>
<body>
	<!--이벤트 배너-->
	<header class="header_css" th:fragment="top">
		<script>
        $(document).ready(function(){
            $("#close").click(function(){
                $("#top1").slideUp(1000);
            });

            $("#f").submit(function(){
                    var $search = $("#search").val();
           
           if($search==""){
            alert("검색할 상품명을 입력해 주시길 바랍니다.");
            return false;
           }
           else{
                $("#f").submit();
           }   
        });
        
        $("#menu_cate>li").eq(0).click(function(){
             $("#menu_cate>li:eq(0)>ol").slideDown();
        });

        $("#banner_outline").mouseover(function(){
            $("#banner_outline > span").stop().fadeIn();
        });

        $("#banner_outline").mouseout(function(){
            $("#banner_outline > span").stop().fadeOut();
        });

        });
    </script>
		<div class="event_top">
			<!--이벤트 배너-->
			<label class="top1" id="top1">
				<ul class="top_banner">
					<li><img src="./image/topbanner1.jpg"></li>
					<li><img src="./image/topbanner2.jpg"></li>
					<li><span class="close" id="close">X</span></li>
				</ul>
			</label>
			<!--탑 메뉴 : 즐겨찾기~고객센터-->
			<label class="top2">
				<ul class="ul_left">
					<li>즐겨찾기</li>
					<li>입장신청▼</li>
				</ul>
				<ul class="ul_right">
					<li onclick="location.href='./shop_login.do';">로그인</li>
					<li onclick="location.href='./shop_join.do';">회원가입</li>
					<li onclick="location.href='./shop_custom.do';">고객센터</li>
				</ul>
			</label>
		</div>
	</header>
	<!--로그 & 메뉴-->
	<!-- menulist 매개변수값은 main.html, login.html에서 Controller가 적용한 값을 가져오는 방식 -->
	<nav class="nav_css" th:fragment="menu(menulist)">
		<div class="menu_div">
			<label class="menu_logo"> <img src="./image/logo.png">
			</label>
			<!--
			폼 빼고 main.html에서 장착해야함  
			<form id="f" method="GET" action="https://coupang.com/np/search">
			 -->
				<label class="menu_search"> <input type="text" name="q"
					id="search" placeholder="검색할 상품명을 입력해 주시길 바랍니다"> <input
					type="submit" value="상품검색">
				</label>
<!-- 
			</form>
 -->
			<label class="menu_part">
				<ul id="menu_cate" >
				<!-- thymeleaf의 반복문은 each 문법으로 데이터값을 해당 태그에 맞춰서 반복출력 -->
				<li th:each="mu : ${menulist}" th:text=${mu}></li>
					
				</ul>
			</label>
		</div>
	</nav>
	<!--배너-->
	<section class="banner_css" th:fragment="banner">
		<div class="banner_outline" id="banner_outline">
			<ul class="banner_view">
				<li><img src="./banner/banner.png"></li>
				<li><img src="./banner/banner.png"></li>
			</ul>
			<span class="leftcss"><img src="./banner/leftbtn.png"></span> <span
				class="rightcss"><img src="./banner/rightbtn.png"></span> <label
				class="disc">
				<ul>
					<li></li>
					<li></li>
					<li></li>
					<li></li>
				</ul>
			</label>
		</div>
	</section>
	<!--상품출력-->
	<article class="article_css" th:fragment="product">
		<div class="product">
			<p class="product_title">BEST PRODUCT</p>
			<ul class="product_ul">
				<li>
					<div class="product_view">
						<span><img src="./product/bestproduct1.png"></span> <span>베트남
							쌀국수 3종 세트</span> <span><font color="red">균일가</font> 5,500원</span>
					</div>
				</li>
				<li>
					<div class="product_view">
						<span><img src="./product/bestproduct2.png"></span> <span>순수
							PURE 30EA 50% 세일</span> <span><font color="red">균일가</font>
							12,000원</span>
					</div>
				</li>
				<li>
					<div class="product_view">
						<span><img src="./product/bestproduct3.png"></span> <span>정관장
							활기력 20EA 1BOX</span> <span><font color="red">균일가</font> 38,000원</span> <label
							class="coupon"><img src="./product/coupon.png"></label>
					</div>
				</li>
				<li>
					<div class="product_view">
						<span><img src="./product/bestproduct4.png"></span> <span>일렉트로닉
							무선 청소기 15% 할인</span> <span><font color="red">균일가</font> 370,000원</span>
						<label class="coupon"><img src="./product/coupon.png"></label>
					</div>
				</li>
			</ul>
			<p class="product_title">NEW PRODUCT</p>
			<ol>

			</ol>
		</div>
	</article>
	<!--카피라이터-->
	<footer class="footer_css" th:fragment="footer">
		<div class="copyright">
			<span class="cp1">
				<ul>
					<li>회사소개</li>
					<li>인재채용</li>
					<li>입점/제휴문의</li>
					<li>공지사항</li>
					<li>고객의소리</li>
					<li>이용약관</li>
					<li>개인정보처리방침</li>
					<li>제휴마케팅</li>
					<li>광고안내</li>
					<li>신뢰관리센터</li>
				</ul>
			</span> <span class="cp2"> <label>Copyright ⓒ Coupang Corp.
					2024-2025 All Rights Reserved.</label>
			</span>
		</div>
	</footer>
</body>
</html>

 

main.html (템플릿 사용)

<!DOCTYPE html>
<!-- Thymeleaf는 무조건 마크업 기준으로 fragment를 설정하여 가져옴 -->
<html lang="ko" xmlns:th="https://www.thymeleaf.org">
<head th:replace="~{/index.html :: title}"></head>
<body>
<header th:replace="~{/index.html :: top}"></header>

<form id="frm" method="get" action="./search_shop.do" onsubmit="return checks()">
<!-- ${menulist} : Controller에서 Model로 보낸 값을 받아서 index.html에 매개변수 값을 전송  -->
<nav th:replace="~{/index.html :: menu(${menulist})}"></nav>
</form>
<section th:replace="~{/index.html :: banner}"></section>
<article th:replace="~{/index.html :: product}"></article>
<footer th:replace="~{/index.html :: footer}"></footer>
</body>
<script>
function checks(){
	if(frm.q.value==""){
		alert("검색어를 입력하세요");
		return false;
	}else{
		frm.submit();
	}
}
</script>
</html>

 

login.html (템플릿 사용)

<!DOCTYPE html>
<!-- Thymeleaf는 무조건 마크업 기준으로 fragment를 설정하여 가져옴 -->
<html lang="ko" xmlns:th="https://www.thymeleaf.org">
<head th:replace="~{/index.html :: title}"></head>
<link rel="stylesheet" type="text/css" href="./login.css">
<body>
	<header th:replace="~{/index.html :: top}"></header>

	<form id="frm" method="get" action="./search_shop.do"
		onsubmit="return checks()">
		<nav th:replace="~{/index.html :: menu(${menulist})}"></nav>
	</form>

	<main>
		<div class="loginview">
			<span class="member_l">MEMBER LOGIN</span> <span class="login">
				<input type="hidden" name="nomember_security" value="">
				<table border="0" cellpadding="0" cellspacing="0"
					class="table_login">
					<tr>
						<td><input type="text" placeholder="아이디를 입력해주세요" class="id"
							name="shop_id"></td>
						<td rowspan="2"><input type="submit" value="LOGIN"
							class="btn1"></td>
					</tr>
					<tr>
						<td><input type="password" placeholder="패스워드를 입력해주세요"
							class="id" name="shop_pw"></td>
					</tr>
				</table>
				<div class="check1">
					<input type="checkbox" name="shop_idsave" id="l" value="Y">
					<label for="l" class="label_login">아이디 저장</label>
				</div>
				<ul class="btns_login">
					<li><input type="button" value="회원가입" class="a"
						onclick="gopage(3)"></li>
					<li><input type="button" value="아이디 찾기" class="a"
						onclick="alert('서비스 준비중 입니다.');"></li>
					<li><input type="button" value="비밀번호 찾기" class="a1"
						onclick="alert('서비스 준비중 입니다.');"></li>
				</ul> <input type="hidden" name="nomember_security" value="noinfo">
				<span class="clear">비회원 주문조회</span> <span class="search_login">
					<table border="0" cellpadding="0" cellspacing="0"
						class="table_login">
						<tr>
							<td><input type="text" placeholder="주문자명을 입력해주세요" class="id"
								name="nomember_id" tabindex="1"></td>
							<td rowspan="2"><input type="submit" value="주문조회"
								class="btn1"></td>
						</tr>
						<tr>
							<td><input type="text" placeholder="주문번호를 8자리 입력해 주세요"
								class="id" name="nomember_no" maxlength="8" tabindex="2">
							</td>
						</tr>
					</table> <label class="check1"> 주문자명과 주문번호를 잊으신 경우, 고객센터로 문의하여 주시기
						바랍니다. </label>
			</span>
			</span>
		</div>
	</main>

	<footer th:replace="~{/index.html :: footer}"></footer>
</body>
<script>
function checks(){
	if(frm.q.value==""){
		alert("검색어를 입력하세요");
		return false;
	}else{
		frm.submit();
	}
}
</script>
</html>

 

컨트롤러.java

package kr.co.koo.thymeleaf;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

import jakarta.annotation.Resource;

//Thymeleaf + spring-boot => Model 갱장희 중요 (extends, implement, AOP)
@Controller
public class thymeleaf_controller {
	
	Logger log = LoggerFactory.getLogger(this.getClass());
	
	//AOP와 공용으로 사용하는 DTO
	@Resource(name="all_DTO")
	all_DTO all_inject;
	
	/*
	return null : webapp에서 찾음
	return "파일명" : webapp에서 파일명.jsp 찾음
	return "/파일명" : templates에서 파일명.jsp 찾음 
	return "/파일명.html" : templates에서 파일명.html 찾음
	
	WEB-INF의 파일을 불러오고싶다면 
	return "/WEB-INF/views/파일명"	이게 아니라  
	return "WEB-INF/views/파일명"		이렇게 써야함  
	*/
	
	//Thymeleaf View에 Model로 생성 후 .html에 값을 전달 
	@GetMapping("sample.do")
	public String sample(Model m) {
		String product = "냉장고";
		m.addAttribute("product",product);
		
		
		return "/sample.html";
		//Thymeleaf안의 jsp는 <% %>이게 안먹어서 코드가 페이지에 노출됨 
		//파일명만 jsp인거지 기존 jsp처럼 핸들링 불가능 
		
		/*
		"sample" : /sample.jsp 를 찾음
		"/sample" : 500 error (템플렛 안에 jsp있을 경우 출력)
		"sample.html" : sample.html.jsp를 찾음 
		"/sample.html" : 템플렛 안에 html있을 경우 출력
		왜? 프로퍼티스에 그렇게 설정했음
		*/
	}
	
	@GetMapping("sample2.do")
	public String sample2(Model m) {
		String menu = "관리자 등록";
		String copy = "Copyright 2025 WEB By Design...";
		
		m.addAttribute("menu",menu);
		m.addAttribute("copy",copy);
		return "/subpage.html";
	}
	
	//작업용파일
	/*
	@GetMapping("indextest.do")
	public String indextest(Model m) {
		
		return "/index.html";
	}
	*/
	
	
	@GetMapping("shop.do")
	public String shop(Model m) {	//실제 메인페이지 
		m.addAttribute("menulist",this.all_inject.getMenus());
		return "/main.html";
	}
	
	@GetMapping("shop_login.do")
	public String shop_login(Model m) {
		//해당 객체명으로 DTO에 있는 배열값을 타임리프를 이용해 html로 이관
		m.addAttribute("menulist",this.all_inject.getMenus());
		
		return "/login.html";
	}

}

 

aop.java

package kr.co.koo.thymeleaf;

import java.util.ArrayList;
import java.util.Arrays;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
import org.springframework.ui.Model;

import jakarta.annotation.Resource;

@Aspect
@Component
public class thymeleaf_aop {
   
   @Resource(name="all_DTO")
   all_DTO all_inject;
   
   //thymeleaf_controller 해당 class에 있는 모든 메소드에 Controller 실행 전 해당 AOP가 먼저 작동
   @Before("execution(* kr.co.koo.thymeleaf.thymeleaf_controller.*(..)) && args(model,..)")
   public void top_menu(Model model) {
       String menus[] = {"카테고리", "로켓배송", "로켓프레시", "2025추석", "로켓직구", "골드박스", "정기배송", "이벤트/쿠폰", "기획전", "여행/티켓"};
       ArrayList<String> allmenu = new ArrayList<>(Arrays.asList(menus));
       this.all_inject.setMenus(allmenu);
   }
   
}

 

저작자표시 비영리 변경금지 (새창열림)
'Web' 카테고리의 다른 글
  • [Thymeleaf] 기초 2
  • [이니시스 API]
  • [Spring-boot] 메이븐 프로젝트 세팅
  • [Thymeleaf] 세팅
9na0
9na0
응애
  • 9na0
    구나딩
    9na0
  • 전체
    오늘
    어제
    • 분류 전체보기 (211)
      • Web (118)
      • Java (28)
      • 데이터베이스 (14)
      • 세팅 (12)
      • 과제 (3)
      • 쪽지시험 (2)
      • 정보처리기사 (4)
      • 서버 (25)
  • 블로그 메뉴

    • 링크

      • 포폴
      • 구깃
    • 공지사항

    • 인기 글

    • 태그

      file24
      java_io1~10
      noticewriteok
      re2
      notice_writer
      io_dto
      net1
      net2
      Oracle
      re_java10
      file25
      net5~10
      exam1_1~10
      macbook pro m4
      datalist
      net4
      spring-boot
      net3
      ab1
      file25_t
    • 최근 댓글

    • 최근 글

    • hELLO· Designed By정상우.v4.10.3
    9na0
    [Thymeleaf] 기초
    상단으로

    티스토리툴바