본문 바로가기
반응형

개발/Spring71

nested objectId serialize, deserialize 했을 때 값이 달라지는 이슈 해결하기 ObjectId 를 프로퍼티로 가지고 있는 class 를 serialize 한 후 deserialize 하면 값이 달라지는 현상이 일어난다. class RedisSerializerTest { @Test fun test() { val objectMapper = ObjectMapper() val serializer = Jackson2JsonRedisSerializer(ErrorExample::class.java) .also { it.setObjectMapper(objectMapper) } val id = ObjectId("6239341381210e5903548df7") val actual = ErrorExample(id) val serialize = serializer.serialize(actual) val.. 2022. 4. 23.
[Spring Batch] Chunk 기반의 Job 은 어떤 기준으로 작업을 끝낼까 ? 필자는 Spring Batch 를 이용하여 배치 프로그램을 만드는 업무를 시작하였다. 아래와 같은 동작을 하는 간단한 배치프로그램이었다. Reader 로 데이터읽기 Processor 로 데이터 처리하기 Writer 로 데이터 적재하기 굉장히 쉬울줄만 알았던 업무였으나 예상하지 못한 곳에서 막히고 말았다. Job 을 끝내야 하는데 어떤기준으로 끝나는지 알지 못했다. 그래서 Spring Batch 를 간단하게나마 분석하다가 알게된 내용을 공유하고자 이 글을 쓴다. Chunk 기반의 Job 은 별다른 설정을 하지 않는다면 SimpleChunkProvider 에 의해 동작하게 된다. SimpleChunkProvider.provider -> SimpleChunkProvider.read() -> SimpleChun.. 2021. 12. 29.
MongoDB 여러개의 Document 한번에 insert 하기 다수의 도큐먼트를 insert 할때 1개씩 넣어주는것보다 한번에 여러개를 넣어주는것이 효율적이다. 100개의 도큐먼트가 있다고 가정할때 100번의 네트워크 비용보다 1번의 네트워크 비용이 저렴하기 때문이다 MongoDB에는 다수의 Document를 한번에 저장할 수 있는 insertMany 라는 기능을 지원한다. Spring-data-mongo 에서는 insertMany 를이용하여 여러개의 Document를 한번에 저장할 수 있는 saveAll 이라는 Method 를 제공한다. 아래는 saveAll 메소드의 구현내용이다. 내용을 본다면 전부 새로운 Document 여야 saveAll 기능을 효과적으로 이용할 수 있다는 것을 확인할 수 있다. 주의하도록 하자! public List saveAll(Itera.. 2021. 8. 22.
[Spring] Kotlin 을 이용하여 MongoDB Query를 Type-safe 하게 작성하기 Spring data mongo 를 사용하게 되면 아래와 같은 방식으로 쿼리를 작성할 수 있다. Query() .addCriteria( Criteria.where("id").isEqualTo(1L) ) 이렇게 코딩하게 하게 된다면 문제점이 무엇일까 ? 크게 2가지로 나누어볼 수 있을 것이다. Type-safe 하지 않다. 만약 id가 Long 타입이 아니라 다른타입이라면 ? 바로 오류로 이어질 것이다. 오타로 인해 오류가 발생할 수 있다. id를 잘못하여 di 로 적는순간 오류로 이어질 것이다. id는 짧기에 이런일이 없겠지만 필드명이 길어지는 순간 위험도는 증가한다. Kotlin을 이용하여 Spring data mongo 를 이용한다면 이러한 문제점을 해결할 수 있다. org.springframewor.. 2021. 7. 30.
[Spring] Interceptor postHandle이 동작을 안해요. Interceptor 란 ? 특정요청에 대한 요청을 가로채서 수행하기 전, 수행한 후 추가적인 작업을 할 수 있도록 해주는 것 preHandle : 실제 handle 이 실행되기 전 수행 postHandle : 실제 handle 이 수행된 후 실행 afterCompletion : 요청이 완료된 후 실행 ( View Render 가 완료된 후 ) 적용 방법은 간단하다. 아래와 같은 Interceptor 를 만든 후 등록해준다. @Component class DemoInterceptor : HandlerInterceptor { override fun preHandle(request: HttpServletRequest, response: HttpServletResponse, handler: Any): Bool.. 2021. 7. 2.
[ReactiveCrudRepository] 데이터 삭제가 안되는 이슈 굉장히 어이없는 실수였지만 같은 이슈로 고생하시는 분이 계실까 공유합니다. ReactiveCrudRepository 를 학습할 때 발생할 수 있는 이슈입니다. 필자는 webflux 와 ReactiveMongoRepository 를 이용하여 간단한 게시판 예제를 만들어 보고자 했습니다. 입력까지는 잘 되었으나 Delete가 되지 않는 이슈가 발생하였습니다. 코드는 아래와 같습니다. 보고 무엇이 문제인지 아시는 분은 뒤로가기를 클릭하셔도 됩니다. suspend fun delete(deleteRequest: ReplyDeleteRequest) { val replyId = ObjectId(deleteRequest.replyId) val requestId = deleteRequest.requestId Mono.j.. 2021. 5. 7.
[Spring] @ContextConfiguration with Kotlin 기존에 @ContextConfiguration를 이용할 때는 아래와 같이 이용하였다. @ContextConfiguration(classes = {A.class, B.class}) 하지만 Kotlin 을 이용하여 위와 같이 작성하려고 하니 계속 에러가 났다 조금 찾아보니 Kotlin에서는 아래와같이 입력을 해야한다고 한다. @ContextConfiguration(classes = [DemoRouter::class, DemoHandler::class]) 2021. 4. 29.
[Spring data mongodb] 몽고DB에서 시퀀스를 이용하기 Sequence로 이용할 Document를 하나 정의한다.@Document class DatabaseSequence( @field:Id var id: String, var seq: Long ) { } Sequence를 생성하는 Creator를 정의한다.@Component class SequenceCreator( private var mongoTemplate: MongoTemplate ) { fun create(sequenceName: String): Long { val counter: DatabaseSequence = mongoTemplate.findAndModify( query(where("_id").`is`(sequenceName)), Update().inc("seq", 1), options().re.. 2021. 4. 29.
[Querydsl] SemanticException: right-hand operand of a binary operator was null Querydsl을 이용하여 아래와 같은 구문을 작성하였다. 실행 결과 SemanticException: right-hand operand of a binary operator was null 라는 오류를 만났고 30분~1시간 정도를 헤맸다. queryFactory .select(Projections.constructor(ProjectInfo.class , qProject.id, qProject.title, qProject.explain )) .from(qProject) .innerJoin(qProjectParticipants) .on(qProject.id.eq(qProjectParticipants.projectParticipantsId.project.id)) .where(qProjectParticipan.. 2021. 4. 12.
[Spring] @TestConfiguration Controller 테스트할 때 @SpringBootTest 보다는 @WebMvcTest 를 사용하면 조금 더 가벼운 테스트를 할 수 있다. 하지만 @WebMvcTest 는 @Component @Service @Repository 는 Scan 하지 않는다. 즉, 빈으로 등록되지 않는다는 것이다. 그렇기 때문에 Controller 테스트를 할 때 빈 등록이 안된다고 오류가 나거나 빈이 null 로 나오는 상황을 마주칠 수 있다. 이럴 때 사용할 수 있는 어노테이션이 @TestConfiguration 이다. 테스트 환경에서 필요한 빈들을 등록할 수 있도록 도와주는 어노테이션이다. 사용방법을 알아보도록 하겠다. 아래와같이 TestConfig.class 를 만들고 @TestConfiguration 어노테이션을 .. 2021. 4. 9.
[Spring Security] @WebMvcTest Error creating bean with name 'securityConfig' defined 필자의 사이드프로젝트에 Spring Security가 적용되어 있었다. Spring Security의 구조를 리팩토링 한 후에 테스트 케이스를 돌려보았는데 @WebMvcTest 가 붙어있는 테스트케이스들이 깨지기 시작하였다. SecurityConfig 를 생성하지 못한다는 에러를 뿜었다. 이번 리팩토링에서 변화한 것은 필드가 추가되었고 그에따른 생성자가 추가되었다는 것이다. @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { private final LoginAuthenticationProvider loginAuthenticationProvider; private final J.. 2021. 4. 5.
[Spring Security] Login 이 성공했을 때 후처리를 어떻게 할 수 있을까? Spring Security를 쓰면 Login이 손쉽게 구현할 수 있다. 하지만 우리는 Login이 성공했을 때 추가로 작업을 해줘야 하는 상황들이 많이 있다. 대표적인 예가 토큰을 발급해서 내려준다든지 쿠키나 헤더에 어떠한 값들을 세팅을 해줘야 할 때가 종종 있다. 어떻게 할 수 있는지 알아보도록 하겠다. 방법은 매우 간단하다. Spring Security에 존재하는 AuthenticationSuccessHandler 인터페이스를 구현하기만 하면 된다. AuthenticationSuccessHandler 은 총 2개의 메소드로 이루어져 있고 그 중 하나는 default 메소드이다. 이 인터페이스를 구현한 Handler 클래스를 하나 생성한다. public class LoginAuthHandler imp.. 2021. 4. 3.