📒 [실전! 스프링 부트와 JPA 활용 - 김영한] 프로젝트를 완성한 후 부족한 기능을 추가한 후 정리하는 글입니다.
private String email;
private String password;
Member
Entity의 속성이다.email
), 비밀번호(password
) 속성을 Member
Entity에 추가하였다.public boolean checkPassword(String password){
return this.password.equals(password);
}
Member
Entity에 비밀번호 검증을 위한 메서드를 추가하였다.password
)과, 현재 개체의 비밀번호 값(this.password
)을 equals()
메서드를 통해 boolean 값을 반환하는 checkPassword()
메서드를 추가하였다.public Optional<Member> findByEmail(String email){
return em.createQuery("select m from Member m where m.email = :email",Member.class)
.setParameter("email", email)
.getResultList().stream().findAny();
}
MemberRepository
에 데이터베이스에서 이메일(email
)을 통해 Member
개체를 찾는 함수를 구현하였다.email
)에 해당하는 개체가 존재하지 않은 경우 NullPointException
예외가 발생하기 때문에 이를 방지하기 위해서 Optional
클래스를 사용하였다.email
) 정보는 중복이 존재하지 않는 속성이기 때문에 getResultList()
대신 getSingleResult()
를 사용하고자 했지만, getSingleResult()
는 데이터베이스에 해당 이메일 속성을 가진 개체가 존재하지 않으면 Null
을 반환하는 것이 아닌 예외가 발생하는 문제가 발생하기 때문에 getResultList()
를 사용하였다.private final MemberRepository memberRepository;
public Member login(String email, String password) {
Optional<Member> findMember = memberRepository.findByEmail(email);
if(!findMember.orElseThrow(()->new NotCorrespondingEmailException("해당 이메일이 존재하지 않습니다.")).checkPassword(password)){
throw new IllegalStateException("이메일과 비밀번호가 일치하지 않습니다.");
}
return findMember.get();
}
Member
개체에 접근하기 위해서 MemberRepository
를 생성한 후 의존성 주입(DI)을 해준다.findByEmail()
메서드를 통해 반환받은 Optional
클래스가 적용된 Member
개체가 Null이 아닌지 확인하기 위해 orElseThrow()
메서드를 적용한다.Member
개체가 Null이라면 사용자 정의 예외(NotCorrespondingEmailException
)를 터뜨려준다.Member
개체가 Null이 아니라면 checkPassword()
메서드를 통해 고객으로부터 전달받은 비밀번호(password
)와 객체의 비밀번호가 일치하는지 확인한다.IllegalStateException()
예외를 터뜨려준다.findByEmail()
메서드를 통해 반환받은 Member
개체를 반환해준다.@GetMapping("/")
public String homeLogin(@SessionAttribute(name = SessionConst.LOGIN_MEMBER, required = false)Member member, Model model){
/**
* Login 페이지로 이동
**/
if(member == null) {
model.addAttribute("loginForm", new LoginForm());
return "logins/loginForm";
}
/**
* 메인 페이지로 이동
**/
model.addAttribute("member", member);
return "home";
}
'/'
에 해당하는 페이지에서 현재 로그인 Session 존재 여부에 따라 다른 페이지로 연결이 된다.@SessionAttribute
어노테이션을 활용하여 현재 SessionConst.LOGIN_MEMBER
에 해당하는 Session이 있는지 확인한다.@SessionAttribute
어노테이션의 required
속성은 기본값이 true
이다.required
속성은 값이 true
일 경우, Session이 존재하지 않는다면 Session이을 생성하여 반환한다.required
속성의 값을 false
로 할당한다.SessionConst.LOGIN_MEMBER
에 해당하는 Session이 존재하지 않는다면 Model
에 LoginForm
개체를 추가하여 로그인 페이지로 이동한다.Model
에 현재 로그인한 Member
개체를 추가하여 메인 페이지로 이동한다.@PostMapping("/login")
public String login(@Valid LoginForm form, BindingResult bindingResult, HttpServletRequest request) {
// LoginForm 에 email 혹은 password 의 값이 존재하지 않을 때
if (bindingResult.hasErrors()) {
return "/logins/loginForm";
}
Member loginMember = loginService.login(form.getEmail(), form.getPassword());
/**
* 로그인 성공 처리
**/
//세션이 있으면 있는 세션 반환, 없으면 신규 세션을 생성
HttpSession session = request.getSession();
//세션에 로그인 회원 정보 보관
session.setAttribute(SessionConst.LOGIN_MEMBER, loginMember);
return "redirect:/";
}
login
은 LoginForm
객체와 검증 오류가 발생할 경우 오류 내용을 보관하는 스프링 프레임워크에서 제공하는 객체인 BindingResult
그리고 Sessions 생성을 위한 HttpServletRequest
를 인자로 사용한다.BindingResult
에 값이 존재한다면 현재 페이지를 재시작하여 고객에게 현재 발생한 문제 정보를 전달한다.LoginForm
에 저장된 이메일(email
), 비밀번호(password
) 정보를 이용하여 LoginService
의 login
메서드를 실행한 후 Member
객체를 반환받는다.HttpServletRequest
의 getSession()
메서드를 통해 Session을 생성한 후 setAttribute()
메서드를 통해 생성한 Session을 등록한 후 메인 페이지로 이동한다.// 서블릿 HTTP 세션 사용
@PostMapping("/logout")
public String logout(HttpServletRequest request) {
// getSession(false) 를 사용해야 함 (세션이 없더라도 새로 생성하면 안되기 때문)
HttpSession session = request.getSession(false);
if (session != null) {
session.invalidate();
}
return "redirect:/";
}
logout
은 HttpServletRequest
에서 getSession()
메서드를 통해서 Session을 불러온 후 invalidate()
메서드를 통해 Session을 삭제한다.Optional
은 Null이 아닌 값을 포함하거나 포함하지 않을 수 있는 컨테이너 객체이다.Optional
은 클래스이기 때문에 다양한 메서드를 지원한다.Optional
클래스는 반환값이 Null이 발생할 수도 있는 메서드에 사용하면 NPE를 피할 수 있고, 다양한 Optional
의 메서드를 통해 Null이 발생했을 때 문제를 해결할 수 있다.@SessionAttribute
은 메소드 매개변수를 세션 속성에 바인딩하기 위한 어노테이션이다.@SessionAttribute
의 속성name
: 바인딩할 세션 속성의 이름value
: name()에 대한 별칭required
: 세션 속성이 필요한지 여부BindingResult
는 검증 오류가 발생할 경우 오류 내용을 보관하는 스프링 프레임워크에서 제공하는 객체이다.HttpServletRequest
는 HTTP 서블릿에 대한 요청 정보를 제공한다.