반응형

JAVA/JAVA | Spring 학습기록 66

[Spring] log4j2를 활용한 로깅 전략을 다룬 yml 파일을 생성하자

배포 환경에서, 그리고 개발하면서 api를 맞춰보면서 특정 문제가 발생했을 때 그에 대한 기록을 남겨두면 이후에 그 기록을 바탕으로 대처를 할 수 있다. Spring에서는 다양한 logging configurations들을 제공한다. log4j, logback, log4j2들이 대표적이다. 이번 포스팅에선 log4j2를 선택한 이유와, 개발 및 배포환경에서 각각 다른 log4j2 yml을 어떻게 만들었는지 작성해보도록 하겠다. logback vs log4j2 log4j는 2015년에 서비스가 종료됐고, 오래된 로그 프레임워크이기 때문에 제외하도록 하겠다. logback log4j 개발팀이 제작하여 기본적으로 log4j와 비슷하지만 성능이 향상됨. spring-boot-starter-web의 기본 로깅 프..

[JAVA] IoC, DI, DIP

친구와 얘기하던 중, Spring IoC, DIP 개념에 대한 얘기가 나왔다. 이 개념들은 구글링하면 워낙 잘 정리된 글들이 많아 별도로 작성하지 말까 고민도 했다. 하지만 해당 개념들은 객체지향에서 매우 중요하기 때문에 한번쯤은 포스팅하는 것이 좋을 듯하여 정리해보려 한다. IoC(제어의 역전) Inversion of Control, 즉 IoC는 제어의 역전이라고 번역된다. 쉽게 말하자면 어떤 객체에 대한 관리를 나 대신 다른 애한테 맡긴다는 것이다. 스프링을 쓴다면 스프링에게 특정 객체의 생성과 소멸을 빈으로 등록해 맡겨주는 것으로 생각하면 된다. 즉, 제어권을 내가 아닌 스프링 컨테이너에게 빈의 생성, 의존 관계 설정을 맡기는 것이므로 IoC가 이루어지는 것이다. 스프링을 사용하지 않는다고 하더라도..

[Spring] 인증 토큰을 생성하는 JwtTokenProvider를 알아보고 테스트를 작성해보자

그동안 미루고 미루어왔던 JwtTokenProvider에 대해 알아보고, 테스트 코드를 작성하는 법을 작성하려 한다. JwtTokenProvider는 로그인 인증 과정을 처리할 때 반드시 필요한 access Token을 생성해주는 역할을 한다. 이 JwtTokenProvider는 @Configuration 어노테이션으로 스프링 빈으로 관리되고 있는 ArgumentResolver이나 Interceptor에서 사용되고 있기 때문에 @Component 어노테이션으로 스프링 빈 등록을 해주어야 한다. 특히 인터셉터에서 HttpServletRequest로 토큰을 추출해주고, 아규먼트 리졸버에서 토큰값으로 payload를 가져오는 역할을 해주기 때문에 JwtTokenProvider의 역할은 매우 중요하다. JwtT..

[Spring] 테스트에서 test 스키마가 아닌 main의 스키마를 의존한다면? _ application.yml 설정

아래 그림과 같이 main과 test 패키지에서 따로 db를 생성해야 한다고 해보자. 테스트에서는 매번 drop table if exists를 해주지만, main에서의 schema.sql에서 drop table을 해줄 경우에 배포할 때마다 데이터들이 리셋되므로 정말 큰일나게 된다. 이렇게 테스트 때와 실제 실행에서의 schema.sql을 다르게 해주고 싶다면 어떻게 해야 할까? @Sql 어노테이션을 쓰는 방법으로 해결된다고들 하지만, 나는 그 방법으로 해결되지 않았다. test 클래스마다 @Sql 어노테이션으로 classpath prefix까지 붙여주면서 사용해보아도 자꾸 test_schema가 아닌 메인 패키지의 schema.sql을 의존했다. 아직도 이 부분은 명확한 이유를 모르겠다.. 그럼 어떻게 ..

[ERROR] Required request body is missing 해결

Required request body is missing 이 에러를 본 적 있는가? 해석해보자면 요청의 body에 존재해야될 것이 존재하지 않는다는 것이다. 보통 400 Bad Request, 415 Unsupported Media Type 에러와 함께 발생할 확률이 높다. 해당 api를 사용할 때 요청에 들어있는 객체를 이용해서 처리하는데, 정작 요청 body에 값이 없는 것이다. 주로 POST, PUT http method API를 사용할 때 많이 발생한다. 해결 방법은 어떻게 될까? 1. (가장 높은 확률로) 요청 body에 담긴 값이 JSON이 아닐 때 400 Bad Request, 415 Unsupported Media Type 에러와 함께 postman을 이용하여 간접적으로 api 호출을 할..

[ERROR] Request method 'GET' not supported 해결

Request method 'GET' not supported 뿐만 아니라 Request method 'GET' not supported, Request method 'PUT' not supported 등등. Request method '{HTTP method}' not supported 관련 에러가 뜰 때 해당되는 포스팅이다. 보통 405 Method Not Allowed, 500 Internal Server Error와 함께 발생할 확률이 높다. 나의 경우는 특정 기능을 수행하거나 테스트할 때 위 문구와 함께 500 에러가 발생했다. 원래대로라면 body에 원하는 객체의 속성들이 담겨있어야 한다. 하지만 결과는? com.fasterxml.jackson.databind.exc.UnrecognizedPr..

[Spring][TDD] RestAssured를 이용한 e2e test로 Controller API까지 통합 테스트해보자

그동안 나는 단위 테스트만을 진행해왔다. 도메인 로직이 잘 실행되는지 junit 문법의 Assertions로 테스트해왔다. dao test는 @JdbcTest를 이용하여 단위테스트를 했고, service test는 fake 객체를 만들어주어 단위 테스트를 진행해주었다. 그런데 컨트롤러는 @RestController에서 @RequestBody로 request를 받고, ResponseEntity를 넘겨주기 때문에 웹 애플리케이션을 직접 실행하면서 테스트하지 않는 이상, 어떻게 테스트해야할지 감이 오지 않았다. RestAssured를 이용하면 API response의 statusCode뿐만 아니라 body에 올바른 값이 담기는지도 테스트가 가능하다! 이번 시간에는 Spring 환경에서의 RestAssured를..

[Spring] @Transactional로 DB 동시성 문제를 방지하자

웹 데이터 애플리케이션을 만들 때, dao에서 sql문으로 db에 접근하고 service에서 dao 메서드들을 이용하여 하나의 트랜잭션을 관리한다. 그런데 만약 이 애플리케이션을 여러 명이서 동시에 사용한다면? 동시성 문제가 발생할 수 있다. 동시성 문제란, 두 개 이상의 세션이 공통된 자원을 읽고 쓸 때 발생할 수 있는 문제를 의미한다. 이번 포스팅에선 이러한 동시성 문제와 트랜잭션에 대해서 알아보고, @Transactional 어노테이션으로 해결하는 방법을 알아볼 것이다. +) 22.10.13. 트랜잭션 격리레벨 설명 수정 및 보충 트랜잭션이란? DBMS에서 데이터를 다루는 작업의 단위를 의미한다. 용어상 정의로는 이해하기 어렵지만, 트랜잭션의 성질을 알아보면 보다 더 쉽게 이해할 수 있을 것이다. ..

[ERROR] GroovyRuntimeException: Conflicting module versions. (feat. java.lang.ExceptionInInitializerError)

문제 상황 스프링 환경에서 jdbcTemplate을 이용하여 애플리케이션을 생성하고 있었다. 그러던 도중, dao test코드에서 아래와 같은 에러가 발생했다. 웃긴 건, 애플리케이션 실행 자체는 정말 잘 된다는 점이다. groovy.lang.GroovyRuntimeException: Conflicting module versions. Module [groovy-xml is loaded in version 4.0.1 and you are trying to load version 3.0.10 dao 테스트 코드에서만 위 에러가 뜨면서 실패한다. 문제 원인 build.gradle의 rest-assured 버전이 문제였다. testImplementation 'io.rest-assured:rest-assured..

[ERROR] 406 에러 _ Not Acceptable (스프링 직렬화/역직렬화)

문제 상황 스프링 환경에서 특정 dto 를 반환해주는 api에서 406 에러가 발생했다. @GetMapping("/status") public ResponseEntity status() { return ResponseEntity.ok(chessService.getStatus()); } 뿐만 아니라, 응답으로 MoveDto를 받아서 작동하는 move api도 아예 작동하지 않았다. @PostMapping("/move") public ResponseEntity move(@RequestBody MoveDto moveDto) { System.out.println(moveDto); return ResponseEntity.ok(chessService.move(moveDto)); } MoveDto를 요청으로 받아서 ..

반응형