[내일배움캠프Spring-30일차] CH 3 일정 관리 앱 Develop Lv2~Lv6

2025. 3. 31. 21:25·백엔드 부트캠프/TIL

어쩌다보니 진도를 쭉 나가게 되었다. Lv2 는 주말에 대부분 구현해두어, 오늘은 어느정도의 리팩토링과 Lv6 까지 구현했다 보면 된다.

Lv3 은 Pwd 만 추가하는 거라 4 레벨부터 본격적이라고 생각하면 된다. 구현한 레벨이 많다 보니, 모든 내용을 한번에 담기는 힘들다. 내가 고민했던 포인트만 코멘트 남기겠다.

Lv 2. 유저 CRUD

  • 유저를 생성, 조회, 수정, 삭제할 수 있습니다.
    • 유저는 아래와 같은 필드를 가집니다.
    • 유저명, 이메일, 작성일 , 수정일 필드
    • 작성일, 수정일 필드는 JPA Auditing을 활용합니다.
  • 연관관계 구현
    • 일정은 이제 작성 유저명 필드 대신 유저 고유 식별자 필드를 가집니다

- 유저 Enity 같은 경우에는 일정 Entity 와 연관관계가 있기 때문에, 해당 부분을 일정 Entity 에 추가해주어야한다.

  @ManyToOne
  @JoinColumn(name="userId")
  private User user;
  public void setUser(User user) {
    this.user = user;
  }

- setUser를 통해서 주입 해주어야 하는 것도 잊지 않았다.

- 이때부터 RequestDto 와 ResponseDto 가 막 생겨나기 시작했다. 그래서 이 많은 Dto 를 어떻게 처리할까? 하다가 아래와 같은 이유로 Entity 별로 나누기로 했다.

// 왜 패키지를 Entity 별로 분리 했냐 ? -> Entity 를 기준으로 기능을 만들기 때문에
// Error 가 있어 수정해야할 일이 있으면 Entity request 와 response 를 동시에 확인해봐야함.
// 그래서 Entity 패키지로 묶어 두면 조금 더 관리하기 쉬울 거 같아서 Entity 를 기준으로 패키지 별로 분리함.

Lv 3. 회원가입 필수

  • 유저에 비밀번호 필드를 추가합니다.
    • 비밀번호 암호화는 도전 기능에서 수행합니다.

- 일당 해당 부분에서는 필드만 추가하라고 했기 때문에, 필드만 추가했다.

- 추가적으로 회원 가입 시, RequestDto 에 pwd 를 추가해두었다.

Lv 4. 로그인(인증)

  • 조건
    • 이메일과 비밀번호를 활용해 로그인 기능을 구현합니다.
    • 회원가입, 로그인 요청은 인증 처리에서 제외합니다.

- 로그인은 세션과 필터를 잘 활용해야 된다.

- 먼저, LoginFilter 를 만들어야 된다.

package com.example.scheduleappserverjpa.filter;

import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import org.springframework.http.HttpStatus;
import org.springframework.util.PatternMatchUtils;
import org.springframework.web.server.ResponseStatusException;

import java.io.IOException;
import java.net.http.HttpConnectTimeoutException;

public class LoginFilter implements Filter {

  private static final String[] WHITE_LIST = {"/", "/users/signup", "/users/login"};

  @Override
  public void doFilter(ServletRequest servletRequest,
                       ServletResponse servletResponse,
                       FilterChain filterChain)
          throws IOException, ServletException {
    HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
    // request 에서 url 가져오기.
    String requestURL = httpServletRequest.getRequestURI();

    // response 도 다운 캐스팅
    HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;

    // 화이트 리스트에 있지 않은 url 의 경우에는 로그인 여부를 확인해야한다.
    if (!isWhiteList(requestURL)) {
      // 만약 체크해야할 url 이라면,
      HttpSession session = httpServletRequest.getSession(false);

      // 세션이 없거나, 세션 키가 널이라면, 로그인 되지 않은 것.
      if (session == null || session.getAttribute("loginUser") == null) {
        throw new ResponseStatusException(HttpStatus.UNAUTHORIZED);
      }
    }
    filterChain.doFilter(servletRequest, servletResponse);
  }

  // 화이트 리스트 안에 있는 값과 현재 url 을 비교하는 것.
  public boolean isWhiteList(String string) {
    return PatternMatchUtils.simpleMatch(WHITE_LIST, string);
  }
}

- 간단하게 설명하면, WhiteList 에 있는 값들은 조건문을 들어가지 않을 것이고(로그인 여부 확인을 안 해도 됨), 없는 모든 url 들은 해당 조건문을 수행해야한다.

- 조건문에서는 아예 세션이 널이거나? loginUser 라는 세션이 없다면 ? 인증 에러가 뜨게 하는 것이다.

- 강의에서는 따로 common 이라는 곳에 interface 를 구현해 두었는데. 해당 부분을 보자.

public interface Const {
  String LOGIN_USER = "loginUser";
}

- 이렇게 인터페이스에 따로 Login_user 를 만들어 둔 이유는 상수로 만들기 위함이다. enum 의 원리를 생각하면 조금 이해가 쉬울 것이다.

- 일단은 로그인, 로그아웃 까지만 구현했고, 인가에 대한 요구사항은 없어서 이후에 모든 과제를 끝낸 후 인가를 추가적으로 수정하기로 했다.

Lv 5. 다양한 예외처리 적용하기

  • Validation을 활용해 다양한 예외처리를 적용해 봅니다. 
  • 정해진 예외처리 항목이 있는것이 아닌 프로젝트를 분석하고 예외사항을 지정해 봅니다.
    • Ex) 할일 제목은 10글자 이내, 유저명은 4글자 이내
    • @Pattern을 사용해서 회원 가입 Email 데이터 검증 등

- ReqeustDto 에다가 Valid 를 설정해주었고, 할일과 유저명에 대한 유효값 검증을 적절히 수정해주었다.

  // https://jakarta.ee/specifications/bean-validation/3.0/jakarta-bean-validation-spec-3.0.html#builtinconstraints-size
  // emil 검색시 나오는 정규표현식
  @Pattern(regexp = "[a-z0-9._%+-]+@[a-z0-9.-]+\\.[a-z]{2,4}", message = "이메일 형식이 올바르지 않습니다.")

- 이메일은 이렇게 수정해주었다. 공식 문서에 나와 있는 표현식을 보고 적절히 수정해주었다.

  @NotBlank(message = "이름은 필수값 입니다.")
  @Size(min=2, max=4)
  private String username;

  @NotBlank(message = "제목은 필수값 입니다.")
  @Size(max=10)
  private String title;

- 할일과 유저명도 유구사항에 맞게 Vaild 를 넣어주었다.

- 추가적으로 커스텀한 에러들도 만들었다.

- 일단 커스텀 에러는 총 3가지로 데이터가 존재하지 않을 때, 인증이 되지 않을 때, 입력값이 이상할때 만들어 두었다.

- Handler 에서도 해당 에러를 아래와 같은 방법으로 나타나게 수정했다. 확실히 많은 정보가 담기니 훨 나은 거 같다 : >

[
    "Message: Required request body is missing: public org.springframework.http.ResponseEntity<java.lang.String> com.example.scheduleappserverjpa.controller.UserController.delete(java.lang.Long,com.example.scheduleappserverjpa.dto.user.DeleteRequestDto)",
    "ErrorType: class org.springframework.http.converter.HttpMessageNotReadableException",
    "ErrorClass: org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor",
    "ErrorMethod: readWithMessageConverters",
    "HttpStatus: BAD_REQUEST"
]

- handler 에는 이런 에러 들을 담아냈다.

 

Lv 6. 비밀번호 암호화 도전

  • Lv.3에서 추가한 비밀번호 필드에 들어가는 비밀번호를 암호화합니다.
    • 암호화를 위한 PasswordEncoder를 직접 만들어 사용합니다.

- 과제에 주어진 코드를 이용해서 회원가입, 로그인 시 실행해야할 로직을 작성해주었다.

- 먼저 회원가입이다.

  public SignUpResponseDto signUp(SignUpRequestDto dto) {
    // pwd 암호화
    String encode = passwordEncoder.encode(dto.getPwd());
    // user Entity 생성
    User user = new User(dto.getName(), dto.getEmail(), encode);
    // Save Repository
    User saved = userRepository.save(user);
    return SignUpResponseDto.from(saved);
  }

- 암호화한 pwd 를 Repository 에 넣어준다.

- 그런 후 Login 할 때 비교해주어야 한다.

  public FindResponseDto login(LoginRequestDto dto) {
    // 이메일에 맞는 유저 찾기
    User findUser = userRepository.findByEmailOrElseThrow(dto.getEmail());

    // 유저의 비밀번호를 가져와서 비교
    boolean isMatch = passwordEncoder.matches(dto.getPwd(), findUser.getPwd());

    if(!isMatch) {
      throw new InvalidPasswordException("비밀번호가 틀렸습니다.");
    }
    return FindResponseDto.from(findUser);
  }

- 나는 처음에 아래와 같은 방식을 생각했었다.

- 근데 알고보니,, 같은 String 값을 가진 pwd 라고 해도, 매번 암호화 할 때마다 다른 값으로 설정된다는 것이다.. !?

- 그래서 이런 방식이 아닌 2번의 방식으로 코드를 만들어야 됐다 : > 

 

✅ 오늘의 회고

- 아직은 인가에 대해서 자세한 부분을 다루지 않았는데, 내일 인가에 대한 부분을 조금 더 수정해볼 생각이다.

- 로그인 되어 있는 세션을 이용하여 해당 세션의 아이디를 가진 유저가 수정할 수 있어야 하기 때문에 해당 부분은 좀 더 세밀하게 다루어야할 거 같다. 유저 뿐만 아니라, 일정도 이런 방향으로 수정해야 되기 때문에 ! 할 부분이 많다 : >,,, 이 부분을 댓글 CRUD 와 Paging 처리 이후에 할 까 생각도 든다.

'백엔드 부트캠프 > TIL' 카테고리의 다른 글

[내일배움캠프Spring-32일차] CH 3 일정 관리 앱 Develop Lv7~Lv8, Refactoring  (1) 2025.04.02
[내일배움캠프Spring-31일차] 과제 트러블슈팅  (1) 2025.04.01
[내일배움캠프Spring-29일차] CH 3 일정 관리 앱 Develop Lv0~Lv1  (0) 2025.03.28
[내일배움캠프Spring-28일차] Spring DI/IoC  (1) 2025.03.27
[내일배움캠프Spring-27일차] 일정 관리 앱 개발 회고  (0) 2025.03.26
'백엔드 부트캠프/TIL' 카테고리의 다른 글
  • [내일배움캠프Spring-32일차] CH 3 일정 관리 앱 Develop Lv7~Lv8, Refactoring
  • [내일배움캠프Spring-31일차] 과제 트러블슈팅
  • [내일배움캠프Spring-29일차] CH 3 일정 관리 앱 Develop Lv0~Lv1
  • [내일배움캠프Spring-28일차] Spring DI/IoC
sintory-04
sintory-04
🚀🚀🚀
  • sintory-04
    Sintory Dev Blog
    sintory-04
    글쓰기 관리
  • 전체
    오늘
    어제
    • 분류 전체보기 (291)
      • 백엔드 부트캠프 (111)
        • TIL (97)
        • WIL (0)
        • 문제풀이 (7)
        • 기타 (6)
      • 백엔드 부트캠프[사전캠프] (35)
        • TIL (16)
        • 문제풀이 (17)
        • 기타 (1)
      • Troubleshooting (11)
      • 코딩 공부 (118)
        • Java (28)
        • Baekjoon-Java (24)
        • Programmers-Java (40)
        • Spirngboot (11)
        • typescript (1)
        • JavaScript (6)
        • Spring 입문 (8)
      • 프로젝트 (2)
        • ToDoApp(FireBase) (3)
        • ToDoApp(Spring) (5)
      • 기타 (4)
  • 블로그 메뉴

    • 소개
    • Github
  • 최근 글

  • 최근 댓글

  • hELLO· Designed By정상우.v4.10.3
sintory-04
[내일배움캠프Spring-30일차] CH 3 일정 관리 앱 Develop Lv2~Lv6
상단으로

티스토리툴바