Spring MVC & Thymeleaf
2024. 1. 3. 15:42
728x90
1. MVC 패턴
: 사용자 인터페이스를 비즈니스 로직으로부터 분리하는 것을 목표로 만들어진 디자인 패턴
- Model : 어플리케이션을 표현하기 위한 데이터 관리하는 부분
- View : 사용자에게 정보가 표현되는 방식을 관리하는 부분
- Controller : 사용자의 입력을 받아, Model이 이해할 수 있는 형태로 변환
- 1) 외부의 클라이언트가 요청을 보낸다.
- 2) DispatcherServlet은 적당한 Controller의 RequestMapping으로 위임한다.
- 3) Controller는 요청을 Model에 명령을 보내고 >> Model은 명령을 처리하여 갱신된 데이터를 전달하거나, 명령 처리의 상태에 대하여 알려준다.
- 4) Controller는 Model에서 받은 데이터를 표현할 View를 선정해서 DispatcherServlet에 전달한다.
- 5) DispatcherServlet은 다시 요청을 보낸 클라이언트로 응답을 번역해서 전송한다.
- 이때 메서드의 반환이 무엇인지에 따라 데이터를 응답할지/ HTML을 응답할지를 DispatchServlet에서 결정하는데
- 문자열이 메서드에서 반환되면 일종의 View라고 판단하여 > ViewResolver에게 반환된 문자열과 이름이 일치하는 View를 반환해달라고 요구한다.
2. View - Thymeleaf 사용해보기
1) Template Engine ?
: 단순한 HTML이 아니고, 상황과 사용자에 따라 (Model의 변화에 따라) 드러나는 모습이 다르게 동적으로 바꿔주는 라이브러리의 일종.
- Spring Boot에서는 HTML과의 유사성, 다양한 기능을 가진 Thymeleaf를 권장.
//text.html
<!doctype html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<h1>여기의 내용을 바꿀 것</h1>
</body>
</html>
// MvcController class
@Controller
public class MvcController {
//text로 요청이 오면 text.hmtl을 반환하는 메서드
@RequestMapping("/text")
public String text() {
return "text";
}
}
2) 내용물 대체
- 요소 전체 변경 : ${data} 와 Model 활용
// text.html
<!doctype html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<h1 th:text="${message}">여기의 내용을 바꿀 것.</h1>
</body>
</html>
//MvcController class
@Controller
public class MvcController {
//text로 요청이 오면 text.hmtl을 반환하는 메서드
@RequestMapping("/text")
public String text(Model model) {
model.addAttribute("message", "Hello, Thymeleaf");
return "text";
}
}
- th: text : HTML 요소의 내용을 전달받은 값으로 대치
- &{data} : model에서 넘겨받은 이름이 data인 데이터로 대치.
- 요소 일부만 바꿀 때 : [[${data}]] + model 활용
// text.html
<!doctype html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<h1>메세지 : [[${message}]] </h1>
</body>
</html>
3) 객체를 이용한 표현
: 객체 클래스 생성(public 속성이거나, getter 생성) + model 활용
// Student class
public class Student {
private String name;
private String email;
public Student() {
}
public Student(String name, String email) {
this.name = name;
this.email = email;
}
public String getName() {
return name;
}
public String getEmail() {
return email;
}
}
// MvcController class
//text-object로 요청이 오면 text-object.html을 반환하는 메서드
@RequestMapping("/text-object")
public String textObject(Model model) {
model.addAttribute("object", new Student("Alex", "alex@gmail.com"));
return "text-object";
}
// text-object.html
<!doctype html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<!--두개의 p요소로 이름과 이메일을 나타내기-->
<!--Getter가 존재하는 속성 또는 메서드 사용가능-->
<p>이름 : [[${object.getName()}]]</p>
<p>이메일 : [[${object.email}]]</p>
</body>
</html>
4) 조건부 표현
: th:if, th:unless 활용
// MvcController class
@RequestMapping("/is-logged-in")
public String isLoggedIn(Model model) {
model.addAttribute("isLoggedIn", true);
return "if-unless";
}
// if-unless.html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<!--로그인 여부를 model로 판단하고 보이는 문구를 바꾸는 뷰-->
<h1>Welcome.</h1>
<div th:if="${isLoggedIn}">you are logged in</div>
<div th:unless="${isLoggedIn}">please log in.</div>
</body>
</html>
5) 리스트 데이터 반복
: th:each 활용하여 대상 요소를 반복해서 표현
- 리스트 데이터 반복
// MvcController class
@RequestMapping("/each")
public String each(Model model) {
List<String> lists = Arrays.asList("aaa", "bbb", "ccc");
model.addAttribute("itemList", lists);
return "each";
}
// each.html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<h1>Item List</h1>
<div>
<p th:each="item: ${itemList}">[[${item}]]</p>
</div>
</body>
</html>
- 객체 데이터도 반복 가능!!
// MvcController class
@RequestMapping("/each-student")
public String eachStudent(Model model) {
List<Student> studentList = Arrays.asList(
new Student("Alex", "alex@gmail.com"),
new Student("Brad", "brad@gmail.com"),
new Student("Chad", "chad@gmail.com")
);
model.addAttribute("studentList", studentList);
return "each-student";
}
// each-student.html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
// 학생리스트가 있으면 학생 정보 표시, 없으면 No student 표시
<div th:if="${studentList.isEmpty()}"> No student..</div>
<div th:unless="${studentList.isEmpty()}" th:each="student: ${studentList}">
<p>이름 : [[${student.name}]]</p>
<p>이메일 : [[${student.email}]]</p>
</div>
</body>
</html>
3. HTML Form
: 웹 브라우저에서 사용자의 입력을 받는 용도로 사용.
<form> 요소와 <input> 태그.
// message.html
<h1>Send Messages</h1>
<form action="/receive" method="post"> // http methods에 따라 보내는 요청의 목적을 나타냄.
<label for="message"> Message:
<input type="text" id="message" name="message"> //name 속성을 바탕으로 동작
</label>
<!-- 양식 제출 버튼-->
<input type="submit" value="Send message">
</form>
<h1>Received Messages</h1>
<form action="/receive">
<label for="receivedMessage">
<div id="receivedMessage" th:each="message: ${receivedMessage}">
[[${message}]]
</div>
</label>
</form>
</h1>
</body>
</html>
// FormController
@Controller
public class FormController {
// 1. 사용자에게 표기하고 싶은 메시지를 전달할 수 있는
// html을 반환하는 메서드
@GetMapping("/send")
public String getSendForm() {
return "message";
}
// 2. 사용자가 전달한 데이터를 처리할 수 있는 메서드
@PostMapping("/receive")
public String receiveMessage(
@RequestParam("message") String message,
Model model
) {
model.addAttribute("receivedMessage", message);
return "message";
}
}
- @RequestParam : 요청의 값을 메서드의 인자로 전달하는 표시.
- action/ th:action="@{ }" : Form이 요청을 보내는 곳을 설정. (th:action은 상황에 따라 변할 수 있는 url을 사용해야 할 때)
728x90
'Programming > Spring, SpringBoot' 카테고리의 다른 글
MyBatis (1) | 2024.01.04 |
---|---|
Post/Redirect/Get : redirect를 사용해야하는 이유 (0) | 2024.01.04 |
스프링부트 기초 (0) | 2024.01.03 |
Spring 어노테이션 정리 (0) | 2023.12.29 |
[타임리프 에러] Property or field ' ' cannot be found on object of type 'java.util.ArrayList' - maybe not public or not valid? (1) | 2023.12.29 |