[JPA,SpringBoot] 프로젝트 KnockKnock - 개발일지 1130

Hyebin Lee·2021년 11월 30일
0

knockknock 개발일지

목록 보기
2/29
post-thumbnail

✔오늘의 계획과 달성

  1. 각 Entity에 해당하는 Service와 Service Request Form 구현하기
  2. 구현한 부분 Test 코드 작성하고 Test 통과하기
  3. 가능하면,, Android 연결이랑 Android view에서 데이터 어떻게 출력되는지 한 번 찍어보기

오늘의 이슈

  1. JPAQueryFactory 의존성 주입
    : 'com.querydsl.jpa.impl.jpaqueryfactory' that could not be found. 에러
  2. QueryDsl문 작성 시 null 값 return Exception 설정 필요
    : emptyresultdataaccessexception: no entity found for query
    :nested exception is javax.persistence.NoResultException: No entity found for query 에러
  3. Service 와 Controller 의 실질적 차이 공부
  4. RequestForm 형태는 Controller에서/Service에서 받나?

1. JPAQueryFactory 의존성 주입

.impl.jpaqueryfactory는 Bean 등록이 자동으로 되지 않아서 수동으로 해주어야 한다.
따라서 다음과 같은 방법으로 jpaqueryfactory를 bean으로 등록할 수 있다.

package jpaproject.knockknock;

import com.querydsl.jpa.impl.JPAQueryFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

@Configuration
public class KnockKnockConfig {

    @PersistenceContext
    private EntityManager entityManager;

    @Bean
    public JPAQueryFactory jpaQueryFactory(){
        return new JPAQueryFactory(entityManager);
    }
}

@Configuration 을 안써본지 오래돼서 검색해봤는데
주로 이 어노테이션은 위와 같이 Bean을 수동으로 등록해줄 때 쓴다고 한다.

본래 영속성 컨텍스트로 EntityManager는 이렇게 따로 등록해주지 않아도 되지만
여기서는 수동으로 JPAQueryFactory 등록할 때 EntityManager가 필요해서 별도로 주입 받았다.

수동으로 QueryDSL 코드 짤 때 까먹지 말고 JPAQueryFactory Bean 등록하자!

Test 구동할 때 필요한 경우에도 따로 TestConfig Class 만들어서 bean 등록해주자!

2. 조회 결과로 null이 출력될 수도 있는 Query문의 Exception 처리

InitService에 초기 데이터를 설정하고 코드를 돌리려는데

: emptyresultdataaccessexception: no entity found for query
:nested exception is javax.persistence.NoResultException: No entity found for query

다음과 같은 오류 발생,,
오류 코드가 장황하게 길었지만 SpringBoot는 꽤나 오류를 친절하게 설명해주는 프레임워크이기 때문에 하나하나 꼼꼼하게 읽다보면 문제가 나는 코드를 찾아갈 수 있다.

나름의 꿀팁이 있다면,, 문제나는 코드 하이퍼링크 되어있는 부분을 찾을 때 기존의 SpringBoot Class들 말고 내가 만든 Class 부분 링크를 찾아가면 된다.. 당연한 얘기일 수도 있지만 아직 초반이라 이런 것들 하나하나가 개발 오류를 잡는데 도움이 되었다..ㅎㅎ

여튼 그렇게 찾아간 문제의 코드는 이것이였다.

public HashTag findByTag(String tag){
        return em.createQuery("select h from HashTag h " +
                "where h.tag = :tag",HashTag.class)
                .setParameter("tag",tag)
                .getSingleResult();
                }
    

이게 왜 문제가 되었냐 하면 이 메소드는 일단 찾는 tag와 일치하는 HashTag를 return 하는 메소드고,.. 따라서 찾는 tag와 일치하는 HashTag가 없을 수도 있다.
심지어 Service 부분 구현할 때는 findByTag해서 값이 null이면 어떻게 할건지 코드까지 짜놨으니,, 당연히 오류가 나지...

이렇게 특정 조건에 해당하는 Entity를 반환하도록 하는 조회 메소드는
웬만하면 전부 Exception 처리를 미리 해두는 것이 좋다
만약에 조건에 해당하는 Entity가 없을 경우 null값을 리턴한다든지의 Exception을 처리해주자!

Exception을 처리하면 다음과 같이 코드를 수정할 수 있다.

 public HashTag findByTag(String tag){
        try{
        return em.createQuery("select h from HashTag h " +
                "where h.tag = :tag",HashTag.class)
                .setParameter("tag",tag)
                .getSingleResult();}
        catch(NoResultException nre){
            return null;
        }
    }

Service 와 Controller 의 실질적 차이

이와 관련된 내용은 따로 공부해서 SpringBootTIL에 적어두었다.

간단하게 정리해보자면 Service에서 대부분의 핵심 API 기능을 구현하고
Controller에서는 UI 에 따라 특수하게 적용되는 기능이 아닌 경우
그냥 유저의 요청만 받으면 된다.
엔티티 객체 생성은 Service에서 하든 Controller에서 하든 상관 없어 보인다.

0개의 댓글