이제 로그인을 구현해볼것이다.
로그인 폼은 아래와 같다.
package com.shopingmall.seungjae.controller.Member;
import lombok.Data;
@Data
public class LoginForm {
private String loginId;
private String password;
private String loginError;
}
로그인 로직이다.
입력된 아이디 비밀번호를 토대로 member를 return하는데, 만약 해당하는 member가 없다면 null을 반환한다.
package com.shopingmall.seungjae.service;
import com.shopingmall.seungjae.domain.Member;
import com.shopingmall.seungjae.repository.MemberRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.ui.Model;
import java.util.Map;
import java.util.Optional;
@Service
@RequiredArgsConstructor
public class LoginService {
private final MemberRepository memberRepository;
public Member login(String loginId, String password) {
Optional<Member> member = memberRepository.findByLoginId(loginId);
return member.filter(m -> m.getPassword().equals(password)).orElse(null);
}
}
우선 GetMapping으로 들어올 경우 login/loginPage를 return해서 로그인폼 뷰를 사용자에게 보여준다.
@PostMapping으로 /member/login에 요청이 왔을 경우 검증하고 LoginForm 클래스에 바인딩한다.
form에 들어온 (사용자가 입력한 값)을 loginService.login으로 확인하고 loginMember를 생성한다.
loginMember가 null이면 아이디 비밀번호가 틀린것이므로 에러메시지와 함께 다시 login/loginPage를 랜더링한다.
로그인에 성공했다면 세션이 있으면 세션을 반환하고 없다면 신규 세션을 생성한다.
이 때 세션은 서블릿이 제공하는 HttpSession을 사용하여 생성한다.
이렇게 생성한 세션에 로그인 회원 정보를 보관한다.
return "redirect:" + redirectURL; 로 로그인 시도했던 Url로 사용자를 보낸다.
package com.shopingmall.seungjae.controller.Member;
import com.shopingmall.seungjae.domain.Member;
import com.shopingmall.seungjae.repository.MemberRepository;
import com.shopingmall.seungjae.repository.MemberRepositoryImpl;
import com.shopingmall.seungjae.service.LoginService;
import com.shopingmall.seungjae.service.SessionManager;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import java.util.Optional;
@Controller
@Slf4j
@RequestMapping("/member")
@RequiredArgsConstructor
public class ShoppingMallMemberLoginController {
private final SessionManager sessionManager;
MemberRepository memberRepository = new MemberRepositoryImpl();
private final LoginService loginService;
@GetMapping("/login")
public String loginPage() {
return "login/loginPage";
}
@PostMapping("/login")
public String loginV4(@Valid @ModelAttribute LoginForm form, Model model, @RequestParam(defaultValue = "/") String redirectURL, HttpServletRequest request) {
Member loginMember = loginService.login(form.getLoginId(),
form.getPassword());
log.info("login? {}", loginMember);
if (loginMember == null) {
model.addAttribute("loginError", "아이디, 비밀번호가 틀렸습니다. 다시 입력해주세요.");
return "login/loginPage";
}
//로그인 성공 처리
//세션이 있으면 있는 세션 반환, 없으면 신규 세션 생성
HttpSession session = request.getSession();
//세션에 로그인 회원 정보 보관
session.setAttribute(SessionConst.LOGIN_MEMBER, loginMember);
return "redirect:" + redirectURL;
}
@PostMapping("/logout")
public String logoutV3(HttpServletRequest request) {
//세션을 삭제한다.
HttpSession session = request.getSession(false);
if (session != null) {
session.invalidate();
}
return "redirect:/";
}
//사용자 페이지 (사용자의 정보를 볼 수 있음)
@GetMapping("/{loginId}")
public String userPage(@PathVariable("loginId") String loginId, Model model) {
Member member = memberRepository.findByLoginId(loginId).orElse(null);
model.addAttribute("member", member);
return "userPage";
}
}
<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>로그인</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
}
.container {
width: 400px;
margin: 0 auto;
padding: 20px;
background-color: #f0f0f0;
}
.form-group {
margin-bottom: 20px;
}
.form-group label {
display: block;
margin-bottom: 5px;
}
.form-group input {
width: 100%;
padding: 8px;
border-radius: 4px;
border: 1px solid #ccc;
}
button[type="submit"] {
padding: 10px 20px;
background-color: #4285f4;
color: #fff;
border: none;
border-radius: 4px;
cursor: pointer;
}
.error{
color : red;
}
</style>
</head>
<body>
<div class="container">
<h2>로그인</h2>
<form action="/member/login" method="post">
<div class="form-group">
<label for="loginId">아이디</label>
<input type="text" id="loginId" name="loginId" placeholder="아이디를 입력하세요">
</div>
<div class="form-group">
<label for="password">비밀번호</label>
<input type="password" id="password" name="password" placeholder="비밀번호를 입력하세요">
</div>
<div th:text="${loginError}" class="error">로그인 에러 메시지</div>
<button type="submit">로그인</button>
<button type="button" onclick="location.href='/';">홈으로 돌아가기</button>
</form>
</div>
<script>
<!-- const form = document.querySelector('form');-->
<!-- form.addEventListener('submit', function (event) {-->
<!-- event.preventDefault();-->
<!-- const id = document.querySelector('#id').value;-->
<!-- const password = document.querySelector('#password').value;-->
<!-- // 여기에 로그인 처리를 위한 JavaScript 코드를 추가하세요-->
<!-- // 예시:-->
<!-- console.log('아이디:', id);-->
<!-- console.log('비밀번호:', password);-->
<!-- // 로그인 처리 로직을 구현하세요-->
<!-- // 서버로 요청을 보내고 응답을 처리하는 등의 작업이 필요합니다.-->
<!-- });-->
</script>
</body>
</html>
로그인 실패

로그인 성공

로그내역
