@SessionAttributes & @ModelAttribute
Controller 위쪽에 SessionAttributes를 적고
메소드의 인자로 ModelAttribute를 적었는데
인자로 전달될 이름이 같은 경우
먼저 세션에서 전달된 이름으로 저장된 객체를 찾고
해당 객체에 요청으로부터 넘어온 값을 설정해서 전달.
메소드가 return한 값은 argument의 이름을 key로 하여 세션에 저장되게 됨
아래의 예제는 세션에 값을 초기화하는 목적으로 사용되었습니다.
setUpUserForm() 메서드에서 반환하는
User 객체가 이 user 라는 이름으로 세션에 저장됨
@SessionAttributes("user")
public class LoginController {
@ModelAttribute("user")
public User setUpUserForm() {
return new User();
}
}
@SessionAttributes의 파라미터와 같은 이름이 @ModelAttribute에 있을 경우 세션에 있는 객체를 가져온 후, 클라이언트로 전송받은 값을 설정합니다.
SessionAttributes와 ModelAttribute 어노테이션의 인자 이름이 같을 경우
세션에서 정보를 찾아서 이 user에 전달해줌
@Controller
@SessionAttributes("user")
public class LoginController {
......
@PostMapping("/dologin")
public String doLogin(@ModelAttribute("user") User user, Model model) {
......
}
}
@SessionAttribute
메소드에 @SessionAttribute가 있을 경우 파라미터로 지정된 이름으로 등록된 세션 정보를 읽어와서 변수에 할당
@GetMapping("/info")
public String userInfo(@SessionAttribute("user") User user) {
//...
//...
return "user";
}
SessionStatus
전달받은 값을 삭제할 때는
sessionStatus의 setComplate() 메소드 호출
SessionStatus 는 컨트롤러 메소드의 파라미터로 사용할 수 있는 스프링 내장 타입입니다.
이 오브젝트를 이용하면 현재 컨트롤러의 @SessionAttributes에 의해 저장된 오브젝트를 제거할 수 있습니다.
@Controller
@SessionAttributes("user")
public class UserController {
......
@RequestMapping(value = "/user/add", method = RequestMethod.POST)
public String submit(@ModelAttribute("user") User user, SessionStatus sessionStatus) {
......
sessionStatus.setComplete();
......
}
}
Spring MVC - form tag 라이브러리
Spring MVC가 제공하는 tag 라이브러리를 이용하면
세션에 있는 정보들을 form에다가 출력할 수 있음
modelAttribute속성으로 지정된 이름의 객체를 세션에서 읽어와서 form태그로 설정된 태그에 값을 설정합니다.
<form:form action="login" method="post" modelAttribute="user">
Email : <form:input path="email" /><br>
Password : <form:password path="password" /><br>
<button type="submit">Login</button>
</form:form>
실습
- 관리자는 /loginform에서 암호를 입력해 로그인을 한다.
- 관리자가 암호를 맞게 입력할 경우 세션에 로그인 정보가 저장된다.
- 세션에 로그인 정보가 있을 경우 방명록에는 "삭제" 링크가 보여진다.
- 삭제 링크를 누르면 삭제가 된다. 삭제 작업에서도 로그인 정보가 있는지를 검사해야 한다.
GuestbookAdminController.java
guestbook 프로젝트의 controller 패키지에 생성
로그인 폼을 요청하면 해당 요청을 처리하는 일과
로그인 해주세요라고 요청하면 로그인을 처리해주는 일을 수행
package kr.or.connect.guestbook.controller;
import javax.servlet.http.HttpSession;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
@Controller
public class GuestbookAdminController {
@GetMapping(path="/loginform")
public String loginform() {
return "loginform";
}
// 암호가 일치하면 세션에 로그인 정보를 저장
@PostMapping(path="/login")
public String login(@RequestParam(name="passwd", required=true) String passwd,
HttpSession session,
RedirectAttributes redirectAttr) {
// 비밀번호 일치 여부 확인
if("1234".equals(passwd)) {
session.setAttribute("isAdmin", "true");
}else {
redirectAttr.addFlashAttribute("errorMessage","암호가 틀렸습니다.");
return "redirect:/loginform";
// redirect할 때 딱 한 번 만 값을 유지할 목적으로 사용
// redirect는 요청이 한 번이 아니라 두 번이 오는 것
// 이 요청은 login이고 redirect한다는 건 loginform이란 요청을 다시 보낸다는 의미
// forward는 요청이 하나여서
// 유지하고 싶은 값들을 request에 넣어도 redirect 됐을 때 사라짐
// 세션에 저장할 수도 있지만, redirectaAttr을 사용하는 것이 더 효율적
}
return "redirect:/list";
}
}
loginform.jsp
views 폴더에 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>loginform</title>
</head>
<body>
<h1>관리자 로그인</h1>
<br><br>
${errorMessage}<br>
<!-- post 방식을 요청 -->
<form method="post" action="login">
암호 : <input type="password" name="passwd"><br>
<input type="submit">
</form>
</body>
</html>
삭제 기능 추가
list.jsp에 isAdmin 세션값이 있을 경우 삭제 링크를 걸어준다
<c:forEach items="${list}" var="guestbook">
${guestbook.id }<br>
${guestbook.name }<br>
${guestbook.content }<br>
${guestbook.regdate }<br>
// if문 추가
<c:if test="${sessionScope.isAdmin == 'true'}">
<a href="delete?id=${guestbook.id }">삭제</a>
<br><br>
</c:if>
</c:forEach>
GuestbookController.java에 /delete 메소드 추가
세션 값을 읽어올 때는 꼭 @SessionAttribute 어노테이션 명시하기
@GetMapping(path="/delete")
public String delete(@RequestParam(name="id", required=true) Long id,
@SessionAttribute("isAdmin") String isAdmin,
HttpServletRequest request,
RedirectAttributes redirectAttr) {
if (isAdmin == null || !"true".equals(isAdmin)) {
redirectAttr.addFlashAttribute("errorMessage", "로그인을 하지 않았습니다.");
return "redirect:/loginform";
}
String clientIp = request.getRemoteAddr();
guestbookService.deleteGuestbook(id, clientIp);
return "redirect:/list";
}
로그아웃 기능 추가
GuestbookAdminController 클래스에 코드 추가
@GetMapping(path="/logout")
public String logout(HttpSession session) {
session.removeAttribute("isAdmin"); // 세션에서 값 지우기
return "redirect:/list";
}
참고
Spring에서 인증 등을 처리하기 위해 Spring Security 모듈을 제공
이를 이용해 인증 처리 과정을 구현해보기
'Web > Java+Spring' 카테고리의 다른 글
ArgumentResolver (0) | 2021.07.13 |
---|---|
Interceptor (0) | 2021.07.13 |
RestController - Rest API by Spring MVC (0) | 2021.06.10 |
Layered Architecture 실습 - 방명록 (0) | 2021.06.09 |
Layered Architecture (0) | 2021.06.07 |