스프링 MVC 2편(백엔드 웹 개발 활용 기술)

Ch06. 로그인 처리(쿠키, 세션) - 로그인 기능

webmaster 2022. 3. 17. 11:01
728x90

LoginService

@Service
@RequiredArgsConstructor
public class LoginService {
    private final MemberRepository memberRepository;

    /**
     * @return null 로그인 실패
     */
    public Member login(String loginId, String password){
        /*
        Optional<Member> findMemberOptional = memberRepository.findByLoginId(loginId);
        Member member = findMemberOptional.get();
        if(member.getPassword().equals(password)){
            return member;
        }else{
            return null;
        }
        */
        return memberRepository.findByLoginId(loginId)
            .filter(m -> m.getPassword().equals(password))
            .orElse(null);
    }
}
  • 로그인의 핵심 비즈니스 로직은 회원을 조회한 다음에 파라미터로 넘어온 password와 비교해서 같으면 회원을 반환하고, 만약 password가 다르면 null을 반환한다.

LoginForm

@Data
public class LoginForm {

    @NotEmpty
    private String loginId;
    @NotEmpty
    private String password;
}

LoginController

@Slf4j
@Controller
@RequiredArgsConstructor
public class LoginController {
    private final LoginService loginService;

    @GetMapping("/login")
    public String loginForm(@ModelAttribute("loginForm") LoginForm form){
        return "login/loginForm";
    }

    @PostMapping("/login")
    public String login(@Valid @ModelAttribute LoginForm form, BindingResult bindingResult){
        if(bindingResult.hasErrors()){
            return "login/loginForm";
        }
        Member loginMember = loginService.login(form.getLoginId(), form.getPassword());
        if(loginMember == null){
            bindingResult.reject("loginFail", "아이디 또는 비밀번호가 맞지 않습니다.");
            return "login/loginForm";
        }
        //로그인 성공 처리 TODO

        return "redirect:/";
    }
}
  • Login에 실패하게 될 경우 bindingResult.reject를 사용 Global 오류를 생성한다. 

loginForm.html

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
  <meta charset="utf-8">
  <link th:href="@{/css/bootstrap.min.css}" href="../css/bootstrap.min.css" rel="stylesheet">
  <style>
 .container {
    max-width: 560px;
 }
 .field-error {
   border-color: #dc3545;
   color: #dc3545;
 }
 </style>
</head>
<body>
<div class="container">
  <div class="py-5 text-center">
    <h2>로그인</h2>
  </div>
  <form action="item.html" th:action th:object="${loginForm}" method="post">
    <div th:if="${#fields.hasGlobalErrors()}">
      <p class="field-error" th:each="err : ${#fields.globalErrors()}" th:text="${err}">전체 오류 메시지</p>
    </div>
    <div>
      <label for="loginId">로그인 ID</label>
      <input type="text" id="loginId" th:field="*{loginId}" class="form-control"
             th:errorclass="field-error">
      <div class="field-error" th:errors="*{loginId}" />
    </div>
    <div>
      <label for="password">비밀번호</label>
      <input type="password" id="password" th:field="*{password}"
             class="form-control"
             th:errorclass="field-error">
      <div class="field-error" th:errors="*{password}" />
    </div>
    <hr class="my-4">
    <div class="row">
      <div class="col">
        <button class="w-100 btn btn-primary btn-lg" type="submit">
          로그인</button>
      </div>
      <div class="col">
        <button class="w-100 btn btn-secondary btn-lg"
                onclick="location.href='items.html'"
                th:onclick="|location.href='@{/}'|"
                type="button">취소</button>
      </div>
    </div>
  </form>
</div> <!-- /container -->
</body>
</html>
728x90