Back-End/Spring

[Spring Boot] 회원 연습 (4) - 로그인

09009 2024. 1. 22. 18:23

MemberController

package com.yyi.member.controller;

import com.yyi.member.dto.MemberDTO;
import com.yyi.member.service.MemberService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;

@Controller
@RequiredArgsConstructor
public class MemberController {
    // 생성자 주입
    private final MemberService memberService;

    // 회원가입 페이지 출력 요청
    @GetMapping("/member/save")
    public String saveForm() {
        return "save"; // templates 폴더에서 "save"라는 html 파일을 찾는다.
    }

    @PostMapping("/member/save")
    public String save(@ModelAttribute MemberDTO memberDTO) {
        System.out.println("MemberController.save");
        System.out.println("memberDTO = " + memberDTO);
        memberService.save(memberDTO);
        return "login";
    }


}

 

로그인 페이지 생성하기

templates 폴더에 login.html 생성

login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>login</title>
</head>
<body>
    <form action="/member/login" method="post">
        이메일 : <input type="text" name="memberEmail"> <br>
        비밀번호 : <input type="password" name="memberPassword"> <br>
        <input type="submit" value="로그인">
    </form>

</body>
</html>

 

 

MemberController

    @GetMapping("/member/login")
    public String loginForm() {
        return "login";
    }

 

로그인 메서드 생성

아직 service에 login 메서드가 없기 때문에 오류 발생 (신경 쓰지 않아도 된다)

MemberController

   @PostMapping("/member/login")
    public String login(@ModelAttribute MemberDTO memberDTO) {
        MemberDTO loginResult = memberService.login(memberDTO);
        if (loginResult != null) {
            // 로그인 성공

            return "main";
        } else {
            // 로그인 실패

            return "login";
        }
    }

 

 

이전에 회원가입할 때 사용한 save 메서드는 repository에 없었다.

그 이유는, MemberRepository는 JpaRepository에서 상속을 받아 save 메서드를 제공받았기 때문에

 

MemberService

    public MemberDTO login(MemberDTO memberDTO) {
        /*
            1. 회원이 입력한 이메일로 DB에서 조회를 함
            2. DB에서 조회한 비밀번호와 사용자가 입력한 비밀번호가 일치하는지의 여부 확인
        * */

    }

 

MemberRepository

public interface MemberRepository extends JpaRepository<MemberEntity, Long> {
    // 이메일로 회원 정보 조회 (select * from member_table where member_email = ? 쿼리를 메서드 정의만으로 실행시키기 위함)
    // Optional : java.util에서 제공하는 클래스 (null 방지 위함)
    // 모든 repository에서 주고받는 객체는 모두 entity 객체의 형태, 즉 entity 객체로 return을 받는다
    Optional<MemberEntity> findByMemberEmail(String memberEmail);

}

 

MemberService

  public MemberDTO login(MemberDTO memberDTO) {
        /*
            1. 회원이 입력한 이메일로 DB에서 조회를 함
            2. DB에서 조회한 비밀번호와 사용자가 입력한 비밀번호가 일치하는지의 여부 확인
        * */

        // optional 객체로 return 받기, entity 객체를 optional 객체로 한 번 더 감싼 개념 (포장지 두 개로 생각)
        Optional<MemberEntity> byMemberEmail = memberRepository.findByMemberEmail(memberDTO.getMemberEmail());
        if (byMemberEmail.isPresent()) {
            // 조회 결과가 있을 경우 (해당 이메일을 가진 회원 정보가 있을 때)
            // get() 메서드 : optional로 감싸진 객체를 하나의 포장지를 벗겨내는 느낌의 메서드
            MemberEntity memberEntity = byMemberEmail.get();
            // ↓ 비밀번호 일치 여부 확인
            if (memberEntity.getMemberPassword().equals(memberDTO.getMemberPassword())) {
                // 비밀번호 일치
                // Entity로 DB에서 조회를 했지만, 컨트롤러로 넘겨줄 땐 DTO로 넘겨준다.
                // Entity 객체는 service 클래스 안에서만 사용하도록 일단 계획. 컨트롤러에서는 dto 객체 사용
                // 작업 : entity 객체 -> dto 변환 후 return
                
                
                
            } else {
                // 비밀번호 불일치 (로그인 실패)
                return null;
            }
        } else {
            // 조회 결과가 없을 경우 (해당 이메일을 가진 회원 정보가 없을 때)
            return null;
        }

    }

 

entity 객체를 dto로 변환하기 위해서 DTO 클래스에서 작업

 

MemberDTO 메서드 추가

package com.yyi.member.dto;

import com.yyi.member.entity.MemberEntity;
import lombok.*;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class MemberDTO {
    private Long id;
    private String memberEmail;
    private String memberPassword;
    private String memberName;

    public static MemberDTO toMemberDTO(MemberEntity memberEntity) {
        MemberDTO memberDTO = new MemberDTO();
        memberDTO.setId(memberEntity.getId());
        memberDTO.setMemberEmail(memberEntity.getMemberEmail());
        memberDTO.setMemberPassword(memberEntity.getMemberPassword());
        memberDTO.setMemberName(memberEntity.getMemberName());
        return memberDTO;
    }
}

 

MemberService 코드 추가

    public MemberDTO login(MemberDTO memberDTO) {
        /*
            1. 회원이 입력한 이메일로 DB에서 조회를 함
            2. DB에서 조회한 비밀번호와 사용자가 입력한 비밀번호가 일치하는지의 여부 확인
        * */

        // optional 객체로 return 받기, entity 객체를 optional 객체로 한 번 더 감싼 개념 (포장지 두 개로 생각)
        Optional<MemberEntity> byMemberEmail = memberRepository.findByMemberEmail(memberDTO.getMemberEmail());
        if (byMemberEmail.isPresent()) {
            // 조회 결과가 있을 경우 (해당 이메일을 가진 회원 정보가 있을 때)
            // get() 메서드 : optional로 감싸진 객체를 하나의 포장지를 벗겨내는 느낌의 메서드
            MemberEntity memberEntity = byMemberEmail.get();
            // ↓ 비밀번호 일치 여부 확인
            if (memberEntity.getMemberPassword().equals(memberDTO.getMemberPassword())) {
                // 비밀번호 일치
                // Entity로 DB에서 조회를 했지만, 컨트롤러로 넘겨줄 땐 DTO로 넘겨준다.
                // Entity 객체는 service 클래스 안에서만 사용하도록 일단 계획. 컨트롤러에서는 dto 객체 사용
                // 작업 : entity 객체 -> dto 변환 후 return
                MemberDTO dto = MemberDTO.toMemberDTO(memberEntity);
                return dto;
            } else {
                // 비밀번호 불일치 (로그인 실패)
                return null;
            }
        } else {
            // 조회 결과가 없을 경우 (해당 이메일을 가진 회원 정보가 없을 때)
            return null;
        }

    }

 

MemberController

  @GetMapping("/member/login")
    public String loginForm() {
        return "login";
    }

    @PostMapping("/member/login")
    public String login(@ModelAttribute MemberDTO memberDTO, HttpSession session) {
        MemberDTO loginResult = memberService.login(memberDTO);
        if (loginResult != null) {
            // 로그인 성공
            session.setAttribute("loginEmail", loginResult.getMemberEmail());
            return "main";
        } else {
            // 로그인 실패

            return "login";
        }
    }

 

(다른 코드)

  @PostMapping("/member/login")
    public String login(@ModelAttribute MemberDTO memberDTO, HttpSession session) {
        MemberDTO sessionUser = memberService.login(memberDTO);
        if (sessionUser != null) {
            session.setAttribute("memberDTO", sessionUser);
            return "main";
        } else {
            return "login";
        }
    }

 

main.html 생성 후 코드 작성

타임리프 적용

xmlns:th="http://www.thymeleaf.org"
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    session 값 확인 : <p th:text="${session.loginEmail}"></p>
</body>
</html>

 

(다른 코드)

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>main</title>
</head>
<body>
    session 값 확인 : <p th:text="${session.memberDTO.memberEmail}"></p>
</body>
</html>

 

 

application.yml 확인 - ddl-auto는 update로

  # spring data jpa 설정
  jpa:
    database-platform: org.hibernate.dialect.OracleDialect
    open-in-view: false
    show-sql: true
    hibernate:
      ddl-auto: update

 

여기까지 코드 작성 후 실행시키기

로그인 수행 후 모습