티스토리 뷰
초보 웹 개발자를 위한 스프링 5 프로그램 입문을 보고 복습 겸 개인 학습 정리입니다. (windows 기준)
chap13에서는 세션, 인터셉터, 쿠키에 대해 공부한다. 이번 글에서는 세션(HttpSession) 적용하는 방법을 선행해 보았다.
로그인 기능을 이용하기 때문에 1번부터 9번까지는 로그인 기능 및 뷰를 만들고 10번부터 컨트롤러에서 로그인 상태를 유지하는 HttpSession를 사용한 코드를 변경하였다.
예제 프로젝트 만들기 (메이븐 기준) 예제 코드
sp5-chap13 프로젝트 폴더 생성
+ chap12의 src 파일 복붙
+ chap12의 pom.xml 복붙 후 <artifactId> 13로 변경
이클립스에서 sp5-chap12 폴더에 생성한 메이븐 프로젝트 import
1. 로그인 성공 후 인증 상태 정보를 세션에 보관할 때 사용할 AuthInfo 클래스를 작성한다.
→ sp5-chap13/src/main/java/spring/AuthInfo.java
package spring;
public class Authinfo {
private Long id;
private String email;
private String name;
public Authinfo(Long id, String email, String name) {
this.id =id;
this.email=email;
this.name=name;
}
public Long getId() {
return id;
}
public String getEmail() {
return email;
}
public String getName() {
return name;
}
}
2. 암호 일치 여부를 확인하기 위해 Member 클래스에 matchPassword() 메서드를 추가한다.
→ sp5-chap13/src/main/java/spring/Member.java
package spring;
import java.time.LocalDateTime;
public class Member {
... 생략 ...
public boolean matchPassword(String password) {
return this.password.equals(password);
}
}
3. 이메일과 비밀번호가 일치하는지 확인해서 AuthInfo 객체(1번에서 만든 클래스)를 생성하는 AuthService 클래스를 작성한다.
→ sp5-chap13/src/main/java/spring/AuthService.java
package spring;
public class AuthService {
private MemberDao memberDao;
public void setMemberDao(MemberDao memberDao) {
this.memberDao = memberDao;
}
public AuthInfo authenticate(String email, String password) {
Member member = memberDao.selectByEmail(email);
if (member == null) {
throw new WrongIdPasswordException();
}
if (!member.matchPassword(password)) {
throw new WrongIdPasswordException();
}
return new AuthInfo(member.getId(),
member.getEmail(),
member.getName());
}
}
4. 위에서 작성한 AuthService를 이용해서 로그인 요청을 처리하는 LoginCommand 클래스를 작성한다.
→ sp5-chap13/src/main/java/controller/LoginCommand.java
package controller;
public class LoginCommand {
private String email;
private String password;
private boolean rememberEmail;
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public boolean isRememberEmail() {
return rememberEmail;
}
public void setRememberEmail(boolean rememberEmail) {
this.rememberEmail = rememberEmail;
}
}
5. LoginController 클래스와 폼에 입력된 값이 올바른지 검사하는 LoginCommandValidator 클래스를 작성한다.
→ sp5-chap13/src/main/java/controller/LoginCommandValidator.java
package controller;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;
public class LoginCommandValidator implements Validator {
@Override
public boolean supports(Class<?> clazz) {
return LoginCommand.class.isAssignableFrom(clazz);
}
@Override
public void validate(Object target, Errors errors) {
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "email", "required");
ValidationUtils.rejectIfEmpty(errors, "password", "required");
}
}
6. 로그인 요청을 처리하는 LoginController 클래스를 작성한다.
→ sp5-chap13/src/main/java/controller/LoginController.java
package controller;
..import 생략...
@Controller
@RequestMapping("/login")
public class LoginController {
private AuthService authService;
public void setAuthService(AuthService authService) {
this.authService = authService;
}
@GetMapping
public String form(LoginCommand loginCommand) {
return "login/loginForm";
}
@PostMapping
public String submit(LoginCommand loginCommand, Errors errors) {
new LoginCommandValidator().validate(loginCommand, errors);
if (errors.hasErrors()) {
return "login/loginForm";
}
try {
AuthInfo authInfo = authService.authenticate(
loginCommand.getEmail(),
loginCommand.getPassword());
// TODO 세션에 authInfo 저장해야 함
return "login/loginSuccess";
} catch (WrongIdPasswordException e) {
errors.reject("idPasswordNotMatching");
return "login/loginForm";
}
}
}
7. login/loginForm, loginSuccess 뷰를 위한 JSP를 작성하자. (접은 글로 대체)
→ sp5-chap13/src/main/WEB-INF/view/login/loginForm.java
<%@ page contentType="text/html; charset=utf-8" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<!DOCTYPE html>
<html>
<head>
<title><spring:message code="login.title" /></title>
</head>
<body>
<form:form modelAttribute="loginCommand">
<form:errors />
<p>
<label><spring:message code="email" />:<br>
<form:input path="email" />
<form:errors path="email"/>
</label>
</p>
<p>
<label><spring:message code="password" />:<br>
<form:password path="password" />
<form:errors path="password"/>
</label>
</p>
<input type="submit" value="<spring:message code="login.btn" />">
</form:form>
</body>
</html>
→ sp5-chap13/src/main/WEB-INF/view/login/loginSuccess.java
<%@ page contentType="text/html; charset=utf-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<!DOCTYPE html>
<html>
<head>
<title><spring:message code="login.title" /></title>
</head>
<body>
<p>
<spring:message code="login.done" />
</p>
<p>
<a href="<c:url value='/main'/>">
[<spring:message code="go.main" />]
</a>
</p>
</body>
</html>
8. 뷰에서 사용할 메시지 label.properties 파일에 추가 (접은 글로 대체)
→ sp5-chap13/src/main/resources/message/label.properties
login.title=로그인
login.btn=로그인하기
idPasswordNotMatching=아이디와 비밀번호가 일치하지 않습니다.
login.done=로그인에 성공했습니다.
8. 컨트롤러와 서비스를 스프링 빈에 등록하기
→ sp5-chap13/src/main/java/config/MemberConfig.java
package config;
..생략..
import spring.AuthService;
import spring.ChangePasswordService;
import spring.MemberDao;
import spring.MemberRegisterService;
@Configuration
@EnableTransactionManagement
public class MemberConfig {
..생략..
// 인증 서비스 빈 추가
@Bean
public AuthService authService() {
AuthService authService = new AuthService();
authService.setMemberDao(memberDao());
return authService;
}
}
→ sp5-chap13/src/main/java/config/ControllerConfig.java
package config;
..생략..
import controller.LoginController;
import controller.RegisterController;
import spring.MemberRegisterService;
import spring.AuthService;
@Configuration
public class ControllerConfig {
@Autowired
private MemberRegisterService memberRegSvc;
//추가
@Autowired
private AuthService authService;
@Bean
public RegisterController registerController(){
RegisterController controller = new RegisterController();
controller.setMemberRegisterService(memberRegSvc);
return controller;
}
//추가
@Bean
public LoginController loginController() {
LoginController controller = new LoginController();
controller.setAuthService(authService);
return controller;
}
}
9. 서버 실행 후 "localhost:8090/sp6-chap13/login" 접속하기
[Run As] → [Run on Server] → [톰캣😺 서버 실행] → [브라우저에 "localhost:8090/sp6-chap13/login" 접속]
📌컨트롤러에서 HttpSession 사용하기
컨트롤러에서 HttpSession 사용하려면 다음 두 가지 방법 중 하나를 사용하면 된다.
- 요청 매핑 애노테이션 적용 메서드에 HttpSession 파라미터 추가
스프링 MVC는 컨트롤러의 메서드를 호출할 때 HttpSession 객체를 파라미터로 전달한다. 이 HttpSession을 생성하기 전이면 새로운 HttpSession을 생성하고 그렇지 않으면 기존에 존재하는 HttpSession을 사용한다. (항상 HttpSession 생성)
@PostMapping
public String submit(LoginCommand loginCommand, Errors errors, HttpSession session) {
... 생략
}
- 요청 매핑 애노테이션 적용 메서드에 HttpSevletRequest 파라미터를 추가하고 HttpServletRequest를 이용해서 HttpSession을 구한다. (필요한 시점에만 HttpSession을 생성)
@PostMapping
public String submit
(LoginCommand loginCommand, Errors errors, HttpServletRequest req) {
HttpSession session = req.getSession();
... 생략
}
10. LoginController 코드에 인증 후 인증 정보를 세션에 담도록 submit() 메서드의 코드를 수정한다.
로그인에 성공하면 HttpSession의 authInfo 속성에 인증 정보 객체를 저장하도록 수정했다.
→ sp5-chap13/src/main/java/controller/LoginController.java
package controller;
..생략
import javax.servlet.http.HttpSession;
@Controller
@RequestMapping("/login")
public class LoginController {
... 생략
@PostMapping // HttpSession 파라미터 추가
public String submit(LoginCommand loginCommand, Errors errors, HttpSession session) {
new LoginCommandValidator().validate(loginCommand, errors);
if (errors.hasErrors()) {
return "login/loginForm";
}
try {
AuthInfo authInfo = authService.authenticate(
loginCommand.getEmail(),
loginCommand.getPassword());
// 세션 추가한 것
session.setAttribute("authInfo", authInfo);
return "login/loginSuccess";
} catch (WrongIdPasswordException e) {
errors.reject("idPasswordNotMatching");
return "login/loginForm";
}
}
11. LogoutController 클래스를 만들고 로그아웃을 위해 HttpSession을 삭제한다.
→ sp5-chap13/src/main/java/controller/LooutController.java
package controller;
import javax.servlet.http.HttpSession;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class LogoutController {
@RequestMapping("/logout")
public String logout(HttpSession session) {
session.invalidate();
return "redirect:/main";
}
}
12. LogoutController 클래스 빈을 ControllerConfig 설정 클래스에 추가하자
→ sp5-chap13/src/main/java/config/MemberConfig.java
package config;
..생략..
import controller.LogoutController;
import controller.LoginController;
import controller.RegisterController;
import spring.MemberRegisterService;
import spring.AuthService;
@Configuration
public class ControllerConfig {
@Autowired
private MemberRegisterService memberRegSvc;
//추가
@Autowired
private AuthService authService;
@Bean
public RegisterController registerController(){
RegisterController controller = new RegisterController();
controller.setMemberRegisterService(memberRegSvc);
return controller;
}
//추가
@Bean
public LoginController loginController() {
LoginController controller = new LoginController();
controller.setAuthService(authService);
return controller;
}
// 12 추가
@Bean
public LogoutController logoutController() {
return new LogoutController();
}
}
13. HttpSession을 사용하는지 확인할 수 있도록 main.jsp를 수정한다.
→ sp5-chap13/src/main/WEB-INF/view/main.java
수정 전
<%@ page contentType="text/html; charset=utf-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<title>메인</title>
</head>
<body>
<p>환영합니다.</p>
<p><a href="<c:url value="/register/step1" />">[회원 가입하기]</a>
</body>
</html>
수정 후
<%@ page contentType="text/html; charset=utf-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<title>메인</title>
</head>
<body>
<c:if test="${empty authInfo}">
<p>환영합니다.</p>
<p>
<a href="<c:url value="/register/step1" />">[회원 가입하기]</a>
<a href="<c:url value="/login" />">[로그인]</a>
</p>
</c:if>
<c:if test="${! empty authInfo}">
<p>${authInfo.name}님, 환영합니다.</p>
<p>
<a href="<c:url value="/edit/changePassword" />">[비밀번호 변경]</a>
<a href="<c:url value="/logout" />">[로그아웃]</a>
</p>
</c:if>
</body>
</html>
14. 서버 실행 후 "localhost:8090/sp6-chap13/main" 접속하기
[Run As] → [Run on Server] → [톰캣😺 서버 실행] → [브라우저에 "localhost:8090/sp6-chap13/main" 접속]
로그인에 성공할 경우 HttpSession의 "authInfo" 속성에 인증 정보를 저장한다.
로그인에 실패할 경우 아래와 같이 화면에 8에서 작성한 멘트("아이디와 비밀번호가 일치하지 않습니다.")가 나온다.
'study > Spring' 카테고리의 다른 글
chap 13 - Cookie (0) | 2023.02.23 |
---|---|
chap 13 - HandlerInterceptor (0) | 2023.02.23 |
스프링 프로젝트 생성하기 (start.spring.io) (0) | 2023.02.16 |
chap 12 - 커맨드 객체 검증과 에러 메시지 (0) | 2023.02.15 |
chap 12 - MVC 메세지 처리 (0) | 2023.02.13 |
- Total
- Today
- Yesterday
- authenticate()
- musma
- Django tutorial
- python3
- 혼자 공부하는 파이썬
- API
- 암호화
- Magazine K
- Spring
- 디자인 패턴
- 한글 형태소 분석기
- django-environ
- git공부
- git 공부
- 웹페이지
- 회원가입
- git
- Java
- 톰캣
- django
- 회원 로그인
- 환경 변수 설정
- 커맨드 객체
- path variable
- 면접을 위한 CS 전공 지식 노트
- error: failed to push some refs to 'https://github.com/
- django.contrib.auth
- 검색 결과 내 페이지네이션
- Python
- 배열
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |