기존의 프로젝트는 순수 jpa와 QueryDSL을 사용하여 레파지토리를 구현했다.
그러다보니 간단한 CRUD도 직접 구현해야하는데..! 영한쌤의 스프링 데이터 JPA 강의를 완독한 후 아 ..! 바꿔야겠다 싶었다.
그래서 바꿨다!
UserJpaRespository.java -> 기존의 순수 jpa 를 사용한 코드
@Repository @RequiredArgsConstructor public class UserJpaRepository { private final EntityManager em; private final JPAQueryFactory queryFactory; public Optional<User> findByUserId(String userId){ return em.createQuery("select u from User u where u.user_id = :user_id", User.class) .setParameter("user_id", userId) .getResultList() .stream().findAny(); } public User findUserById(String id){ return em.find(User.class, id); } public void saveUser(User user) { em.persist(user); } public Optional<User> findUserByCoupleCode(String coupleCode) { return em.createQuery("select u from User u where u.coupleCode = :coupleCode", User.class) .setParameter("coupleCode", coupleCode) .getResultList() .stream().findAny(); } }
UserRepository.java -> 스프링 데이터 JPA
public interface UserRepository extends JpaRepository<User, String> { Optional<User> findUserByCoupleCode(String coupleCode); }
와훙... ㅋㅋㅋ 기존 코드가 사실 많은 편이 아니긴 했지만 그래도 완전 대박 간결하게 줄었다.
UserRepository 를 보면 findUserByCoupleCode 그냥 메소드명으로 쿼리를 뽑아낼 수 있다! 기존에 em.createQuery... 해서 직접 쿼리 작성하고 하던 귀찮던 (?) 작업들을 그냥 한 줄로 요약시켜버린 것이다.
UserService.java
@Service @Transactional(readOnly = true) @RequiredArgsConstructor public class UserService { private final UserRepository userRepository; public User findUserByCoupleCode(String coupleCode) { return userRepository.findUserByCoupleCode(coupleCode).orElse(null); } }
서비스에서는 반환 타입이 Optional 이므로 orElse(null)로 처리해주는 방식을 택했다.
값이 없다면 그냥 null로 처리할 생각이기 때문에 ~
방식이 바뀌는 건 그렇게 어렵지는 않았고 그냥 오류가 없는지, 내가 정한 규칙과 잘 들어맞는지를 따져가며 리팩토링에 신경 써봤다.
이쯤에서 리팩토링할 부분에 대해 풀어보자면
내가 지켜야 할 원칙
1. Controller는 웹 전달만 하는 계층
비즈니스 로직은 서비스에서 처리할 수 있도록 하자.
2. Service 에서 DTO <-> Entity 변환의 역할을 맡도록 하자.
그렇지 않으면 LazyInitializationException 노출 위험이 커짐
트랜잭션 안에서 하이버네이트의 명령이 이루어질 수 있도록 하자.
3. 서비스 안에서 다른 서비스 호출 가능
캘린더에서 그룹조회를 원한다면 당연히 그룹서비스를 불러 호출
-> 이렇게 된다면 Service에서 중복코드가 사용될 가능성도 있다.
4. RequestDTO / ResponseDto 구분
요청과 응답 그리고 엔티티의 경계는 확실히 해두자.
암튼 수정했고 차근차근 올리도록 하겠다.