web/Spring

    Spring Webflux url length 제한 413 에러 해결 방법

    프로젝트에서 사용되는 특정 api에 request param의 길이가 길어지는 api가 현재 구조상 어쩔 수 없이 존재하게 되었다. 그렇게 조심스럽게 운영하다가 request param의 길이가 너무 길어져서 api에서 413에러를 내뱉으면서 결과를 반환 받지 못하는 문제가 생겼다. 우선 nginx에 있는 request param 길이 관련 설정이 문제를 유발하는지 확인해봤다. 우선 테스트를 위한 api를 하나 만들었다. 단순하게 요청을 받고 바로 반환하는 api package com.wedul.reactivetest; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annot..

    WebFlux에서 Mono, Flux에 Map 또는 flatMap을 사용할 때 null을 리턴하는 경우

    WebFlux로 구성되어 있는 프로젝트에서 Mono, Flux stream에서 map이나 flatMap을 사용해서 특정 데이터를 매핑하는 과정에서 특정한 경우에 대해서 null을 리턴하고 다음 파이프라인에서 filter로 Objects의 nonNull을 사용해서 컨텐츠를 필터링 하려고 했다. 작성하려고 한 코드의 일부 예시를 만들어서 작성해봤다. 만약 resultData를 통해 전달받은 데이터가 예상 대로라면 map과정에서 500보다 큰 5189값만 정상 반환하고 나머지는 null을 반환한 후 filter를 통해 정상적으로 하나의 데이터만 남을 것이라고 예상했다. @Test @DisplayName("map 과정에서 반환된 null이 정상적으로 필터링 되었는지 확인하는 테스트") void mono_null..

    Spring Boot version 2.1.x에서 2.2.x (spring frame 5.2 이상)으로 버전업 진행 시 Spring Cloud AWS SnsAutoConfiguration 에서 TypeNotPresentExceptionProxy 가 발생하며 실행안되는 문제

    문제 발생 평소 문제가 많았던 webflux 부분 수정을 위해 spring boot 2.1.3에서 2.2.7버전으로 업그레이드를 진행하기 위해 gradle에서 spring boot version을 2.2.7로 변경하고 애플리케이션을 실행 시켰다. 그런데 평소에는 자주본적이 없던 TypeNotPresentExceptionProxy 에러가 발생했다. org.springframework.beans.factory.BeanDefinitionStoreException: Failed to process import candidates for configuration class [com.baemin.bmart.search.BmartSearchAdminApplication]; nested exception is java..

    Spring reactor 2.1.2 (netty 0.8.4) Mono.zip readTimeoutException 문제

    Mono zip 각 Mono 처리 스레드를 병렬로 실행하고 이를 묶어서 사용할 수 있는게 Mono.zip이다. 근데 Mono zip에서 병렬로 실행되는 작업 중 하나가 empty 또는 error가 발생 되면 바로 error 또는 complete를 내뱉게 되어있다. 하지만 각 Mono 구독 작업에 error와 empty 발생 시 문제에 대해 fallback 처리를 해주면 에러가 발생하더라도 그 로직을 타게 되어있다. 하지만 2.1.2(netty 0.8.4) 버전을 사용하고 있을 때 호출 체인에서 첫 번째 요청의 실패 이후에 두 번째 요청이 정상적으로 이루어 지지 않아서 readTimeout이 발생되는 문제를 경험하였습니다. 이 문제를 해결하기 위해서 알아보던 중 2.1.2버전에 문제가 있는 것을 알게 되어..

    Spring boot2 resilience4j를 이용한 circuit breaker 사용

    fault tolerance library (장애 허용 시스템) fault tolerance library는 무엇인가? 간단하게 이야기해보자. MSA 환경에서 한 개의 서비스에서 다른 api를 호출 할 때 일시적으로 에러가 발생하고 있다고 가정해보자. 만약 이 시기에 요청이 계속 들어오면 계속 500에러를 내보내게 된다. 그럼 사용자들은 이 서비스에 대해서 신뢰를 잃어 버리게 되고 안좋은 인식을 만들 수 있다. 그래서 특정 api 호출과 같은 작업에 에러가 발생했을 때, 그 횟수를 정해놓고 그 횟수 이상 에러를 초과하면 기존에 설정해 놓은 fallback에 맞게 동작하게 하고 일정 시간 후에 다시 시도하여 진행하는 등에 작업이 필요하다. 이게 바로 fault tolerance library (장애 허용 ..

    spring cloud resilience4j 사용시 CircuitBreakerConfiguration 에러

    CircuitBreaker 테스트를 위해서 Resilience4j를 사용했다. 버전은 1.3.0을 사용하려고 했다. //Resilience4J compile("io.github.resilience4j:resilience4j-spring-boot2:1.3.0") compile("io.github.resilience4j:resilience4j-reactor:1.3.0") compile("io.github.resilience4j:resilience4j-timelimiter:1.3.0") 그런데 분명 1.3.0을 사용한다고 명시하였고 gradle도 clean하고 사용하는 denpendency도 확인하였는데 계속해서 다음과 같이 1.1.0 라이브러리를 사용하려고 해서 문제가 발행했다. Cannot resolve ..

    RestHighLevelClient를 사용하여 search after 기능 구현하기

    https://wedul.site/541에서 search after 기능을 사용해서 검색을 하는 이유를 알아봤었다. 그럼 spring boot에서 RestHighLevelClient를 이용해서 search after를 구현을 해보자. 1. Mapping 우선 index가 필요한데 간단하게 상품명과 지역 가격정보들을 가지고 있는 wedul_product 인덱스를 만들어 사용한다. { "settings": { "index": { "analysis": { "tokenizer": { "nori_user_dict": { "type": "nori_tokenizer", "decompound_mode": "mixed", "user_dictionary": "analysis/userdict_ko.txt" } }, "ana..

    JPA 다양한 Join 방법 정리 (N+1, queryDSL, fetch join)

    JPA를 사용하다 보면 join을 할 때가 많아진다. join을 어떠한 방법으로 하느냐에 따라서 수행되는 쿼리가 달라지고 성능에 문제가 발생하는 경우도 종종있다. 그래서 다양한 방식의 join 방식을 알아보고 방식에 따라 작업을 진행해 보자. 우선 사용될 entity 두 개를 설명하면 다음과 같다. @Getter @Entity @Table(name = "wedul_classes") @AllArgsConstructor(access = AccessLevel.PROTECTED) @NoArgsConstructor @Builder public class WedulClasses extends CommonEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY..

    데이터 베이스 버전 컨트롤 Flyway

    Spring에서 초기 테이블과 데이터 관리를 위해서 data.sql과 schema.sql을 사용하였다. 하지만 테이블 스키마가 변경되거나 필수로 초기에 들어가야하는 데이터들이 추가되거나 수정되었을 때 히스토리 관리가 잘 되지 않았다. 특히 서로 교류가 잘 되지 않은 경우에서는 컬럼이 추가되거나 무엇이 변경되었는지 알지 못해서 문제를 유발할 수 있기에 이를 관리 할 수 있는 무언가가 필요했다. 그래서 Redgate에서 제공하는 Flyway를 사용해보기로 했다. 우선 내 개인 프로젝트인 timeline에 적용시켜봤다. 데이터베이스 버전관리 Flyway https://flywaydb.org/ 동작 방식 Flyway가 버전관리를 하기위해서 테이블이 생성된다. Flyway가 버전관리는 이 테이블에 데이터베이스의 ..

    Redis에서 Pub/Sub 방식 소개 및 Spring Boot에서 구현해보기

    redis에 추가된 SUBSCRIBE, UNSUBSCRIBE 그리고 PUBLISH는 Publish/Subscribe 메시지 패러다임을 구현한 기능이다. sender(publisher)들은 특별한 receiver(subscriber)에게 값을 전달하는게 아니라 해당 채널에 메시지를 전달하면 그 메시지를 구독하고 있는 subscribe에게 메시지를 전송한다. subscribers는 하나 또는 그 이상의 채널에 구독을 요청하고 publisher가 누구인지 상관 없이 해당 채널에 들어온 모든 메시지를 읽게된다. 이 subscriber와 publisher의 decoupling은 확장성있는 성장을 가져올 수 있다. Redis-Cli로 기능 사용하기 subscriber redis-cli를 열고 SUBSCRIBE 채널..

    Spring5 리액티브 스트림 정리 및 api 전달 방식 정리

    리액티브 또는 리액티브 스트림은 오늘날 spring framework에서 뜨거운 토픽으로 자리잡고 있다. 그래서 나도 이전 포스팅에서도 정리도 하고 했었는데 아직 확실히 개념이 서질 않아서 다시 정리해봤다. 리액티브 스트림 (Reactive Stream) 이란? 리액티브 스트림은 무엇인가? 정확하게 공식문서에는 다음과 같이 기록되어 있다. (https://www.reactive-streams.org/) Reactive Streams is an initiative to provide a standard for asynchronous stream processing with non-blocking back pressure.This encompasses efforts aimed at runtime enviro..

    Spring boot 모니터링 Actuator 소개 및 설치

    spring acturator를 통해서 스프링 애플리케이션의 작동여부등을 체크해보자. 설정 우선 gradle 라이브러리를 추가한다. compile 'org.springframework.boot:spring-boot-starter-actuator' 그리고 기존에는 application.properties나 yml에 아래 옵션을 설정해줘야 했지만 기본적으로 설정이 되어있다. endpoints.health.enabled=true 하지만 이는 Spring boot 2.0에서 다음으로 변경되었다. (https://stackoverflow.com/questions/48900892/how-to-enable-all-endpoints-in-actuator-spring-boot-2-0-0-rc1) How to enable..

    Intellij에서 spring boot multi module 사용시 jsp 못찾는 이슈 해결방법

    기존에 공부삼아서 개발중이던 wedulpos에 spring batch를 추가해보려고 했다. 그래서 공통으로 mono 프로젝트로 되어있던 wedulpos를 multi module로 수정했다. 그랬더니 이상하게 servlet context에서 jsp를 로드하지 못했다. 그래서 계속해서 ServletException not include... jsp 또는 ServletException not jsp found 오류가 발생했다. 그래서 엄청난 구글링을 2틀동안했다. 집에서 그리고 약속장소에서 기다리면서 노트북으로 그리고 퇴근하고 오늘.. 정말 가지가지한 방법을 다해봤었다. 기본적으로 embed-tomcat의 경우 jasper를 가지고 있지 못해서 별도의 모듈을 추가하고 servlet jspl 추가했고, comp..

    heroku 에서 spring boot jar파일 deploy시 Web process failed to bind to $PORT within 90 seconds of launch 에러 처리

    heroku에 코드를 올리지 않고 바로 jar 파일을 deploy하기 위해서 heroku cli를 이용하여 올리는데 자꾸 Web process failed to bind to $PORT within 90 seconds of launch가 발생했다. 이유를 몰라서 계속 알아보던 중 heroku에서 spring boot를 실행시키기 위해서는 Procfile을 작성하고 port를 지정해줘야 한다. 우선 application.yml 설정 server: port: ${port:8080} Procfile 설정 - Procfile은 확장자 없이 만들어야한다. - 포트는 8080이나 원하는 걸로 지정해 주고 profile까지 작성해주고 나머지 depoly를 위한 내요을 작성한다. web: java -Dspring.se..

    creating bean with name 'webMvcRequestHandlerProvider' defined in URL 에러처리

    Spring 시작 시 creating bean with name 'webMvcRequestHandlerProvider' defined in URL에러가 발생했다. 이유는 spring context관련 설정이 중복되어 발생한 문제였다. @EnableWebMvc를 사용하는곳에서는 @Configuration을 지워주면 문제가 해결되었다.

    Spring Boot에서 6.4 Elasticsearch 연결 및 간단 CRUD

    Elasticsearch를 Spring Boot에서 작업을 하는 간단한 정리를 해보자. 1. Library 추가Elasticsearch를 사용하기 위해서는 spring-data-elasticsearch 라이브러리가 추가되어야 한다. gradle에 추가해보자.1234567dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-elasticsearch' implementation 'org.springframework.boot:spring-boot-starter-web' testImplementation 'org.springframework.boot:spring-boot-starter-test' compileOnly "o..

    kafka docker에 간단 설치 후 Spring boot 연동 테스트

    간단하게 Kafka 설치docker-compose.yml 생성 후 docker-compose up -d를 통해 설치12345678910111213141516version: '2'services: zookeeper: image: wurstmeister/zookeeper ports: - "2181:2181" kafka: image: wurstmeister/kafka ports: - "9092:9092" environment: KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181 KAFKA_ADVERTISED_HOST_NAME: wedul.pos KAFKA_CREATE_TOPICS: "test:1:1" volumes: - /var/run/docker.sock:/var/run/docker.so..

    Spring Reactive Web Application

    Sprint 5에서 리액티브 프로그래밍을 지원하는 웹 애플리케이션을 만들 수 있다. 리액티브 프로그램이란? 이전시간에 정리했었지만 스프링 리액티브 프로그래밍을 들어가기 전에 간단하게 정리해 보자. 일반적으로 리액티브 프로그래밍은 비동기, evnet-driven 방식으로 non-blocking 하는 프로그래밍으로써 일반적인 시스템 보다 작은 작은 쓰레드 수가 필요하다. 그럼 왜? 비동기-논블록킹 리액티브 개발이 가능. 기존 멀티쓰레드 블로킹 방식과는 다르게 서버의 응답에 의지하지 않는 효율적 개발이 가능. 서버간에 호출이 잦은 마이크로 서비스에서 사용됨 Spring Web Reactive Module (Servlet 3.1 이상부터 지원) Spring Framework 5는 spring-web-reacti..

    생성한 Custom validation으로 에러메시지 출력하기

    바로 직전 https://wedul.tistory.com/562?category=595982 에서 Custom validation을 만들어서 입력된 값에 validation을 체크하는 방법을 알아봤다.그럼 이 validation체크를 통해서 front에 상황에 맞는 에러를 보내줄 수 있도록 조치를 취해보자.우선 @valid 처리를 했었던 컨트롤러에서 에러 메시지를 수집해야한다. 1. ControllerSpring에서 Validation 작업을 진행할 시 validation에 문제가 발생하면 에러 내용을 묶어서 BindingResult로 처리할 수 있도록 제공해준다. 이를 사용하기 위해서 parameter로 BindingResult값을 추가해준다.1234567891011121314/** * 회원가입 * *..

    Custom Validation 만들어서 추가하기

    Spring에서 @NotBlank, @Email등 여러 템플릿에 맞게 Validation을 넣을 수 있다.하지만 추가적으로 패스워드 규칙과 같이 별도 체크할 validator가 필요할 때 만들어서 사용해야 하는데 만들어서 지정해보는 작업을 해보자. 1. Controller요청을 받을 DTO앞에 @Valid 어노테이션을 추가해야한다.1234567891011/** * 회원가입 * * @param reqDto * @return * @throws Exception */@RequestMapping("/join")public ResponseEntity join(@Valid UserDto reqDto) throws Exception { return ResponseEntity.ok(userService.insertUs..

    inteliij 사용 시 related gradle configuration 설정을 찾지 못할 경우 해결방법

    Inteliij로 프로젝트를 정상적으로 작업하고 있었는데 어느날 application.yml 설정을 읽지 못해서 오류가 막 발생했다. 그래서 인텔리제이 오류 내용에서 찾아보던 중 다음과 같은 오류 내용을 볼 수 있었다.Unable to make the module: related gradle configuration was not found. Please, re-import the Gradle project and try again 그래서 무엇인고 하니 gradle 설정을 찾지 못한다는 이슈인 것 같아서 gradle 설정을 새로고침 해줬다.방법은 Gradle Task 관련 view에서 새로고침 버튼만 눌러주면 된다. ## 만약 view가 보이지 않는다면 여기 메뉴에서 찾아서 설정할 수 있다.

    [공유] spring에서 생성자 의존성 주입

    spring에서 사용하는 의존성 주입에 경우 @Autowired만을 사용하면 나중에 테스트 케이스를 만들때 어려움이 생긴다. 그래서 생성자 주입을 사용하는데 잘 정돈된 사이트가 있어 공유한다. http://multifrontgarden.tistory.com/214

    Spring Boot Cross Domain 처리

    웹 브라우저에서 같은 도메인을 사용하는 서비스에 대한 요청은 정상적으로 처리가 되나 도메인이 같지 않은 서비스에 요청을 할경우에 오류가 발생한다. 이는 동일 출처 정책(Same Origin Policy) 라는 정책을 두어 다른 도메인의 서버에 요청하는 것을 보안 문제로 간주하고 이를 차단하는 것 때문에 발생한다. Spring Boot에서 간단한 방식으로 해결할 수 있다. 1. 요청에 @CrossOrigin 애노테이션 붙히기12345@GetMapping("/greet")@CrossOriginpublic Greet greeting() { return new Greet("test");}Colored by Color Scriptercs 2. 특정 도메인에서 오는 요청만 받고 싶을 경우.-> 특정 도메인에서 오는..

    Facebook Javascript plugin과 spring security를 이용한 페이스북 로그인

    개인적으로 공부겸 만들고 있는 Wedul Pos에는 아이디와 패스워드를 사용해서 로그인하는 방식을 제공했다. 하지만 페이스북 로그인 방식을 추가해보고 싶어서 facebook 개발자 사이트에 가입하여 정보를 얻고 추가해봤다. 우선 페이스북 로그인 방식을 처리하는 방식은 Facebook Javascript plugin을 사용하여 spring security에서 인증을 하는 방식과 /sign/facebook 요청만 front에서 보내면 server에서 모든 처리를 진행하는 방식 두가지가 있다. 그 중에 첫번째 javascript plugin을 이용하는 방식을 사용해서 구현해보자. 1. facebook developer 사이트에서 javascript 내용 얻기 https://developers.facebook...

    Spring Boot application.properties 암호화 내역 복호화 방법

    Spring Boot에서는 여러 설정값을 application.properties에 입력하여 사용할 수 있다. Spring보다 편리하고 효율적이다. 하지만 DBMS 사용을 위해서 연결정보를 properties에 입력할 때 평문으로 그냥 삽입하면 정보 유출에 문제가 발생 할 수 있다. 이를 해결하기 위해서 application.properties에서 어떻게 사용하는지 확인해보자. 1. application.properties 내용 암호화하여 입력하기우선 application.properties에 있는 내용을 암호화 해서 삽입한다. 나는 AES256으로 암호화 하여 삽입하였다.12spring.datasource.username=K2amNtg+kL5xK23g7H3Znw==spring.datasource.pas..

    Spring boot hibernate jpa에서 Auditing 사용 - update, create 시간 자동 변경

    엔티티를 만들고 데이터를 삽입하고 조작할 때 create date와 last modified date를 별도로 업데이트 해주면서 관리하였다. 하지만 이번에 JPA를 공부하면서 별도의 작업 없이 JPA의 Auditing 기능을 사용하면 데이터를 삽입하고 수정할 때 자동으로 날짜를 수정하도록 할 수 있는 기능이 있는 것을 확인했다. 1. ConfigurationJPA Auditing을 사용하기 위해서는 기능을 자동으로 활성화 해주는 어노테이션을 붙혀주면 된다. 처음에는 @Configuration을 사용하는 클래스에 함께 선언해주었는데 정상적으로 적용이 되지 않아서 @SpringBootApplication을 사용하는 곳에 적용했더니 성공적으로 적용되었다. 123456789101112131415161718192..

    Spring Validation을 이용해서 요청 검증처리

    대게 개발을 진행할 때 front에서 validate를 체크하고 민감한 정보에 대해서는 한번더 체크를 진행하고 작업을 했었다. 하지만 클라이언트에서만 validation을 체크하게 되는 경우 브라우저에서 악의적인 행동에 대해서 대응하기 어려워질수 있기 때문에 백엔드에서도 Validation을 처리해야한다. 여기서 사용되는 @valid 어노테이션들을 알아보자. 1. DTO validation 선언 우선적으로 DTO에 각 속성에 필요한 @valid 옵션들을 추가한다.1234567891011121314151617181920212223242526272829303132package com.wedul.springboottest.rest.dto; import lombok.*; import javax.validatio..

    Spring Application Test 정리

    Spring에서 Junit을 통해 테스트하는데 익숙해져있다. 이 방식과 더불어서 Spring의 MockMvc를 이용하여 Web Layer를 테스트 하는 방법에 대해 공부해보자. 우선 테스트를 진행하기 위해서 Spring-boot-starter-test를 추가해야한다. Gradle1testCompile("org.springframework.boot:spring-boot-starter-test")cs 그러면 테스트 클래스 파일에 @SpringBootTest와 @RunWith가 추가된다. @SpringBootTest는 Spring Boot에서 주 구성 클래스를 찾아서 Spring Application Context를 시작하도록 하는 어노테이션이다. Controller 테스트를 진행할 떄 서버를 가동시키고 Te..

    Java 9 이후 deprecated된 Spring @PostConstruct와 @PreDestory 대안소개

    이 둘은 Bean의 생성 (생성자가 호출 된 후)과 소멸 시점에서 실행할 부분을 정의할때 사용한다. 하지만 @PostConstruct와 @PreDestory 어노테이션은 Java 9에서 Deprecated 되었고 Java 11에서는 제거될 예정이다. 그래서 이와 같은 동작이 필요할 때 사용할 수 있는 대안을 소개한다. InitializingBean, DisposableBean 인터페이스 구현 두 개의 인터페이스를 구현하면서 afterPropertiesSet()과 destroy() 메서드를 재정의하면서 deprecated된 두개의 어노테이션을 대신할 수 있다. 123456789101112131415161718192021@Servicepublic class UserService implements UserS..

    Swagger 라이브러리를 사용하여 API 내용 정리하기

    Web 개발을 진행하다보면 다양한 API를 개발하게 된다. 하지만 정리하기가 쉽지 않고 이를 위해서 인터페이스정의서를 계속 정리하기도 사실 쉽지 않다. 이를 위해서 한번에 API 내용이 정리되어 한눈에 볼 수 있도록 제공해주는 library가 있다. 이 library인 swagger를 적용해보자. 1. 라이브러리 추가 Swagger 사용을 위한 라이브러리를 gradle에 추가하자.12compile group: 'io.springfox', name: 'springfox-swagger2', version: '2.5.0'compile group: 'io.springfox', name: 'springfox-swagger-ui', version: '2.5.0'cs 2. Swagger 설정 관련 내용 Configu..