필자는 Spring Security를 활용하여 로그인을 구현할 때, 현재 JWT 토큰값으로 로그인한 사용자를 바로 불러올 수 있는 편의메소드를 제작하여 사용한다. public class SecurityUtils { public static String getCurrentAccountEmail() { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); if (authentication == null || authentication.getName() == null) { throw new AccountException(AccountCode.NOT_FOUND_ACCOUNT); } return authenti..
Spring Security는 API 요청 URL 중 ;나 //가 포함되어 있으면 RequestRejectedException을 내뱉는다. 로깅을 할 때 해당 예외는 Security 필터 단에서 터지는 예외이므로 ControllerAdvice가 핸들을 하지 못해서 이렇게 지저분하게 로그가 남게 된다. 이를 처리하지 않게 하기 위해서는 다음과 같이 설정해 주면 된다. @Bean fun setDefaultFirewall(): StrictHttpFirewall { val firewall = StrictHttpFirewall() firewall.setAllowSemicolon(true) firewall.setAllowUrlEncodedDoubleSlash(true) return firewall } 자세한 건 공..
QueryDSL을 사용해서 검색 쿼리를 작성하는 방법에 대해서 공유하고자 한다. # 요구사항 예시 "모집 글(Recruit)"이라는 엔티티를 10개씩 검색해서 페이징 처리해서 내려줘야 한다. Recruit은 보통 게시물이라고 생각하면 편할 것이다. # QueryDSL 리포지토리 구조 본인은 QueryDSL로 리포지토리를 구성할 때 위와 같은 구조를 가장 많이 채택한다. 사용해 보니 이 구조가 가장 깔끔한 것 같다. RecruitRepositoryCustom에 검색을 위한 search 메소드를 구현할 것이다. # RecruitController @GetMapping("/recruit") public ApiResponse searchRecruit( @PageableDefault(sort = "id", dir..
이번에는 FCM (Firebase Cloud Message)라는 무료 메시징 서비스를 통해서 앱,웹으로 푸시 알림을 보내는 API 예제를 작성하는 방법에 대해 알아본다. # Firebase, Spring Boot 설정 다음 일련의 과정을 따라한다. 스프링 부트에 넣을 json 키를 생성해야 한다. 생성된 json 파일을 잘 모셔둔다. 그리고 스프링 부트 resources 디렉토리 밑에 그대로 넣어준다. 그리고 Gradle에 다음 의존성들을 추가한다. implementation("com.google.firebase:firebase-admin:6.8.1") implementation("com.squareup.okhttp3:okhttp:4.9.1") okhttp는 파이어베이스에 토큰값을 요청할 때 사용할 예정..
AOP로 기능을 구현하다 보면 다소 복잡한 기능을 추가적으로 구현해야 하는 경우가 있다. 기존까지 AOP기능은 통합 테스트를 진행했었는데, 이러면 테스트가 너무 무거워져서 단위 테스트 방법을 찾아봤다. 전적으로 다음 블로그를 많이 참조했다. https://junhyunny.github.io/spring-boot/test-driven-development/improve-feign-client-aop-test/ FeignClient AOP 단위 테스트 개선하기 junhyunny.github.io # 배경 사용자가 방탈출에 관련한 인증 글을 작성했을 때, 10개 이상이 되면 탈출중독 이라는 뱃지를 추가하는 로직을 AOP로 작성했다. # CheckBadgeAspect @Aspect @Component class..
개발을 하다가 Swagger가 갑자기 먹통이 된 경우가 있었다. Swagger로 접속하면 MMethodArgumentTypeMismatchException가 발생했었다. 엄청난 삽질 끝에 Swagger가 RestController로 선언된 컨트롤러에 문자열 URI가 오지 않고 바로 {id}가 오는 경우 때문에 발생한 문제였다. 혹시라도 해당 오류가 발생한다면 컨트롤러 단의 API 엔드포인트 매핑이 적절하게 이루어져 있는지 확인하면 되겠다.
서비스 레이어 단위 테스트를 할 때 private 메소드를 테스트 하는 방법에 대해 공유하고자 한다. # 테스트 할 메소드 private fun String.toSort(): Sort { return if (this == "DATE") { Sort.by(Sort.Direction.DESC, "modifiedAt") } else { Sort.by(Sort.Direction.DESC, "likeCount") } } 문자열 확장함수로 정의된 toSort() 메소드는 정렬 기준을 문자열로 DATE 이면, modifiedAt 기준 내림차순, LIKE이면 likeCount 기준 내림차순으로 정렬하는 Sort 객체를 반환하는 메소드이다. # private 메소드 자체 테스트 @Test fun `(private) to..
Kafka를 연동하여 아주 간단한 pub/sub 구조의 서비스를 만들어본다. 스프링 서버로 message 요청이 오면 이를 Kafka 서버로 전달하고, Kafka는 해당 토픽을 구독중인 컨슈머에게 전달하는 아주 간단한 구조이다. # Kafka 설치 윈도우 11기준으로 2.8.0 버전을 설치해서 사용했다. 적당한 위치에 설치하고 폴더명을 kafka (혹은 짧은) 명으로 바꿔준다. 나중에 cli로 명령어를 입력할 때 너무 명령어가 길다는 오류를 보지 않기 위함이다. # Zookeeper 와 Kafka 실행 Kafka는 Zookeeper를 내부적으로 사용한다. Kafka를 실행하기 위해선 반드시 먼저 Zookeeper를 켜줘야 한다. Kafka 설치 경로로 이동하여 cmd를 열어준다. Zookeeper를 실행..