https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#the-template-engine
Tutorial: Using Thymeleaf
1 Introducing Thymeleaf 1.1 What is Thymeleaf? Thymeleaf is a modern server-side Java template engine for both web and standalone environments, capable of processing HTML, XML, JavaScript, CSS and even plain text. The main goal of Thymeleaf is to provide a
www.thymeleaf.org
여기서 타임리프에 관한 설명을 읽으며 모르는 단어는 번역기 돌려 보고 문장도 모르겠으면 통째로 번역해서 다시 번역해보고
잘 모르겠거나 정리용으로 블로그 글 들을 뒤져보곤 하는데,
아무도 ITemplateResolver가 TemplateResolver로 구현되어있는데,
왜 ServletContextTemplateResolver의 객체로만 보이는지에 대한 자세한 설명이 없다.
이에 대해 의문이 들어 자바/스프링 단톡방에도 질문하였으나, 평일 오후라 그런지 다들 답변이 없으셨다.
스택오버플로우에도 딱히 관련된 사항이 없는 것 같아 한번 간단히 정리하였다.(결론적으로 내 예상이 맞았다..)
2번의 The tymleaf Resolver에 관한 내용을 읽어보면
Template Resolvers are objects that implement an interface from the Thymeleaf API called org.thymeleaf.templateresolver.ITemplateResolver:
라는 설명이 있다.
번역하자면, Template Resolvers는 Thymleaf API에서 요청한 인터페이스의 ITemplateResolver를 구현한 객체라는 말이다.
자 그러면 코드를 보자.
ServletContextTemplateResolver templateResolver =
new ServletContextTemplateResolver(servletContext);
여기서 templateResolver는 ServletContextTemplateResolver class를 참조하는 것 같다
(당연하지만 추상 class나 interface면, new로 인스턴스화 작업이 일어나지 않는다
추상 class에서 default 함수만 쓸 경우 그냥 class를 쓰는 것이 낫기 때문에 쓸 필요가 없다)
그러면 여기서, templateResolver는 ITemplateResolver를 구현한 객체인데, 왜 templateResolver는 ServletContextTemplateResolver를 참조한다고 할까?
그러면 당연히 ServletContextTemplateResolver의 부모 class나 인터페이스가 ITemplateResolver라고 생각할 수 있다.
나도 여기까지는 예상했다.
그런데 다시 의문이 생긴다.
그러면, TemplateResolver라는 네이밍으로
구현하면되는 걸, 왜 네이밍할때 ServletContextTemplateResolver로 구현했는가에 대한 의문이 생긴다.
다시말해 ITemplateResolver랑 ServletContextTemplateResolver가 네이밍으로 봤을 때
서로가 1차적으로 연결된 관계가 아니란 점은 도출해 볼 수 있다는 말이다.
2시간동안 찾아보니 상속 관계는 위와 같고(링크: https://www.thymeleaf.org/apidocs/thymeleaf/3.0.0.BETA03/org/thymeleaf/templateresolver/ServletContextTemplateResolver.html)
구현의 관계는 위와 같다
즉 AbstractTemplateResolver가 ItemplateResolver를 구현하고,
AbstractConfigurableTemplateResolver , DefaultTemplateResolver , StringTemplateResolver 라는 자식 class가 존재한다
org.thymeleaf.templateresolver.AbstractConfigurableTemplateResolver는 ClassLoaderTemplateResolver, FileTemplateResolver, ServletContextTemplateResolver, UrlTemplateResolver 라는 자식 class가 존재한다
AbstractTemplateResolver라는 추상 class는
protected boolean computeResolvable 함수로 resolver가 적용가능한지 체크하고,
protected abstract TemplateMode
enum으로 templateResolver.templateMode = TemplateMode.HTML여기서 쓰는 것처럼
HTML,CSS 형식으로 setting 하는 것이 가능하고,
protected abstract ICacheEntryValidity
템플릿이 캐시에 들어가는 게 가능한지나, 템플릿이 여전히 유효한 지 검사할 수 있고,
boolean getCheckExistence()
템플릿이 리턴하기 전에 존재하는 지 검사할 수 있고,
String getName()
템플릿 확인자 이름을 반환하는 것이나
등등을 알 수 있다.
여기서 prefix랑 suffix를 set으로 설정하는 것을 알 수 있다.
templateResolver.setPrefix("/WEB-INF/templates/");
templateResolver.setSuffix(".html");
이걸로 타임리프를 사용할 떄 접두사 접미어로 (상위폴더,하위이름) 실제 파일의 이름을 쉽게 찾아서 사용한다
여기서 이제, controller에서 view resolver로 보내줄 때
return "thymleafpractice1";
이렇게 보내주는데 이러면, (또는 thymeleafpractice1.html로 보내주기도 하는데, 이렇게 해도 아마 .html이 접미어랑 중복되면 자동으로 접미어만 빼거나 하는식으로 해주지않을까 싶다)
servletContext.getResourceAsStream("/WEB-INF/templates/thymleafpractice1.html")
그러면 내부적으로 함수를 호출해 다음과 같이 처리해준다는 얘기인 것 같다
그리고, 캐시라는 말이 애매하게 보여서 찾아보니 https://countryxide.tistory.com/8 에서
캐싱하는 것이 임시저장소에서 바로 등록했던 걸 가져오고 하는 시간인 것 같다.
그래서,
templateResolver.setCacheTTLMs(3600000L);
이렇게 작성하면 대략 1시간 정도 내가 코드를 바꿔도 임시저장소에서 있던 걸 그대로 보내주는 시간을 정해주는 작업인것같다
60*60*1000ms(1s)
templateEngine = new TemplateEngine();
templateEngine.setTemplateResolver(templateResolver);
결과적으로 , 템플릿 엔진에서는 이렇게 만든 템플릿리졸버를 값으로 받는데 이 과정은 CGVT 엔진에서 동작한다
public class GTVGApplication {
...
private final TemplateEngine templateEngine;
...
public GTVGApplication(final ServletContext servletContext) {
super();
ServletContextTemplateResolver templateResolver =
new ServletContextTemplateResolver(servletContext);
// HTML is the default mode, but we set it anyway for better understanding of code
templateResolver.setTemplateMode(TemplateMode.HTML);
// This will convert "home" to "/WEB-INF/templates/home.html"
templateResolver.setPrefix("/WEB-INF/templates/");
templateResolver.setSuffix(".html");
// Template cache TTL=1h. If not set, entries would be cached until expelled
templateResolver.setCacheTTLMs(Long.valueOf(3600000L));
// Cache is set to true by default. Set to false if you want templates to
// be automatically updated when modified.
templateResolver.setCacheable(true);
this.templateEngine = new TemplateEngine();
this.templateEngine.setTemplateResolver(templateResolver);
...
}
}