[SpringBoot]Thymeleaf 사용하기

☘️ Thymeleaf 사용하기

[목표]


Thymeleaf 타임리프란?

참조 : https://www.thymeleaf.org/documentation.html

  • 스프링 부트의 자동 설정을 지원하는 웹 템플릿 엔진
  • HTML, XML, JS, CSS, 기본 텍스트까지 지원
  • 확장성이 좋고 유지보수가 쉬운 템플릿을 쉽게 만들 수 있도록 도와줌
  • HTML문서에 HTML5 문법으로 서버쪽 로직을 수행하고 적용시킬 수 있음
  • HTML 디자인에 전혀 영향을 미치지 않고 웹 템플릿 엔진을 통해 HTML 생성 가능 (디자인 - 개발팀의 커뮤니케이션 도와줌)
  • 템플릿 엔진, th:xx 형식으로 속성을 html 태그에 추가하여 값 처리
  • WAR 패키징이 필수인 JSP와 다르게 JAR 패키징으로 동작하기 때문에 thymeleaf를 가장 많이 사용



Thymeleaf 타임리프 표현식


1. Variable Expressions - ${ }

: 해당 Context의 포함된 변수들을 사용할 수 있음

<tr th:each="user : ${users}">
  <td th:text="${user.name}"></td>
  <td th:text="${user.email}"></td>
</tr>

2. Selection Variable Expressions - *{ }

: 가까운 DOM에 th:object로 정의된 변수가 있다면 그 변수에 포함된 값을 생략하고 나타낼 수 있음

<tr th:object="${users}">
  <!-- *{name} == ${users.name} -->
  <td th:text="*{name}"></td>
  <td th:text="*{email}"></td>
</tr>

3. Message Expressions - #{ }

: 미리 정의된 message.properties 파일이 있다면 #표현식으로 나타낼 수 있음

<span th:if="${#fields.hasErrors('name')}" th:errors="*{name}"></span>
//[에러 메세지를 포함하는 객체]
@Column	@JacksonXmlProperty
@NotBlank(message = "* Name은 필수 입력 항목입니다. ")
private String name;

@Column(unique=true)
@JacksonXmlProperty
@NotBlank(message = "* Email은 필수 입력 항목입니다. ")
private String email;

: @표현식을 이용하여 다양하게 URL을 표현할 수 있음

<!-- adduser url 연걸  -->
<form
  action="#"
  th:action="@{/adduser}"
  th:object="${user}"
  method="post"
></form>



Thymeleaf 타임리프 사용예제


> 기본 페이지 띄워보기~!

Hello page 띄우기


[leaf_first.html] : 화면에 띄울 html 설정

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
  <head>
    <meta charset="UTF-8" />
    <title>leaf_first</title>
  </head>
  <body>
    <h2 th:text="${myName}">text</h2>
    <h2>Hello, <span th:text="${myName}"></span></h2>
    <h2>Hola! [[${myName}]]</h2>
  </body>
</html>


[UserContoller.java] : url 매핑

@Controller
public class UserThymController {

    @GetMapping("/leaf")
    public String hello(Model model) {
    model.addAttribute("myName", "Thymeleaf");
    // leaf_first.html
    return "leaf_first";
    }
}

[웹 페이지 화면]



> index와 유저 등록 페이지 띄우기

<form></form> 태그로 새로운 유저를 등록하고, index페이지에 값 뿌려주기


[UserController.java] : /index url 매핑

@Controller
public class UserThymController {

	@Autowired
	UserRepository userRepo;

	@GetMapping("/index")
	public ModelAndView getUsers() {
		List<User> userList = userRepo.findAll();
		return new ModelAndView("index", "users", userList);
	}

	@GetMapping("/leaf")
	public String hello(Model model) {
		model.addAttribute("myName", "Thymeleaf");
		return "leaf_first";
	}
}


[src/main/resources/templates/index.html] : 등록된 유저리스트를 모두 볼 수 있는 페이지 작성

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
  <meta charset="UTF-8" />
  <body>
    <table>
      <tr>
        <th>Name</th>
        <th>Email</th>
      </tr>
      <!-- each = ${users} = controller에 설정해준 users -->
      <tr th:each="user : ${users}">
        <td th:text="${user.name}"></td>
        <td th:text="${user.email}"></td>
      </tr>
    </table>
    <a href="/signup"> >> 사용자 등록 </a>
  </body>
</html>


[주의]

  • Controller에서 넘겨주는 객체명을 html에서 정확히 받아줘야 함
  • Controller getUsers()로 넘겨준 ‘users’와 index.html에서 th:each 에서 받아주는 객체 ‘users’의 이름이 정확히 같아야 함


[localhost:포트 번호/index로 설정접속한 웹 화면]

> User CRUD 구현하기


[Controller.java]

@Controller
public class UserThymController {

	@Autowired
	UserRepository userRepo;

	@GetMapping("/edit/{id}")
	public String showUpdateForm(@PathVariable("id") long id, Model model ) {
		User editUser = userRepo.findById(id).orElseThrow(()-> new IllegalArgumentException("유효하지 않은 아이디입니다. "));
		model.addAttribute("user", editUser);
		return "update";
	}

	@GetMapping("/update/{id}")
	public String updateUser(@PathVariable("id") long id, @Valid User user, BindingResult result, Model model) {
		if(result.hasErrors()) {
			return "update";
		}
		userRepo.save(user);
		return "redirect:/index";
	}

	@GetMapping("/delete/{id}")
	public String deleteUser(@PathVariable("id") long id, Model model) {
		userRepo.deleteById(id);
		return "redirect:/index";
	}

	@GetMapping("/signup")
	//showSignUpForm() 인자를 안넘겨주면 에러 발생
	//user은 클래스 이름이라서 타입만 User로 잘 지정해주면 이름은 상관없음
	public String showSignUpForm(User user) {

	//add-user.html에 User 오브젝트를 넘겨주기 위함
	return "add-user";
	}

	@PostMapping("/adduser")
	//BidingResult
	public String addUser(@Valid User user, BindingResult result, Model model){

		//입력 항목에 오류가 있는지 체크
		if (result.hasErrors()){
			//에러 발견시 입력페이지 다시 뿌려줌
			return "add-user";
		}
		userRepo.save(user);

		//index로 바로 redirect해줌
		return "redirect:/index";
	}

	@GetMapping("/index")
	public ModelAndView getUsers() {
		List<User> userList = userRepo.findAll();
		return new ModelAndView("index", "users", userList);
	}

	@GetMapping("/leaf")
	public String hello(Model model) {
		model.addAttribute("myName", "Thymeleaf");
		return "leaf_first";
	}
}


[src/main/resources/templates/index.html] : Edit과 Delete 기능 추가

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<meta charset="UTF-8">
<body>
    <table>
	    <tr>
		<th>Name</th>
		<th>Email</th>
		<th>Edit</th>
		<th>Delete</th>
	    </tr>

	    <tr th:each="user : ${users}">
		<td th:text="${user.name}"></td>
		<td th:text="${user.email}"></td>
		<td><a th:href=@{/edit/{id}(id=${user.id})}>Edit </a> </td>
		<td><button th:onclick="deleteUser('[[${user.name}]]')"/>delete</button></td>
		<td><a th:href=@{/delete/{id}(id=${user.id})}>Delete</a> </td>
	    </tr>
    </table>
    <a href="/signup"> >> 사용자 등록 </a>
</body>
</html>

[웹 페이지 화면]


[src/main/resouces/templates/add-user.html] : 유저 등록 폼

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
  <meta charset="UTF-8" />
  <body>
    <h2>사용자 등록</h2>
    <form action="#" th:action="@{/adduser}" th:object="${user}" method="post">
      <label for="name">Name : </label>
      <input type="text" th:field="*{name}" id="name" />
      <!-- user에 설정해둔 에러메세지가 이 span에 출력됨   -->
      <span th:if="${#fields.hasErrors('name')}" th:errors="*{name}"></span>

      <br /><br />

      <label for="email">Email : </label>
      <input type="text" th:field="*{email}" id="email" />
      <span th:if="${#fields.hasErrors('email')}" th:errors="*{email}"></span>

      <br /><br />
      <input type="submit" value="Add User" />
    </form>
  </body>
</html>

[웹 페이지 화면]


[src/main/resouces/templates/update.html] : 유저 정보 수정 입력 form

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
  <meta charset="UTF-8" />
  <body>
    <h2>사용자 정보 수정</h2>
    <form
      action="#"
      th:action="@{/update/{id}(id=${user.id})}"
      th:object="${user}"
      method="get"
    >
      <label for="name">Name : </label>
      <input type="text" th:field="*{name}" id="name" />
      <!-- user에 설정해둔 에러메세지가 이 span에 출력됨   -->
      <span th:if="${#fields.hasErrors('name')}" th:errors="*{name}"></span>

      <br /><br />

      <label for="email">Email : </label>
      <input type="text" th:field="*{email}" id="email" />
      <span th:if="${#fields.hasErrors('email')}" th:errors="*{email}"></span>

      <br /><br />
      <input type="submit" value="수정완료" />
    </form>
  </body>
</html>

[웹 페이지 화면]


+ 자바스크립트 요소 추가하기

[src/main/resources/templates/index.html] : javascript 코드로 confirm화면 띄우기

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<meta charset="UTF-8">
<!-- 자바스크립트 코드 추가 -->
<script type="text/javascript">
    function deleteUser(userName){
	var result = confirm(userName+" 를 정말로 삭제하시겠습니까?");
	    if(result){
		location.href = "delete/" + userId;
	}
}
</script>
<body>
    <table>
	<tr>
	    <th>Name</th>
	    <th>Email</th>
	    <th>Edit</th>
	    <th>Delete</th>
	</tr>
		<!-- each = ${users} = controller에 설정해준 users -->
	<tr th:each="user : ${users}">
	    <td th:text="${user.name}"></td>
	    <td th:text="${user.email}"></td>
	    <td><a th:href=@{/edit/{id}(id=${user.id})}>Edit </a> </td>
	    <td><button th:onclick="deleteUser('[[${user.id}]]','[[${user.name}]]')"/>delete</button></td>

		<!-- <td><a th:href=@{/delete/{id}(id=${user.id})}>Delete</a> </td> -->
	</tr>
	</table>
	<a href="/signup"> >> 사용자 등록 </a>
</body>
</html>

[웹 페이지 화면]