-header.html에 login링크 걸어주기
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<div th:fragment="header">
<div id="header">
<ul>
<li><a href="">Home</a></li><li>
<a href="">Board</a></li><li>
<a href="">Book</a></li><li>
<a href="">FAQ</a></li><li>
<a href="" th:href="@{/login/login}">Login</a></li>
</ul>
</div>
</div>
</html>
- LoginController에서 Model 대신에 RedirectAttribute 사용
(redirect 기능을 쓰고, Model의 자손이라 Model의 기능을 다 물려받고 있다. )
@PostMapping("/login")
public String login(String id, String pwd, RedirectAttributes model) throws Exception{
// 1. id, pwd를 확인
if(loginCheck(id,pwd)) {
// 2. 일치하면, userInfo.html
model.addAttribute("id", id);
model.addAttribute("pwd", pwd);
return "userInfo"; // userInfo.html
} else {
// 일치하지 않으면, login.html로 이동
String msg = URLEncoder.encode("id 또는 패스워드가 일치하지 않습니다.", "utf-8");
model.addAttribute("msg", msg);
return "redirect:/login/login";
// return "redirect:/login/login?msg=" + msg; // redirect는 GET요쳥 -> GetMapping("/login") 받음
}
수정 후 서버를 실행하면 다음과 같은 결과를 확인할 수 있다.

model에 담긴 내용이 자동으로 쿼리 스트링으로 바뀌어 들어간걸 확인할 수 있다.
* 인코딩이 깨져있는 부분을 해결해보자.
- resources/application.properties에 인코딩 설정을 추가해준다.
server.servlet.encoding.enabled=true
server.servlet.encoding.charset=UTF-8
} else {
// 일치하지 않으면, login.html로 이동
// String msg = URLEncoder.encode("id 또는 패스워드가 일치하지 않습니다.", "utf-8");
String msg ="id 또는 패스워드가 일치하지 않습니다.";
model.addAttribute("msg", msg);
return "redirect:/login/login";
// return "redirect:/login/login?msg=" + msg; // redirect는 GET요쳥 -> GetMapping("/login") 받음
}
LoginController 코드도 다음과 같이 수정한 후 서버를 재실행한다.

성공적으로 변환이 이루어진 것을 확인할 수 있다.


우리는 한 번만 요청했는데 요청이 2번 전달된 것을 확인할 수 있다.
첫 번째 login은 '수동 요청'이 된 것이고, 두 번째 login?msg... 는 브라우저가 '자동 요청'을 수행한 것이다.
응답을 보면 302번으로 응답한 것을 확인할 수 있다 (redirect)
해당 Location으로 자동 응답이 이루어진다.
* addFlashAttribute
} else {
// 일치하지 않으면, login.html로 이동
// String msg = URLEncoder.encode("id 또는 패스워드가 일치하지 않습니다.", "utf-8");
String msg ="id 또는 패스워드가 일치하지 않습니다.";
model.addAttribute("msg", msg);
model.addFlashAttribute("msg","일회용 메시지");
return "redirect:/login/login";
// return "redirect:/login/login?msg=" + msg; // redirect는 GET요쳥 -> GetMapping("/login") 받음
}
LoginController에 addFlashAttribute()를 사용하는 문장을 추가해준다.
login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1 th:text = "${param.msg}"></h1>
<h1 th:text = "${msg}"></h1>
<form action="/login/login" method="post">
id<br>
<input type="text" name="id"><br>
pwd:<br>
<input type="password" name="pwd"><br>
<input type="submit" value="로그인">
</form>
</body>
</html>
${param.msg}는 쿼리 스트링에서 읽어오는 것 -> addAttribute로 저장된 거 보여줄 때 사용
${msg}는 세션에서 읽어오는 것이다. -> addFlashAttribute로 저장된 거 보여줄 때 사용(RedirectAttribute에서 읽어옴)

첫 번째 addAttribute로 전달한 것은 쿼리 스트링을 통해 전달된 것을 확인할 수 있다.
addFlashAttribute는 쿼리 스트링에 없는데 어떻게 나온 것일까?
그 이유는 데이터를 세션 객체에 담았다가 전달한 후 지우기 때문이다. (세션 저장은 서버의 부담)
한 번 보여주고 말 때는 쿼리 스트링에 추가되는 것보다 addFlashAttribute를 통해 전달 후 지워버리는 것이 좋다.
- LoginController에 Request 객체 선언
if(loginCheck(id,pwd)) {
// 2. 일치하면, userInfo.html
model.addAttribute("id", id);
model.addAttribute("pwd", pwd);
return "userInfo"; // userInfo.html
} else {
// 일치하지 않으면, login.html로 이동
// String msg = URLEncoder.encode("id 또는 패스워드가 일치하지 않습니다.", "utf-8");
String msg ="id 또는 패스워드가 일치하지 않습니다.";
model.addAttribute("msg", msg);
model.addFlashAttribute("msg","일회용 메시지");
req.setAttribute("msg", "request에 저장된 msg");
return "redirect:/login/login";
<h1 th:text = "${#request.getAttribute('msg')}"></h1>
request객체에서 읽어올 때 -> request 객체에서 msg를 찾는다.

예상과는 다르게 일회용 메시지가 2번 출력된다.
그 이유는 redirect는 요청이 2번 가기 때문에 2번째 요청에는 새로운 요청이 가게 된다.
처음에 저장된 request객체는 사라지고 새로운 request 객체가 만들어진다.
그래서 이걸 읽을 수 없는 것이다.
login.html 파일에 있는 request의 이름은 같은데 다른 객체에서 msg를 찾으니 msg가 제대로 출력되지 않는 것이다.
-> 제대로 나오게 하려면 redirect를 forward로 바꿔줘야 한다.
redirect와 달리 같은 request를 사용하기 때문에 forward로 하면 request에 저장된 게 날라가지 않는다.
(같은 request에 있는거니까!)
if(loginCheck(id,pwd)) {
// 2. 일치하면, userInfo.html
model.addAttribute("id", id);
model.addAttribute("pwd", pwd);
return "userInfo"; // userInfo.html
} else {
// 일치하지 않으면, login.html로 이동
// String msg = URLEncoder.encode("id 또는 패스워드가 일치하지 않습니다.", "utf-8");
String msg ="id 또는 패스워드가 일치하지 않습니다.";
model.addAttribute("msg", msg);
model.addFlashAttribute("msg","일회용 메시지");
req.setAttribute("msg", "request에 저장된 msg");
return "forward:/";
forward로 수정 후 index.html에
<h1 th:text = "${#request.getAttribute('msg')}"></h1>
문장을 추가해준다.
<div layout:fragment="content">
<h1>환영합니다.</h1>
<h1 th:text = "${#request.getAttribute('msg')}"></h1>
</div>


요청이 1번만 간 것을 확인할 수 있다. (forward - 1번 요청 / 1번 응답)
return "redirect:/";
forward를 redirect로 변경하면 다음과 같이 요청이 2번 가게된다.

'SpringBoot' 카테고리의 다른 글
| ch3 01. Spring DI의 원리(1) (0) | 2023.07.18 |
|---|---|
| ch2 16. thymeleaf 사용하기 (0) | 2023.07.18 |
| ch2 14. forward와 redirect - 이론 (0) | 2023.07.14 |
| ch2 13. filter와 interceptor (0) | 2023.07.07 |
| ch2 12. Thymeleaf로 레이아웃 적용하기 (0) | 2023.07.07 |