Thymeleaf

[Thymeleaf] 변수 표현식이 뭔데요

Empty Brain 2022. 12. 14. 16:24

나다.

 

이번 글 에서는 타임리프에서 변수를 사용하는 방법을 알아보자.

 

변수라 함은 동적페이지를 구성하는데 있어 필수적으로 사용되어야 할 요소이다.

X발

위의 사진을 보라.

지금 두 개의 결과는 같지만 나중에 누군가 와서

"삼각형이 너무 개X만 하네? 크기 좀 키워줘"

 

라고 한다면 왼쪽의 코드는 그냥 i,j라는 변수만 몇개 찌끄리면 되지만

오른쪽의 코드는 하루종일 " * * * * *\n" 이 지X을 n번을 하고 있어야 하는 것이다. 퇴근도 못하고.

 

웹페이지를 구성 할 때도 똑같다.

 

나중에 쓸 Thyemleaf layout에서도 말하겠지만 그때 그때 변해야 하는 값들에 대해 변수를 사용해야 하는 것이 위와 같은 이유다.

물론 위의 예에서 나온 변수와 지금 설명할 변수는 조금 다른 개념이기는 하지만

 

언제 존X 많은 페이지들 속에서 같은거 찾아서 바꾸고 있을건가.

(물론 당신이 시간 빌게이츠라면 괜찮음. 저는 시간 빌게이츠임 ㅋㅋ)

 

먼저, 타임리프에서 사용하는 SpringEL에 대해서 알아볼거다.

 

타임리프의 변수표현식은 ${...} 을 사용한다.

 

그리고 이 ${...} 안에 SpringEL이 들어간다.

 

우리는 지금부터 이 변수표현식을 통해 서버에서 넘기는 값들을 HTML로 꽂아넣어 랜더링 할 것이다.

 

그 과정에서 다양한 변수표현식의 사용법에 대해 설명하겠다.

 

먼저 Attribute(Object)가 넘어왔을 때 어떤 방식으로 변수표현식을 통해 뽑아다 쓰는지 알아보자.

import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
public class TestValue {

    private String testName;
    private String testVal;
    
}
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;


@Slf4j
@Controller
public class TestController {

    @GetMapping("/test/page")
    public String testPage(Model model){
        
        TestValue name1 = new TestValue("name1", "안녕?");

        model.addAttribute("testValue", name1);

        return "test-page";
    }
}

testValue 하나를 간단하게 생성해 넘겼다.

 

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h2>Test</h2>
    <ul>
        <li><span th:text="${testValue.testName}"></span></li>
        <li><span th:text="${testValue['testName']}"></span></li>
        <li><span th:text="${testValue.getTestName()}"></span></li>
        // 이거 세개 다 똑같은거임.
    </ul>
</body>
</html>

우리는 컨트롤러에서 "testValue" 라는 이름의 Attribute에 name1이라는 TestValue 객체를 담아서 보냈다.

 

현재 name1 이라는 객체 안에는 우리가 임의로 생성한 testName = "name1" 과 testVal = "안녕?" 이라는 정보가 존재한다.

 

이는 우리가 보낸 Attribute인 "testValue" 안에도 똑같이 위의 값들이 존재한다는 뜻이다.

 

그렇기때문에 "testValue" 에서 testName을 꺼내더라도 똑같은 "name1"이 빠져나온다는 것이다.

 

Java의 Getter & Setter에 대해 알고있는가?

(모르면 구글에 검색하셈.)

 

${testValue.testName} == name1.getTestName(); 과 똑같은 동작을 한다는 뜻이기도 하다.

 

잘 됨 ㅇㅇ

 

다음으로 간단히 특정 정보가 모인 Attribute(List)를 넘겨받을 때를 알아보자.

import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
public class TestValue {

    private String testName;
    private String testVal;
    
}
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

import java.util.ArrayList;
import java.util.List;

@Slf4j
@Controller
public class TestController {

    @GetMapping("/test/page")
    public String testPage(Model model){
        List<TestValue> list = new ArrayList<>();
        TestValue name1 = new TestValue("name1", "안녕?");
        TestValue name2 = new TestValue("name2", "ㅋㅋ ㅎㅇ");

        list.add(name1);
        list.add(name2);

        model.addAttribute("testList", list);

        return "test-page";
    }
}

먼저 간단한 TestValue를 생성하고 그 안에 각 값을 집어넣은 후 List에 test-page로 전송했다.

 

현재 List안에 존재하는 것은 {name1, 안녕?}, {name2, ㅋㅋ ㅎㅇ} 두 개다.

 

이걸 test-page 안에서 변수표현식을 사용해 꺼내보자.

 

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h2>Test</h2>
    <ul>
        <li><span th:text="${testList[0].testName}"></span></li>
        <li><span th:text="${testList[0].testVal}"></span></li>
        <li><span th:text="${testList[1].testName}"></span></li>
        <li><span th:text="${testList[1].testVal}"></span></li>
        
        <li><span th:text="${testList[0]['testName']}"></span></li>
        <li><span th:text="${testList[0]['testVal']}"></span></li>
        
        <li><span th:text="${testList[0].getTestName()}"></span></li>
        <li><span th:text="${testList[0].getTestVal()}"></span></li>
        
        //이거 세개 다 같은거임
    </ul>
</body>
</html>

 

testList[0] 을 보니 Java의 그 무언가가 생각나지 않는가?

맞다. list.get(n) 의 역할을 똑같이 수행하는 문법이다.

 

지금 리스트 안에는 2개의 정보가 존재한다.

       list.add(name1);
       list.add(name2);

2개의 정보 name1 과 name2를 넣었으니 말이다.

 

그렇다는 것은 현재 testList의 0번째 인덱스는 name1 이 된다는 뜻이다.

(List의 인덱스는 0번째 부터 시작이다.)

 

${testList[0].testName} 을 풀어서 설명하자면

1. testList의 0번째 Index의 정보를 뽑아내고

2. 그 정보안에 testName이라는 새X가 있으면

 

testList[0].testName 의 "." 을 "다음"으로 생각하는 것도 이해하는데 나쁘지 않을 듯 싶다.

testList의 0번째 인덱스를 가져온 "다음" 안에서 testName을 찾아서 가져온다.

 

존X 잘 나온다.

 

 

마지막으로 Attribute(Map)에서 사용하는 방법을 알아보자.

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

import java.util.HashMap;
import java.util.Map;


@Slf4j
@Controller
public class TestController {

    @GetMapping("/test/page")
    public String testPage(Model model){

        Map<String, TestValue> map = new HashMap<>();

        TestValue name1 = new TestValue("name1", "안녕?");
        TestValue name2 = new TestValue("name2", "ㅎㅇ ㅋㅋ");

        map.put("1번임", name1);
        map.put("2번임", name2);

        model.addAttribute("testMap", map);

        return "test-page";
    }
}

먼저 HashMap 1개를 만들고 그 안에 "1번임", "2번임" 이라는 키를 부여해 각 값들을 집어넣어 놓은 상태다.

(HashMap 모르면 구글에 검색하셈. 대충 key / value로 짝 지어서 보관해주는 애임.)

 

아까 설명했듯 "testMap"은 생성한 "map"과 똑같은 정보를 가지고 있는 상태다.

 

이제 이 값을 뽑아내보자.

 

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h2>Test</h2>
    <ul>
        <li><span th:text="${testMap['1번임'].testName}"></span></li>
        <li><span th:text="${testMap['1번임'].testVal}"></span></li>
        <li><span th:text="${testMap['2번임'].testName}"></span></li>
        <li><span th:text="${testMap['2번임'].testVal}"></span></li>
        
        <li><span th:text="${testMap['1번임']['testName']}"></span></li>
        <li><span th:text="${testMap['1번임']['testVal']}"></span></li>
        
        <li><span th:text="${testMap['1번임'].getTestName()}"></span></li>
        <li><span th:text="${testMap['1번임'].getTestVal}"></span></li>
        
        //이거 세개 다 같은거임
    </ul>
</body>
</html>

아까랑 비슷한데 좀 다르다.

 

이번에는 [] 안에 숫자가 아닌 다른 뭔가 들어가있다.

List와 비슷하게 testMap['~~~']map.get("~~~")의 역할과 똑같이 동작한다.

그렇다는 것은

  1. testMap에서 key가 "1번임"인거 가져오셈.
  2. 그 안에 testName 가져오셈.

이렇게 정리된다고 볼 수 있겠다.

 

최종 정리

//Object

${testValue.testName} => name1의 testName을 프로퍼티 접근 == name1.getTestName()
${testValue['testName']} => 똑같음.
${testValue.getTestName()} => name1의 getTestName() <--getter 직접 호출

//List

${testList[0].testName} => List의 0번째 인덱스를 찾은 후 testName 프로퍼티 접근
		== list.get(0).getTestName();
${testList[0]['testName']} => 똑같음.
${testList[0].getTestName()} => getter 직접 호출

//Map

${testMap['1번임'].testName} => Map에서 Key값이 "1번임"을 찾아서 testName 프로퍼티 접근
		== map.get("1번임").getTestName();
${testMap['1번임']['testName']} => 똑같음.
${testMap['1번임'].getTestName()} => 직접 호출.

 

다음 글에서는 지역변수 선언인 th:with에 대해 알아보겠다.

 

글에 틀린 점이 있다면 그건 내가 허접이기 때문에 그런 것이니 양해를 부탁드린다.

 

그럼 컴파일 오류 없는 개발하시길 :)