본문 바로가기

Spring9

[JPA] Hibernate 6.1 @OneToMany 일대다 조회 시 DISTINCT 자동 적용 배경 스프링 부트 3.0 부터 Hibernate 6.1로 기준이 되어 해당 버전을 사용하고 있었다. 일대다에서 fetch join을 하면 중복 row(영한님 말로 - 뻥튀기)가 생긴다. 해결책으로 JSQL의 distinct를 적용하게되는데 SQL distinct와는 다르다. SQL의 distinct는 row의 값이 모두 일치해야 제거가 된다. JPQL에서 distinct를 하면 SQL distinct 기능 + 중복 엔티티 제거하는 기능을 한다. 하지만 Hibernate 6.0부터는 HQL(JPQL의 구현체)에 DISTINCT가 자동 적용된다. https://github.com/hibernate/hibernate-orm/blob/6.0/migration-guide.adoc#distinct 프로젝트 테스트를.. 2023. 1. 25.
[JWT] JWT에 대해서 JWT (Json Web Token) 클라이언트와 서버간에 정보를 JSON으로 안전하게 전송하기 위한 간결하고 독립적인 방법을 정의하는 개방형 표준이다. 클라이언트가 서버에 요청할 때 토큰을 보내어 인증하는 방법에서 쓰인다. 이때 서버는 DB를 조회하지 않고 JWT가 유효한지 알 수 있기 때문에 토큰을 무상태(stateless)로 검증할 수 있다. https://jwt.io/introduction 특징 stateless 클라이언트가 로그인하면 서버는 JWT를 클라이언트에 보내고 클라이언트는 이 토큰을 저장한다. 이후 요청 시에 이 토큰을 함께 서버에 보내게 된다. 서버는 따로 토큰을 저장하지 않아도 되기때문에 무상태 stateless를 할 수 있다. 무결성 JWT가 발급되고 나서 토큰의 내용이 변경되면 .. 2023. 1. 21.
[JPA] fetch join 적용하기 게시판 프로젝트에서 홈을 요청하면 게시글 리스트를 불러온다. 문제는 쿼리인데, 페이징 할 때마다 쿼리가 3개가 나간다 select 게시글 select 회원: 닉네임 조회 게시글 count: 페이징 뷰게시판 프로젝트에서 홈 화면에서 게시글을 불러온다. 문제는 쿼리인데, 페이징 할 때마다 쿼리가 3개가 나간다. 김영한님의 JPA 강의에서 들은 fetch join을 적용해보려 한다. fetch join 여러 엔티티를 한 번의 SQL로 가져오는 것이다. 내 상황에서는 게시글을 불러오고 회원을 불러왔는데 이제 한 번에 fetch join으로 가져온다는 것이다. 이렇게 되면 쿼리 한 번에 회원이 영속성 컨테스트에 처음부터 들어있기 때문에 성능 최적화에 좋다. JPQL과 나가는 SQL 쿼리는 이렇다. JPQL: se.. 2023. 1. 19.
스프링 BindingResult 에러 메시지 JSON으로 응답하기 스프링과 Thymeleaf를 사용하는 환경에서 유효성 검사로 @Validated와 BindingResult로 손쉽게 사용할 수 있다. 바인딩할 객체에 @NotEmpty같이 설정해둔 유효성에 대한 에러메시지를 자동으로 BindingResult에 담아주고 Thymeleaf가 이것을 꺼내어 메시지를 찾아준다. 이때 아래와 같이 설정해두면 에러 메시지를 똑똑하게 찾아준다. # DTO NotEmpty.userName = 사용자 이름을 입력해주세요 NotEmpty.email = 이메일을 입력해주세요 NotEmpty.password = 비밀번호를 입력해주세요 NotEmpty.passwordConfirm = 비밀번호 확인을 입력해주세요 NotEmpty = 빈 칸을 채워주세요 손쉽게 일관적인 에러 메시지를 보낼 수 있다.. 2023. 1. 17.
스프링 Thymeleaf에서 @ExceptionHandler 활용 로그인을 처리하는데 예외처리에서 문제가 생겼다. 로그인을 하게되면 service에서 repository를 불러와 아이디를 가지고 있는 사용자인지, 비밀번호가 맞는지를 체크하고 만약 실패하면 IllegalArgumentException을 던진다. @Transactional public Member login(LoginRequestDto dto) { Member member = memberRepository.findByLoginEmail(dto.getEmail()) .orElseThrow(() -> new IllegalArgumentException("해당 사용자가 없습니다.")); if (!dto.getPassword().equals(member.getPassword())) { throw new Illeg.. 2023. 1. 17.
Interface로 추상화하여 Enum 사용 @ExceptionHandler를 사용하여 예외 처리를 하고 클라이언트에게 ResponseEntity를 사용하여 보여줄 정보만 보내려고 한다. 이때 ExceptionResponse라는 것을 만들어서 이곳에 커스텀 Exception으로 만든 enum을 넘겨주려고 했다. 이 ExceptionResponse를 다른 곳에서 재사용하고 싶어 enum을 추상화하여 만들게 된 계기다. 코드 - https://github.com/delvering17/toy_board 로그인 요청을 받는데 정보가 없는 사용자이거나 비밀번호가 맞지 않을 때의 exception을 처리할 ExceptionHandler이다. @ExceptionHandler(LoginException.class) public ResponseEntity logi.. 2023. 1. 11.