login 기능 구현 중 Service 클래스에서 해당 정보를 찾지 못한 경우(=로그인 할 때 입력한 비밀번호나 이메일이 틀린 경우) null을 return 해야하는 경우가 생김.
문제는 여기서 내가 return: responseDto가 필요로하는 필드값을 불러오기 위해 get메소드를 사용해야하고, null객체에서 메소드를 호출하려하니 에러가 발생하는 것.
public LoginResponseDto login(String email, String password) {
User user = userRepository.findByEmailAndPassword(email, password);
Optional<User> ou = Optional.ofNullable(user);
if(ou.isEmpty()){
throw new ResponseStatusException(HttpStatus.UNAUTHORIZED,"이메일과 비밀번호가 일치하지 않습니다");
}
return new LoginResponseDto(user.getId());
특강에서 배운 대로 null값을 효율적으로 처리하기 위해 Optional을 사용.
DB에서 찾은 객체를 Optional로 감싼 후 null이면 에러 401 처리, null이 아니면 ResponsDto로 return 반환
LoginResponseDto responseDto = userService.login(dto.getEmail(), dto.getPassword());
Long userId = responseDto.getUserId();
Optional<LoginResponseDto> value= Optional.ofNullable(responseDto);
if (userId==null) {<-여기가 문제.
return ResponseEntity
.status(HttpStatus.UNAUTHORIZED)
.body("로그인에 실패했습니다.");
}``````
실행해보니 service의 login메소드는 정상적으로 작동해 에러를 의도대로 처리했지만, 에러가 발생한 후 controller가 돌아가지 않는 문제가 발생.
controller에서 받은 객체에서 null인 경우를 처리하는 부분이 있는데, service에서 null을 미리 에러 처리 하니 코드 실행이 되질 않는 것.
service 클래스에서 Optional 에러 처리 부분을 지우니, 그냥 에러 처리가 안될 뿐, 실행결과는 서버에 문제가 있다는 에러 500이 뜨고 controller 클래스는 실행이 안됨. 고민하다가 return값을 null로 지정하고, controller에서 에러 처리 하기로 함.
Service.class
public LoginResponseDto login(String email, String password) {
User user = userRepository.findByEmailAndPassword(email, password);
Optional<User> ou = Optional.ofNullable(user);
if(ou.isEmpty()){
return null;
}
return new LoginResponseDto(user.getId());
Controller.class
LoginResponseDto responseDto = userService.login(dto.getEmail(), dto.getPassword());
Optional<LoginResponseDto> value = Optional.ofNullable(responseDto);
if (!value.isPresent()) {//null값이면 로그인 실패 메세지를 띄우기
return ResponseEntity
.status(HttpStatus.UNAUTHORIZED)
.body("로그인에 실패했습니다.");
} else {//로그인 성공
service에서는 객체가 null인 경우 null을 return 했고,
controller에서는 return 한 responseDto를 Optional로 다시 감싸 null값이면 에러 401을 띄우도록 만듬. 다행히도 제대로 작동함을 확인.
login 성공 후 JSESSIONID를 생성하는 것까지 확인했으나, 다른 URL로 이동해 LoginFilter의 로그인 검사여부에서 자꾸 실패해 에러메세지가 뜸.
if (session == null|| session.getAttribute("세션값") == null) {
throw new RuntimeException("로그인 해주세요.");
}``````
HttpRequest가 null인지 여부도 확인해봤지만 제대로 동작했고,
결국 튜터님께 여쭤보니 결과는 허무하게도 if문의 session.getAttribute("세션값")==null에 걸려서 JSESSIONID가 있음에도 로그인을 하라는 에러메세지가 뜬 것.
애초에 나는 setAttribute로 session에 데이터를 저장한 적이 없었는데,
강의 코드를 보고 개념이 부족한 상태에서 코드를 따라치니 이런 허무한 결과가 발생.
결론은 코드 한 줄도 다 의도가 있으니, 공부를 열심히 해야겠다는 것밖에 안 나옴.
if (session == null) {
throw new RuntimeException("로그인 해주세요.");
}``````
간단하게 해결
requestparam 입력에서 page=1&size=n으로 하면 일정이 1번이 아니라 2번부터 뜨는 문제가 발생
public ResponseEntity<Page<PageResponseDto>> pageInfo(@RequestParam (defaultValue = "1") int page,
@RequestParam(defaultValue = "10") int size){
Pageable pageable= PageRequest.of(page-1,size);```
int page 의 defaultValue="0" -> defaultValue="1"
PageRequest.of(page, size)-> PageRequest.of(page-1, size) 로 설정해서 입력은 1이지만 실제 메소드에서는 0으로 동작하게 만듬.
url에 page=0을 입력하면 page 메소드에서는 page=-1이 되므로 에러 발생
1부터 제대로 동작
Repository에서 메소드명이 기존 JDBC에서 이용하던 쿼리임을 배우고, 페이지에서
일정은 수정일 기준으로 내림차순, 댓글은 객체가 아니라 갯수로 찾도록 메소드명 작성.
처음엔 댓글 repository에서 countByScheduleIdOrderByModifiedAtDesc로 작성했으나, 댓글 수정일과 일정 수정일은 아무런 관련이 없다는 실수를 깨닫고, 둘을 분리하기로 함.
댓글 repository는 long countByScheduleId(Long scheduleId) 로 일정id를 매개변수로 받아 댓글 갯수를 long으로 반환.
일정 repository는 처음에 Page findAllOrderByModifiedAtDesc (Pageable pageable)로 작성했으나 동작 안됨. 검색해보니 orderby앞에 by를 붙여야 해서 수정.
ScheduleRepository.class
Page<Schedule> findAllByOrderByModifiedAtDesc (Pageable pageable);
CommentRepository.class
Long countByScheduleId(Long scheduleId);