왜 Thymeleaf를 써야하는지는 이전 글의 jsp 설정에서 봤듯이 STS4에서 jsp 셋팅을 기본으로 지원을 하지 않는다는 점이다. 반면에 Thymeleaf는 초기 프로젝트 설정에서 Dependency로 Thymeleaf만 추가해도 셋팅이 된다. 인프런에 있는 많은 강의에서도 대부분 부트 입문자에게 Thymeleaf쪽을 공부하는 것을 추천한다. Thymeleaf는 JSP와 비슷한 것이 많은데 추가적으로 몇가지 편리한 기능들이 추가되어 JSP에서는 불편했던 것들이 Thymeleaf에서는 좀 더 작업하기 편한 것들이 있다. 무조건 Thymeleaf만을 쓰라는 것은 아니다. FreeMarker나 Groovy, Mustache 등의 템플릿 엔진도 있다. 나중에 기회가 되면 이러한 것들도 공부해보고 싶긴하다.

 

Thymeleaf 플러그인 설치

설치해

  • STS4에서 thymeleaf 관련 속성들의 인텔리센스는 위의 플러그인 설치로 인해 가능해진다. 참고하기

설치되면 이게 가능

프로젝트 셋팅

  • 프로젝트 생성
* STS4 > New 탭 > Spring Start Project
  - Name > boot-thymeleaf
  - Type > Maven
  - Packaging > Jar
  - Java Version > 11
  - Language > Java
  - Group > com.test.thymeleaf
  - Artifcat > boot-mybatis
  - Package > com.test.thymeleaf
  - Spring boot version > 2.7.13
  
* Dependency 
  - Spring Web
  - Oracle Driver
  - MyBatis Framework
  - Lombok
  - Thymeleaf 
  - Spring Boot DevTools
  • 설정파일 셋팅 > application.properties
    • classpath이건 스프링과 동일하게 기본적으로 src/main/resources 이다. 
    • 작업할 땐 spring.thymeleaf.cache=false
# 서버 포트 번호
server.port = 8092

# JSP View Resoler, webapp, WEB-INF 폴더가 없음 
spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp

# HikariCP settings
spring.datasource.hikari.minimumIdle=5
spring.datasource.hikari.maximumPoolSize=20
spring.datasource.hikari.idleTimeout=30000
spring.datasource.hikari.maxLifetime=2000000
spring.datasource.hikari.connectionTimeout=30000

spring.datasource.driver-class-name=oracle.jdbc.OracleDriver
spring.datasource.url=jdbc:oracle:thin:@localhost:1521:xe
spring.datasource.username=hr
spring.datasource.password=java1234

#Thymeleaf 
spring.thymeleaf.enabled=true
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html

# 이전에 내용을 캐싱시켜준거 보여주는데 속도 빠르게 해주는데
# 개발할때는 고친게 눈에 바로 보여야 한다. 캐시 활성화 끈다. 
spring.thymeleaf.cache=false
spring.thymeleaf.encoding=UTF-8

# 이설정을 하면 mybatis 다루는데 필요한 설정이 가능 
mybatis.config-location=classpath:mybatis-config.xml

SQL, Mapper 파일

  • typeAliase 설정
<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0/EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>
	<typeAliases>
		<typeAlias type="com.test.domain.BoardDTO" alias="dto"/>
	</typeAliases>
</configuration>
  • sql 파일 
create table tblBoard (
   seq     number      primary key,
   subject varchar2(1000) not null,
   content varchar2(2000) not null,
   regdate           date not null,
   id      varchar2(30) not null
);
-- drop sequence seq;
create sequence seq;

desc tblBoard;

insert into tblBoard values(seq.nextVal, '제목입니다.', '내용입니다.', sysdate, '멍멍이');
insert into tblBoard values(seq.nextVal, '제목입니다.2', '내용입니다.2', sysdate, '야옹이');
insert into tblBoard values(seq.nextVal, '제목입니다.3', '내용입니다.3', sysdate, '어흥이');

select * from tblBoard;
  • mapper.xml쪽
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.test.mapper.ThymeleafMapper">
	<select id="getNum" resultType="Integer">
		select salary from employees where rownum=1
	</select>
	
	<select id="getTxt" resultType="String">
		select first_name from employees where rownum = 1
	</select>
	
	<!-- application.properties에서 typeAlias를 지정해서 패키지명을 생략한 것이다.  -->
	<!-- mybatis-config.xml에 엘리아스를 지정해서 가능하다. -->
	<select id="getDTO" resultType="dto">
		select * from tblBoard where rownum = 1 
	</select>
	
	<select id="getNames" resultType="String">
		select first_name from employees where rownum &lt;= 10
	</select>
	
	
	<select id="getList" resultType="dto">
		select * from tblBoard
	</select>
</mapper>

프로젝트 파일셋팅

★ 자바단
com.test.controller > ThymeleafController.java
com.test.domain > BoardDTO.java
com.test.mapper > ThymeleafMapper.java(I)
com.test.thymeleaf > BootThymeleafApplication.java

★ 매퍼단
src/main/resources
com/test/mapper > ThymeleafMapper.xml

★ 뷰단
templates 폴더에 하나씩 추가

자바단 및 프론트단 파일

  • 기본적인 Controller 틀 
    • 설정파일에서 thymeleaf prefix, suffix를 써놓은대로 > 앞뒤로 string이 붙는다. 
@Controller
public class ThymeleafController {
	
	@GetMapping("/m1")
	public void m1() {
		
		// 요청 메소드의 반환값 > void > m1.jsp 호출 
		// 요청 메소드의 반환값 > void > m1.html 호출
		System.out.println("m1");
	}
    
    // 위와 아래는 동일한 표현이다. > void 반환값, String 반환값
    
    /*@GetMapping("/m1")
	public String m1() {
		System.out.println("m1");
		return "m1"; // 이것도 마찬가지로 m1.html 호출이다.
	}*/
    
}
  • ★★★ Thymeleaf Standard Expression
1. Variable Expression, 변수 표현식 
    - ${}
    - 컨트롤러 > 전달된 값 > 출력하는 역할
			
* 우리가 쓰던 EL과 비슷하다!
			
2. Selection Variable Expression, 선택 변수 표현식
	- *{}
	- 객체/맵 프로퍼티  > 출력 
	- th:object 속성과 같이 사용
			
3. Message Expression, 메세지 표현식
	- #{}
	- 스프링 메세지 > 전용 출력
			
4. Link URL Expression, 링크 주소 표현식 
	` @{}
	- 링크의 URL > 전용 출력
			
5. Fragment Expression, 조각 표현식
	- ~{}
	- 조각 페이지 삽입(include 지시자 or 타일즈 > 유사 ) 
	- 타임리프 > th:XXX 옆엔 속성이다.
  • "/m3" Controller 부분
    • 기존 스프링과 동일 model에 담아서 전송, map을 사용해도 되고 int나 String으로 넣어도 model에 넣는데 차이 없음
@GetMapping("/m3")
	public String m3(Model model) {
		int num = mapper.getNum();
		String txt = mapper.getTxt();
		BoardDTO dto = mapper.getDTO();
		
		Map<String, String> map = new HashMap<String, String>();
		map.put("dog","강아지");
		map.put("cat","고양이");
		
		model.addAttribute("num", num);
		model.addAttribute("txt", txt);
		model.addAttribute("now", Calendar.getInstance());
		model.addAttribute("dto", dto);
		model.addAttribute("map", map);
		
		return "m3";
	}
<h2>변수 표현식</h2>
<div>${num}</div>
<div>10</div>

<!--★ EL 표현은 th:text와 함께 적어야 한다. 그렇지 않으면 변환없이 그대로 나온다. -->

<div th:text="${num}">24000</div>
<div th:text="${num}">200</div>
<div th:text="100"></div>
<!-- 
th 접두어가 붙어야 한다. 태그 내부에 200이라는 값은 th:text="${num}"으로 덮어써진다.
프론트엔드 개발자가 작업하던 페이지를 넘겨주면 백엔드 개발자는 th:text 부분만 채우면 된다.
-->

<h2>타입별</h2>
<div>숫자 : 100</div>
<div th:text="${num}">숫자 : </div>

<div>숫자 : <span th:text="${num}"></span></div>
<div>문자 : <span th:text="${txt}"></span></div>
<div>객체 : <span th:text="${dto}"></span></div>
<div>멥 : <span th:text="${map}"></span></div>				

<!-- th:text를 붙여야 하는 것은 중요하다.
model에 넣은 이름대로 꺼내서 쓴다. -->
<!-- setter를 정의해야하고 .멤버변수명으로 꺼내쓰는건 동일하고 
getSubject() 이렇게 메서드 방식으로 사용하는 방법도 중요함 -->

<h2>복합 데이터(객체, 맵) 프로퍼티</h2>

 <!-- 변수 표현식 -->
 <div>제목 : <span th:text="${dto.getSubject()}"></span></div>
 <div>제목 : <span th:text="${dto.subject}"></span></div>
 <div>아이디 : <span th:text="${dto.id}"></span></div>
 <div>날짜 : <span th:text="${dto.regdate}"></span></div>

 <!-- 
 *{} > 선택 변수 표현식 앞에 : 부분을 생략한다. 반복되면 이득이다.th:object와 함께 쓰이는 것 확인
 -->
 <div th:object="${dto}">
    <!-- <div>제목 : <span th:text="${dto.subject}"></span></div> -->
    <div>제목 : <span th:text="*{subject}"></span></div>
    <div>아이디 : <span th:text="*{id}"></span></div>
    <div>날짜 : <span th:text="*{regdate}"></span></div>
 </div>
 
<!-- 객체가 가진 method를 뷰단에서도 유지가 된다는걸 인지하고 있어야함 -->
 <div th:text="${map.get('dog')}"></div>
 <div th:text="${map.dog}"></div>
 <div th:text="${map.cat}"></div>

 <div th:object="${map}">
    <div th:text="*{dog}"></div>
    <div th:text="*{cat}"></div>
 </div>
  • 실행결과

다국어처리

  • application.properties에 아래 내용 추가
    • 스프링 메시지를 사용하는 방식인데 이걸 정리하기엔 양이 방대하다. 나중에 따로 타픽을 잡어서 해야할 듯?
# 스프링 메시지
spring.messages.basename=messages
spring.messages.encoding=UTF-8
  • messages_en.properties
language=English

item.name=Mouse
item.color=Black
item.price=30000

hello=Hello, I m {0}.
  • messages_ja.properties
language=日本語

item.name=マウス
item.color=黒
item.price=30000

hello=こんにちは、私は{0}です。
  • messages.properties
language=한국어

item.name=마우스
item.color=검정색
item.price=30000

hello=안녕하세요. 저는 {0}입니다.
  • m3.html
	 <h2>다국어 지원<small>스프링 메세지</small></h2>
	 <div class="message" title="사용 언어" th:text="#{language}"></div>
	 
	 <div class="message" title="상품">
	 	<div>상품명 : <span th:text="#{item.name}"></span></div>
	 	<div>색상 : <span th:text="#{item.color}"></span></div>
	 	<div>가격 : <span th:text="#{item.price}"></span></div>
	 </div>
	 
	 <div th:text="#{hello('홍길동')}"></div>
	 <div th:text="#{hello(#{item.name})}"></div>
  • 결과로 브라우저 기본 언어 우선순위에 따라서 적절한 message.properties를 골르고 내용을 읽어 번역이 된다. 

언어 우선순위

  • 일본어를 우선순위 1등으로 했을 때

 

+ Recent posts