문제토스페이먼츠 API를 이용하던 중, 응답으로 주던 날짜 형식 "2024-10-02T21:16:13+09:00" 이 LocalDateTime으로 파싱이 되지 않았다. 해결 OffsetDateTime을 이용해서 파싱 할 수 있었다. 1. LocalDateTime 파싱 에러 발생 @Test@DisplayName("LocalDateTime 파싱 - 에러남")public void testLocalDateTimeParseException() { // given String rawTime = "2024-10-02T21:16:13+09:00"; // when & then assertThatThrownBy(() -> LocalDateTime.parse(rawTime)) .isIns..
TIL ✍️
문제간편결제를 구현하기 위해 6자리 숫자 비밀번호를 도입했다. 근데 평문으로 저장할 순 없으니 암호화를 해야 하는데, 스프링 시큐리티까지는 필요 없이 비밀번호 암호화만 하면 되었다. 해결 dependencies { // ... // spring security crypto implementation 'org.springframework.security:spring-security-crypto' // 여기 !!! // ...}spring-security-crypto 라이브러리를 의존한다. import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configur..
문제결제 엔티티에서 결제 승인 메서드를 실행하면 결제 승인 시간에 자동으로 현재 시간으로 넣어준다. 자동으로 넣어준 LocalDateTIme을 어떻게 테스트할지 궁금했는데, 특정 시간과 가까운지 테스트하는 코드가 있었다.상황 /** * 결제 승인 */public void approve() { this.status = PaymentStatus.APPROVED; this.approvedAt = LocalDateTime.now(); // 여기 !!!}결제 승인 메서드 실행 시 approvedAt에 현재 시간을 넣어준다.해결 전체 테스트 코드import static org.assertj.core.api.Assertions.assertThat;// ... @Test@DisplayName("결제 성공")..
요약eclipse-temurin:17-jre-alpine으로 이미지 굽자.상황어느날 문득, 서버에서 배포할 때 이미 빌드되어 jar 파일만 실행한다면, JDK가 아닌 JRE만 있어도 되는 거 아닌가? 하는 생각이 들었다. 요즘 배포할 때는 도커 이미지로 구워서 띄워버려서, JRE를 사용하면 용량을 더 줄일 수 있을 것 같아서 한번 알아봤다. openjdk를 우선으로 찾아보았는데 내 서치 실력이 부족한 건지 17-jre만 있는 것은 찾을 수가 없어서, temurin으로 테스트해보았다. 예상대로 17-JDK (419.47 MB) > 17-JDK-alpine (335.97 MB) > 17-JRE (262.53 MB) > 17-JRE-alpine (185.34 MB) 순으로 용량이 줄어들었다. JDK에서 ..
문제우리는 JPA 엔티티를 Ksuid라고 하는 고유 식별자를 사용하기로 했다. UUID 같은거다. 생성시간 기반의 20byte 고유 식별자로, 시간순으로 정렬이 가능해서 인덱싱의 이점을 누리면서도 랜덤값도 포함되어 중복 가능성이 거의 없으며, 길이도 짧다. 따라서 엔티티를 저장할 때 id를 넣어서 생성하도록 했다. @Transactionalpublic S save(S entity) { Assert.notNull(entity, "Entity must not be null"); if (this.entityInformation.isNew(entity)) { this.entityManager.persist(entity); return entity; } else {..
문제멀티 모듈 구조에서 JpaRepository 빈을 읽어오지 못하는 문제가 있었다. 상황우리는 멀티 모듈을 채택했고, 스프링 앱, 도메인 코어, 데이터베이스 모듈로 3개를 분리했다. 스프링 앱에서 실행 시, 데이터베이스 모듈의 JpaConfig 설정을 읽어오지 못해서 도메인 코어의 repository에 JpaRepository를 빈이 없다고 주입을 못해주고 있었다. 간단하게 현제 문제인 것들만 정리하자면모듈payment-core : 결제 도메인의 핵심 부분 (서비스, 도메인, 리포지토리 포함)모듈 위치 : service:payment:core 패키지 시작점 : radiata.service.payment.corepayment-api : 결제 도메인의 외부 요청 부분 (스프링 애플리케이션, 컨트롤러, ..
문제 : 카프카 직렬화/역직렬화 처리 중 만난 에러들 하도 많이 만나서 일단 생각나는 것만 적고.. 에러 1 : 객체로 요청 및 응답받고 싶으면 Value의 시리얼라이저를 Json으로 하기.물론 문자열로도 가능하긴 한데, 요청/응답마다 ObjectMapper로 직렬화/역직렬화하기보다, 카프카에서도 JsonSerializer를 제공해 주는데 굳이 문자열로 쓸 필요는 없을 것 같다. 또 컴파일 때 요청 보낼 객체의 타입검사를 해주기도 하고. import ex.application.order.message.DeliveryMessage;import java.util.Map;import org.apache.kafka.clients.producer.ProducerConfig;import org.apache...
값객체를 엔티티의 식별자에도 사용하기 시작했다. @Getter@Embeddable@EqualsAndHashCode@NoArgsConstructor(access = AccessLevel.PROTECTED)public class HubId implements Serializable { // JPA 식별자 타입은 Serializable 구현해야 함 @Column(name = "id") private UUID id; public static HubId of(UUID id) { HubId hubId = new HubId(); hubId.id = id; return hubId; } public static HubId ofRandom() { ..
이번 프로젝트에서 DDD 개념을 일부 도입해 보면서 값객체를 시도해 볼 수 있는 부분에 적용을 해보았다. 인터넷에 유명한 Money나 Address는 당연히 구현해봤고, 아래는 그 외에 잘 구현했다고 생각되는 것을 적어봤다. @Getter@Embeddable@EqualsAndHashCode@NoArgsConstructor(access = AccessLevel.PROTECTED)public class Rating { private static final int MIN_SCORE = 1; private static final int MAX_SCORE = 5; private Integer score; public Rating(int score) { if (!isScoreInR..