전체 글
-
ObjectMapper LocalTime등 날짜시간 타입 매핑 실패 해결법Spring/Trouble Shooting 2024. 1. 13. 01:21
문제 상황 테스트 코드 작성중에 void createOperatingTime() throws Exception { //given AnimalHospital savedAnimalHospital = getSavedAnimalHospital(); List requests = new ArrayList(); for (DayOfWeekStatus value : DayOfWeekStatus.values()) { HospitalOperationTimeCreateRequest hospitalOperationTimeCreateRequest = HospitalOperationTimeCreateRequest.builder() .dayOfWeekStatus(value.name()) .startTime(LocalTime.of(1..
-
QueryDsl 거리 검색 쿼리 최적화Spring/Trouble Shooting 2023. 12. 9. 16:20
개요 사이드 프로젝트를 진행하면서 검색 API 구현을 담당하였다. 개인 프로젝트등에서는 단순 키워드를 통한 검색을 구현 하였지만 본 프로젝트에서는 정보 제공의 목적으로 거리를 계산해서 제공을 해야하는 상황이 발생했다. 이를 해결하는 과정을 기록으로 남겨두어 나중에 비슷한 상황이 발생하면 다시 참고해보는 용도로 해당 글을 작성한다. 문제 요구사항 해당 문제 상황에서 고려되는 사항은 다음 두 가지가 있었다. 유저의 위도, 경도가 주어지면 해당 건물에 대한 거리가 출력되어야한다. 유저의 위도, 경도가 주어지면 거리순 정렬이 되어야한다. 문제 인식 다른 요구사항에는 적절하게 구현이 완성된 상태였다. 기본적인 QueryDsl을 사용해서 값만 매칭시켜두면 해결되는 문제였기에 큰 어려움은 없었다. 다만 해당 문제를 ..
-
ReflectionTestUtils를 활용한 단위 테스트, 객체의 ID 설정하기Spring/Trouble Shooting 2023. 11. 19. 01:21
문제 상황 질문의 번호와 유저의 번호를 받고, 질문의 작성자 번호가 유저의 번호와 같다면 삭제하는 과정이다. public void deleteById(Long questionId, Long memberId) { Question question = findById(questionId); if (validateQuestionWriter(memberId, question)) { questionRepository.deleteById(questionId); } } private Boolean validateQuestionWriter(Long memberId, Question question) { return question.getMember().getId().equals(memberId); } 그다지 이해하기 어..
-
QueryDsl 페이징 최적화 PageImpl vs PageableExecutionUtils 차이Spring/Study 2023. 11. 14. 01:07
PageImpl vs PageableExecutionUtils return PageableExecutionUtils.getPage(result, pageable, countQuery::fetchOne); return new PageImpl(result, pageable, count); 둘의 차이는 무엇일까? 상황 예시 24개의 content가 존재한다고 가정해보자 PageSize = 10 이라고 하면 페이지는 1,2,3 페이지가 존재하게 된다. 1, 2 페이지에서는 10개의 content가 채워져서 페이지 result가 반환되기 때문에 PageImpl, PageableExecutionUtils 둘 다 count 쿼리가 발생한다. 그런데 3페이지 마지막 페이지에서는 차이가 발생한다. 3페이지에서는 4개의 ..
-
Spring Test 환경에서 Audit 적용이 안될 때Spring/Trouble Shooting 2023. 11. 13. 17:13
상황 도메인의 설계 구조를 보고 가자 @Getter @Entity @NoArgsConstructor(access = AccessLevel.PROTECTED) @EntityListeners(AuditingEntityListener.class) public class Question { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; //... @Embedded private AuditEntity auditEntity; //... @Builder public Question( //.. ) //... this.auditEntity = new AuditEntity(); } } Question이라는 도메인에 AuditEntity를 ..
-
Facade 패턴을 통해 코드의 복잡함을 숨겨서 간단해 보이도록 해보자Design Patterns 2023. 11. 8. 17:02
들어가기 전 이전 글 이전 과정은 뇌를 빼고 작성했던 코드를 리팩토링 하는 과정을 거쳐봤다. 해당 글에서는 3가지 일을 맡고 계신 비즈니스 로직의 한 메소드를 디자인 패턴을 통해 간단하게 보이도록 해줄 예정이다. Facade 디자인 패턴 복잡한 로직을 하나로 합쳐서 외부에서는 간단하게 사용할 수 있도록 만드는 것이다. 즉 복잡한 로직을 하나의 인터페이스로 정리해 주는 것이다. 장점은? 복잡한 시스템을 단순화하여 클라이언트가 쉽게 이해하고 사용할 수 있다. 각 도메인 로직에 대한 독립성을 높여 유지보수와 확장성을 향상시킬 수 있다. 도메인 서비스 간의 느슨한 결합을 통해 시스템 변경에 대한 클라이언트의 영향을 최소화한다. 단점은? Facade 패턴을 구현한 클래스가 너무 많은 책임을 가지게 되면 복잡성이 ..
-
Docker 컨테이너 환경에서 Eureka Client 등록시 ip 문제Spring/Trouble Shooting 2023. 11. 7. 00:41
문제 상황 Eureka 클라이언트를 등록하고 Spring Cloud Gateway를 통해 로드 밸런싱 처리를 하도록 설정해뒀다. 하지만 로드밸런싱 처리는 되지 않았고 직접 ip 주소를 통해 요청을 할 때는 정상적으로 요청이 전달되고, Eureka Server에 등록된 클라이언트의 목록에는 이상이 없었다. 원인은? 문제는 Eureka Client가 등록될 때 클라이언트들이 외부 ip 기준으로 등록되는 것이 아니라, 내부 ip를 기준으로 등록되어 문제가 발생하는 것이였다. 원인은 배포 환경을 Docker를 통해 진행했는데, Eureka Client의 경우 컨테이너 환경에서 배포가 될 경우 알아서 실제 배포되는 ip로 등록되는 것이 아닌 내부 ip를 기준으로 등록되는 것이였다. 알아낸 방법 이를 알아낸 방법은..
-
H2-Console 접속 문제 해결Spring/Trouble Shooting 2023. 11. 6. 20:35
문제 상황 위와 같이 내장 H2 DB를 사용하여 접속하려 하는데 문제가 발생했다. 개발자 도구를 통해서 확인해보면X-Frame-Options이 문제인 것을 알 수있다. 해결 방법 public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { return http ... .headers(headers -> headers.frameOptions(FrameOptionsConfig::disable)) ... .build(); } 최근 Security 버전이 변경되면서 함수형으로 선언하도록 바뀌었다. 따라서 위와 같이 선언해줘야 한다.