Backend/SpringBoot

응답으로 템플릿 리턴하기 (model, 타임리프, layout)

Dean83 2024. 10. 23. 14:40

보통 api 응답으로는 json 형식을 리턴하는것이 일반적이고 바람직한 방식이라고 생각한다. 그러나 가끔 html을 이용해야 할 때가 있다. (예 : 가입환영 이메일, 비밀번호 확인 이메일 등)

 

특정 API로 해당 요청을 받음 -> DB 에서 해당 내역 조회 -> 템플릿으로 DB 내용을 담아 전달 의 프로세스가 필요할 때가 있다. 참고로 오브젝트를 리턴하면 Json으로 변환하여 리턴하게 된다


템플릿을 이용하기 위해 보통 타임리프 라이브러리를 사용한다. 다음의 순서로 동작한다

 

***코틀린을 이용하여 VSCode 에서 구동시 ./gradlew bootrun 으로 실행해야 한다.

 

  • build.gradle 설치
  • resource 폴더 -> templates 폴더 -> html 파일 추가
  • Controller 클래스 함수에서 url 매핑
  • 매핑된 함수에서 Model 클래스를 이용하여 전달할 내용 담아주기
  • 매핑된 함수에서 추가한 html 파일을 응답으로 리턴

 

  • 설치
    • build.gradle 에 다음을 추가한다.
   implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
   implementation 'nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect'

 

  • 템플릿 추가
    • resource 폴더 -> templates 폴더에 원하는이름을 입력하여 html 파일을 추가한다.

  • 템플릿 상속 (Fragment)
    • 여러 템플릿 html 파일이 있을경우, 사실상  body를 제외하곤 중복되는 부분이 많다. HTML 기본구조가 같기 때문이다. 하나의 html에 중복되는 부분을 구현해 두고, 다른 템플릿에서는 이를 상속받아 body 부분만 변경 할 수 있다. 
    • resource 폴더 -> templates -> 부모가 될 html 을 추가한다.
    • body 부분에 <th:block layout:fragment="childcontent"></th:block> 을 작성한다.
      • 이 부분에 각 내용들이 삽입된다.
      • childcontent 는 다른 문자열로 대체해도 된다. 단, 자식 html에서도 이름이 같아야 한다.
    • 자식 템플릿 작성
      • html 태그에 layout:decorate="~{부모html이름(확장자제외)}" 를 추가
      • 부모 html에서 layout:fragment 설정한 부분이 될 태그의 어트리뷰트로 layout:fragment="childcontent" 를 입력
**부모 html
.....

<body>
	...
	<th:block layout:fragment="원하는명칭"></th:block>
    ...
</body>

**자식 html

<html layout:decorate="~{부모html이름(확장자제외)}">
	<태그명 layout:fragment="원하는명칭" >
		...
	</태그명>
</html>

 

  • 템플릿 치환 
    • 부모 템플릿을 상속 받는것과는 조금 다르게, 각 템플릿의 일부 태그를 타 템플릿의 내용으로 치환한다.
    • 위에서 눈치 챘겠지만, Fragment 를 선언하고, 필요한 곳에서 해당 Fragment를 가져다 쓰는 방식이다. 
    • Fragment 작성 및 치환 예
**프레그먼트 설정

...
<태그명 th:fragment="원하는 이름" >
...

**프레그먼트 대치하는 쪽

...
<태그명 th:replace="~{대치할html이름(확장자제외)::위의fragment에서_설정한_이름}" >
...



  • Model
    • 스프링에서 자동으로 생성자를 생성해주는 클래스로, 다양한 값들을 담을 수 있다. 
    • addAttribute("이름", 입력할 값) 함수를 이용해 값을 넣는다.
    • @ResponseBody 어노테이션을 삭제한다
    •  
    • import org.springframework.ui.Model 로 추가해야 한다.
      아래는 코틀린 예제이다.
package com.example.test1.test1

import org.springframework.ui.Model
import org.springframework.stereotype.Controller
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.ResponseBody

@Controller
public class test()
{
    @GetMapping("/서브url주소")
    fun Hello(model : Model) : String
    {
    	var a = 10
        //키값 명칭은 자유롭게 추가. html 에서 해당 명칭으로 값을 가져옴
        model.addAttribute("키값명칭",a)
        //templates 에 hello.html을 추가 했을경우 hello 리턴
        return "hello"
    }
}

 

  • HTML 에서 Model 에 넣은 인자값 사용
    • 어트리뷰트로 접근하여 사용 (텍스트인 경우)
      • th:text="${키값명칭}"
        또는 [[${키값명칭}]]
         
<h2 th:text="${test}"></h2>

//또는
<h2>[[${test}]]</h2>
  • 타임리프 분기문
    • th:if="${키값명칭 != null}"
<div th:if="${test != null}">
	<p th:text="${test}">
</div>
  • 타임리프 반복문
    • foreach를 생각하면 된다
    • th:each="item : ${키값명}"
<div th:each="item : ${test}">
	<p th:text="${item}">
</div>
  • 타임리프 반복문 2
    • loop 를 추가 하여 index, count 등 값을 추출 할 수 있다. 
      • loop.index
      • loop.count
      • loop.size
      • loop.current
      • loop.odd
      • loop.even 등등
    • th:each="item, loop : ${키값명}"
  • 타임리프 href
    • @{ } 사이에 주소값을 넣는다.
      • th:href=@"{/url주소/}"
    • 만일 변수값과 같이 조합을 할 경우에는 || 로 감싸줘야 한다
      • th:href=@"{|/url주소/${키값명}|}"