안녕하세요 인포돈 입니다.
타임리프 템플릿을 랜더링 할 때, 자원을 찾지 못하는 오류
프로젝트에서 타임리프를 활용하면서, Model에 값을 넣어주어 활용하였다. 오류가 나는 부분은 아래와 같다.
오류 내용
org.thymeleaf.exceptions.TemplateInputException: An error happened during template parsing (template: "class path resource [templates/chatbot/chat.html]")
Caused by: org.attoparser.ParseException: Could not parse as expression: "favoriteKeyword : ${favoriteKeywords}" (template: "chatbot/chat" - line 288, col 6)
Caused by: org.thymeleaf.exceptions.TemplateProcessingException: Could not parse as expression: "favoriteKeyword : ${favoriteKeywords}" (template: "chatbot/chat" - line 288, col 6)
org.thymeleaf.exceptions.TemplateProcessingException: Could not parse as expression: "favoriteKeyword : ${favoriteKeywords}" (template: "chatbot/chat" - line 288, col 6)
Controller
@RequestMapping("/chat")
public String chatGET(Model model){
HashMap<String, String> favoriteKeywords = new HashMap<>();
~~~~
~~~~
model.addAttribute("favoriteKeywords", favoriteKeywords);
return "chatbot/chat";
}
Tymeleaf
<div th:for="favoriteKeyword : ${favoriteKeywords}">
<a th:href="@{/{id}(id = ${favoriteKeyword.value})}" th:text="${favoriteKeyword.key}"></a>
</div>
분명히 모델에 넣어주고, Map을 꺼내기 위해서 key와 value를 사용했지만,,, 오류가 나는 것을 확인할 수 있었다.
무엇이 문제인지 모르기 때문에, 기초적인 부분부터 하나씩 실험해 보자
1) 기본적인 String 출력
model.addAttribute("hello", "hello");
<div th:text="${hello}"></div>
뭐... 크게 어렵지 않게 꺼내올 수 있었다. 그렇게 된다면, HashMap 자료구조를 통해 꺼내오는 방식이나, th:each의 부분에서 오류가 났을 확률이 높아 보인다. 하나씩 실험해 보자
2) th:each 고쳐보기
아..... 이 부분에서 실수했다..... th:each를 활용하려 했으나,,, th:for을 사용해버렸다... 자동 완성되는 기능을 빠르게 이용하다 보니 나온 실수이다.
<div th:each="favoriteKeyword : ${favoriteKeywords}">
<div th:text="${favoriteKeyword.key}"></div>
<div th:text="${favoriteKeyword.value}"></div>
</div>
해당 코드를 통해 잘 출력됨을 알 수 있다.
* 여기서 th:for을 보고 헷갈릴 수 있다. 이 의미는 우리는 기본적인 프로그래밍 문법에서 for는 반복을 나타낸다. 그러나 타임리프에서 th:for은 <label>의 속성을 나타낸다.
* 참고로 <label> 태그의 for 속성은 <input>과 같이 쓰이며, <label> 태그를 눌러도, 해당 <input>이 체크되거나, focus 되는 속성이다.