이슈 1: User 생성이 안됨.
- 코드에는 문제가 없는데, 아래와 같은 에러 메시지가 나옴
2025-04-03T19:20:43.910+09:00 WARN 67696 --- [schedule] [nio-8080-exec-1] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.HttpMediaTypeNotAcceptableException: No acceptable representation]해결 방법
1. GPT에게 질문
이 에러는 왜 나는 거야? 2025-04-03T19:20:43.910+09:00 WARN 67696 --- [schedule] [nio-8080-exec-1] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.HttpMediaTypeNotAcceptableException: No acceptable representation]2. 답변
HttpMediaTypeNotAcceptableException: No acceptable representation 은 주로 **클라이언트가 요청한 응답 형식(미디어 타입)**에 대해 서버가 "어떻게 응답해야 할지 모를 때" 발생합니다.
![]()
3. 상황 확인
-> UserResponseDto는 Getter를 굳이 쓰지 않아서 Getter를 안 넣음.
- GPT에게 다시 질문
UserResponseDto에 Getter를 안 넣었어. UserResponseDto에서 Getter로 받아오는 속성이 없는데 꼭 필요한 거야? 이유는?- GPT 답변
결론부터 말하자면: 네, @Getter는 꼭 필요합니다. 왜냐하면, Spring에서 @RestController가 리턴한 객체(UserResponseDto)를 **JSON으로 변환하는 과정(Jackson 직렬화)**에서 객체의 값을 읽기 위해 Getter 메서드를 호출하기 때문입니다.4. 결론
- 코드를 짤 때 명시적으로 ResponseDto에서 값을 받아오지 않지만, ResponseDto를 Json으로 변환하는 과정에서 Getter로 ResponseDto를 조회한다. 그러므로 ResponseDto에도 Getter가 필수!
이슈 2. User Id로 조회가 안됨
- 아래와 같은 에러 메시지가 나옴
2025-04-03T19:59:05.088+09:00 ERROR 38584 --- [schedule] [nio-8080-exec-8] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: org.springframework.dao.InvalidDataAccessApiUsageException: The given id must not be null] with root cause
- ID가 Null이면 안된다는 말. Postman에서 생성하고 조회도 했는데, 왜 Id가 Null이지?
- 전체 조회 시에는 생성한 유저 정보가 나옴.
해결방법
1. GPT에게 질문
이 에러가 난 이유는? (위의 코드 복사)2. 답변
에러 메시지 The given id must not be null은 Spring Data JPA에서 ID 값이 null인 상태로 DB를 조회하려고 했기 때문에 발생한 에러예요. 🧠 에러 원인 요약 findById(null) 또는 deleteById(null) 같은 메서드가 호출되었고, 이때 넘겨준 ID 값이 null이었기 때문에 JPA가 "null ID로 조회할 수 없어!" 라고 오류를 낸 거예요. 🔍 주로 발생하는 케이스 1. @RequestBody 또는 @PathVariable로 ID를 받는데, 실제 요청에서 ID가 누락된 경우 2. 객체를 저장한 직후, 그 객체의 ID가 null인 상태인데 getId() 해서 다시 조회하려고 한 경우 3. 테스트나 컨트롤러 호출 시, DTO나 Entity에 ID를 설정하지 않고 JPA에 전달한 경우3. 상황 확인
- 주로 발생하는 케이스 2번인 것 같다. 객체를 저장한 직후 조회하려는 경우가 아닐까?
- 추가 질문 & 답변
User user = new User(requestDto); // ID는 아직 null userRepository.save(user); // 저장했지만... Long id = user.getId(); // ❌ 여기서 getId() 하면 아직 null일 수 있음!
- 생성 시 save 대신 saveAndFlush를 하거나, 저장된 Entity를 반환하고 반환 받은 Entity를 사용하기
- 근데, 후자의 경우, 지금도 이미 이렇게 하고 있는데 오류가 난 것을 보면 userRepository에 id가 안 넘어가는 상황인 것 같은데..
- 아.. 진짜 바보다. 에러 코드를 자세히 살펴보니, Service() 단에서 에러가 났고, Service 단에 id가 안 넘어갔다. 그럼 전 단계인 Controller로 가보니, 메서드에 입력 값을 (Long id)로 넣어놨다... (@PathVariable Long id)로 해야 URL에 적은 id 값을 받는데... 이런... 그래도 잘 찾았다.
4. 결론
- 이런 실수는 충분히 할 수 있다. 에러 코드를 잘 읽어보고 디버깅 하자!
이슈 3
- Schedule Update 시 입력한 username이 달라도 업데이트가 됨(Lv2). 대신 이름은 그대로
- 아마 Schedule의 속성의 username이 schedule.getUser().getUsername()으로 불러와서, schedule에 저장된 유저(user_id로 매칭) 이 user가 변경되지 않으니까 이름도 변경되지 않는 것이 아닐까.
- 그렇다면, RequestDto도 이제 분리해줘야하지 않을까? 회원가입과 로그인 과정을 넣어서, 로그인을 통과한 유저만 본인이 작성한 글을 수정하거나 삭제할 수 있도록 해야할 것 같다. Filter로 chain을 만들어서, (User/Schedule) update, delete는 이 chain을 통과한 유저만 할 수 있도록. 이걸 구현해보자.
- 로그인 했음에도 세션 유지가 안 되어 생성/조회 모든 기능이 안됨
해결방법
1. GPT에게 질문
user controller 로직을 아래와 같이 구현했는데, postman을 이용해 login 호출 이후 RUD 요청을 처리하려고 할 때 로그인해달라는 메시지가 나와. 세션이 유지되지 않는 것 같은데 무슨 문제인지 확인해줄 수 있어?2. 답변
- JSESSIONID를 추가해야한다는데.. 근데 강의자료엔 아래와 같이 나와 있다.
- Sevlet으로 HttpSession을 생성하면 JESSIONID가 상성된다는데..
- 위와 같은 원인도 있다고 한다. 설정을 확인하고 어떻게 해야하는지 추가 질문
- build.gradle에서 starter-security를 사용중인지 확인하고 stateless 부분을 바꿔야 한다는데...
3. 상황 확인
- 여러 차례 핑퐁을 거친 결과... LoginFilter에서 session.getAttribute("sessionKey" = null) 이렇게 받고 있었는데, 이게 아니라, Const.LOGIN_USER로 받아줘야 한다. 강의노트에서 "sessionKey"로 되어 있어 그대로 썼더니 여기서 null이 발생한 듯. UserController 클래스에서 session.setAttribute(Const.LOGIN_USER, loginUser)로 받고 있으므로, getAttribute에서도 Const.LOGIN_USER로 똑같이 받았어야 함! 아마도 강의노트에는 setAttribute에 ("sessionKey", 삐리리) 이렇게 되어 있어 정상적으로 동작한 것이 아닐까 하는 추측. 확인해보자.
- 엥? 강의노트에도 Const.LOGIN_USER로 setAttribute/getAttribute 하고 있다. sessionKey 어디에서 나온지 아는 분? 어쩌면 GPT가 알려줬을지도...
4. 결론
- Cookie와 Session을 설정하는 방법을 제대로 이해할 필요가 있겠다. 문법을 이해하지 못하니 코드 줄마다 어떤 역할을 해주는 건지 모르고, 더 심각한 것은 zero부터 새롭게 짜야할 때 생각이 날리 만무하다는 점이다.
이슈 4
- Postman 테스트 시 로그인이 안 돼서 유저 생성을 여러 번 했는데, 그 이후 로그인도 안됨 -> 중복된 id, pw가 여러 개여서 그런 듯! 이건 예외처리를 해줘야할 것 같다.
해결방법
1. GPT에게 질문
중복로그인 문제는 singup 시 DB에 같은 email이 있는지 조회하도록 Service, Repository에 코드를 추가.2. 답변
<Service 클래스> public UserResponseDto register(UserRequestDto requestDto) { // 💡 이메일 중복 체크 if (userRepository.findUserByEmail(requestDto.getEmail()).isPresent()) { throw new ResponseStatusException(HttpStatus.CONFLICT, "이미 등록된 이메일입니다."); } <Repository 클래스> // 이메일로 유저 검색 (중복 체크용) Optional<User> findUserByEmail(String email); <Entity 클래스> email 필드에 @Column(unique=true) 어노테이션 추가3. 상황 확인
처리하니 중복 로그인 시 Conflict 메시지가 정상적으로 호출 됨!4. 결론
- 예외 처리가 정말 중요하구나.. Lv4에서도 로그인 시 이메일과 비밀번호가 일치하지 않을 경우 HTTP Status code 401을 반환하라고 했는데, 이것도 예외처리를 제대로 해줘야 할 것 같다.
- 예외처리는 박성원 튜터님께서 발제시간에 ExceptionHandler를 포함한 내용을 알려주셨는데 막상 적용하려니 어떻게 해야할지 감이 오지 않는다.
- 복습과 연습, 삽질.. 반복하자.
이슈 5
- 유저 1, 유저 2를 생성한 이후 유저 2로 로그인하고, 스케줄 생성 시 유저id를 1로 설정하면 스케줄이 생성된다. 정상적인 케이스라면, 로그인에 성공한 유저만 본인의 유저 id로 게시글을 작성할 수 있어야 한다.
해결 방법
1. 생각해보기
일단, 생각나는 거 막 던져보기
- ScheduleController의 URL을 Login의 하위로 둔다. > 구조가 복잡해질 것 같다. Schedule Controller 클래스에서 User
- 로그인한 유저의 세션 정보에서 id값을 받아오고 이 id를 createSchedule 메서드의 입력 id로 넣어준다. > 이게 현실적인 방법일 것 같은데. 필터를 거쳐 Controller로 넘어오니, 넘어온 httpservlet에서 id를 갖고 와 넣어주면 되는 일이 아닐까?
2. GPT한테 물어보기
아래 내용에 대해 피드백 해줄 수 있어? 사고력을 키울 수 있게 이끌어주는 피드백을 주면 좋겠어. (위의 정리 내용을 전달함)3. 답변
- 와 Dr.G 미쳤다. 완전 선생님인데? 일단 세션에서 정보를 갖고 온다는 접근은 잘 한 것 같다! 더 나아가, 사고력을 키우는 질문 1을 보면 사용자의 ID를 Body나 Param으로 넘기지 못하게 해야한다고 한다! 그 이유는, 클라이언트에서 보내는 데이터는 누구나 조작할 수 있기 때문이라고! Postman에서도 id:1, id:2와 같이 맘대로 바꿔서 요청할 수 있다!
- 그래서 서버는 세션(또는 토큰)에 저장된 값만을 "유일한 신뢰할 수 있는 유저 정보"로 사용해야 한다.
- 생각했던 두 번째 방법이 옳은 방법이자 유일한 신뢰할 수 있는 방법이었네!
- 그럼, 세션에서 ID만 꺼내면 될까? No. 세션에서 유저 Entity를 갖고올 수 있으면 Best이지 않을까? 지금은 ID로 조회하지만, 나중에는 username이나, password를 비교하거나 Entity의 필드를 사용해야 하는 경우가 있을 수 있다. 그러니 Entity를 꺼낼 수 있으면 최상일 것 같다.
- GPT도 UserResponseDto나 User 전체를 세션에 넣어두는게 편하다고! 이유는 생각했던 것과 비슷하다.
- 그럼, 이제 해야할 일은, Login한 세션에서 유저 정보를 갖고 오는 일! 세션에서 Login을 하면 Repository에서 User를 조회할 수 있었을테고, 그러면 조회한 User 정보를 세션에 담아줄 수 있고, 이 정보를 세션에서 꺼내올 수 있다면 문제는 해결된다.
- 세션에서 User를 꺼내서, 이 userId와 수정하려는 게시글의 userId가 다르면 권한없음, 같으면 수정을 해주면 된다!
4. 상황 확인
- 해결! Service 단에서 validate 로직을 추가했다. 스케줄의 수정/삭제, 유저의 수정/삭제 시 session의 유저 id와 request한 id로 조회한 유저 id가 동일한지 검증하고, 동일하지 않으면 Forbidden Error를 Throw하게 했다.
- 계정 1, 2로 회원가입 -> 1로 로그인 -> 1로 게시글 작성 -> 1로그아웃 -> 2로그인 -> 2로 게시글 수정 시도 -> forbidden / 2로 1유저 정보 수정 시도 -> forbidden 굿!
5. 결론
- 뭔가 이렇게 동작하면 안될 것 같은데.. 싶은 부분이 걸리면 파고들어갈 필요가 있다. 요구사항에 명시되어 있지 않다고 해도 비즈니스 로직 상 더 합리적이라고 판단되면, 그리고 그것이 배움의 범위를 크게 벗어나지 않으면 시도해보자! 복잡해 보이더라도 길이 있다!