전체 글 96

TIL - S3 Presigned URL을 통해 이미지 파일 업로드

build.gradle.kts에 의존성 추가dependencies { implementation("com.amazonaws:aws-java-sdk-s3:1.12.741") // AWS S3} application.yml에 버킷명 및 AWS에서 발급받은 키 설정aws: s3: bucket: access-key: secret-key:  S3Config 설정@Configurationclass S3Config( @Value("\${aws.s3.access-key}") val accessKey: String, @Value("\${aws.s3.secret-key}") val secretKey: String) { @Bean fun s3Client(): AmazonS3C..

Spring Boot 실시간 알림 기능 구현

이번 팀 프로젝트에서 기본적인 CRUD 외 실시간 알림 기능을 구현하게 되었다.해당 기능을 구현하면서 정리한 내용을 기록하고자 한다. 실시간 알림을 구현한 이유특정 사용자에게 메시지를 전할 수 있도록 쪽지 기능이 구현되어 있음쪽지 보관함을 확인하는 경우 DB에서 데이터를 가져오기 때문에 알림 기능이 없는 경우 사용자가 직접 확인을 위해 수시로 쪽지 보관함에 접근해야 함다수의 사용자 쪽지를 보기 위해 여러 번 요청을 날리는 경우 서버에 부담이 됨실시간 알림을 사용하면 사용자가 수시로 쪽지 보관함을 확인하는 수고를 덜 수 있으므로 사용자 경험을 향상 시키고 요청을 줄여서 서버의 부담을 줄일 수 있음 처음에는 SSE로 구현하였고 이유는 다음과 같다.SSE로 구현한 이유SSE(Server-Sent Events)..

Spring Boot 2024.07.28

TIL - Spring Boot에서 Redis Cache 사용 시 발생하는 역직렬화 문제

게시글 및 리뷰에 대한 인기글 조회를 구현하면서 일정 시간마다 데이터를 Cache해서 보여주기 위해 Redis Cache를 사용했다. 초기 RedisConfig 코드는 다음과 같다.@Configuration@EnableCachingclass RedisCacheConfig { @Bean fun redisCacheManager(redisConnectionFactory: RedisConnectionFactory): CacheManager = RedisCacheManager .builder(redisConnectionFactory) .cacheDefaults( RedisCacheConfiguration ..

TIL - ZonedDateTime 사용 시 Converter로 DB와의 시간 차 해결

이번 프로젝트에서 LocalDateTime 대신 ZonedDateTime을 사용하면서 DB에 저장 전, 후의 시간 차가 발생했다. DB에 저장 전 데이터를 보면 Asia/Seoul 기준이지만, DB에 저장된 데이터를 보면 UTC 기준이다.해당 데이터로 시간을 비교하려면 시간 차까지 한 번 더 고려해야 했다. ZoneId.of("Asia/Seoul")로 명시적으로 타임존을 설정해도 DB에 저장될 때는 타임존 부분은 제외된다. 이 문제를 해결하기 위해 util 패키지에 다음과 같이 코드를 추가했다.@Converter(autoApply = true)class ZonedDateTimeConverter : AttributeConverter { override fun convertToDatabaseColumn..

TIL - PostMan에서 Token을 Global로 적용

PostMan을 사용하면서 Token을 직접 추가하는 방식으로 사용했었는데 이번에 Token을 환경 변수로 설정하고 자동 갱신될 수 있게 하는 방법을 알게 되었다. [Enviroments] → [+] → Variable에 변수명 입력 및 체크 → [Save] → 우측 상단에서 생성한 환경변수로 설정 [Collections] → 적용할 폴더 선택 → [Authorization] → [Auth type]을 Bearer Token으로 설정 → [Token]에 {{변수명}} 입력 Request에 URL, Body를 입력해 응답 본문에서 token이 담겨오는 변수명 확인 [Scripts] → [Post-response] → 스크립트 작성 → [Send] [Environments] → Current value 확인..

TIL - IntelliJ에서 Git Flow 사용

[Settings] → [Plugins] → [Marketplace] → Git Flow Integration Plus 설치 후 재시작 재시작 후 IntelliJ 우측 하단의 Gitflow를 누르고 [Init Repo]를 누른다. 다음과 같이 창이 뜨면 Use non-default configuration 체크 후 다음과 같이 설정해준다. 이후 Gitflow를 누르면 다음과 같이 변경되어 있으며 Start Feature로 기능 브랜치를 생성할 수 있다. 다음 입력 칸에 브랜치명을 입력하면 feature/브랜치명으로 브랜치가 생성된다.

TIL - Connection Pool

Connection Pool데이터베이스와의 연결을 미리 생성해 두고 필요할 때 재사용하는 기술매번 연결을 새롭게 생성/종료하는 것보다 훨씬 효율적시스템 부하를 줄이고 성능을 향상시키는 데 도움Spring Boot는 HikariCP를 기본 Connection Pool로 사용한다.Hikari CPSpring Boot 2.0부터 기본으로 설정되어 있는 DB Connection Pool Library빠른 DB 접속 가능: DB 접속 설정 객체를 미리 생성 및 연결해 메모리 상에 등록해 놓기 때문에 클라이언트가 빠르게 DB에 접속 가능서버 자원 고갈 방지: DB Connection 수를 제한할 수 있어서 과도한 접속으로 인한 서버 자원 고갈을 방지쉬운 유지보수: DB 접속 모듈을 공통화해 DB 서버의 환경이 바뀔..

TIL - Apache Tika로 이미지 타입 검사

Apache Tikahttps://tika.apache.org/다양한 문서( Word, Excel, PDF 등) 및 멀티미디어(JPEG, MP4 등) 파일에서 콘텐츠 및 메타데이터를 추출하기 위한 Tool kitbuild.gradle.kts에 의존성 추가tika-core: 파일 타입 체크(단순 파일 타입 체크는 core만 의존성 추가하면 됨)tika-parsers: 파일 구문 분석(파일 안의 내용 체크)implementation ("org.apache.tika:tika-core:2.9.0")implementation ("org.apache.tika:tika-parsers-standard-package:2.9.0")💡파일 내부의 여러 content type 확인은 tika-parsers가 필요!! (예:..

TIL - Apache JMeter를 이용한 성능 테스트

응답 시간(Response Time)클라이언트가 서버에 요청을 하고 그 요청에 대한 응답을 받을 때까지 걸린 시간응답 시간 분류처리 시간(Processing Time): 실제 서버가 요청을 처리하는 데 걸린 시간대기 시간(Latency Time): 클라이언트와 서버 간에 데이터를 주고받는 데 걸리는 시간응답 시간(Response Time) = [동시 사용자 수 / 초당 요청 수(TPS)] - 인지시간(Think Time)인지 시간(Think Time): 두 가지 연속적인 작업 사이에 소비하는 시간TPS(Throughput)서버가 초당 처리할 수 있는 요청의 개수TPS가 높을수록 초당 처리할 수 있는 요청의 수가 많음Apache JMeter 설치 및 실행다음 링크에서 apache-jmemter-x.x.x...

TIL - 조회수 증가 테스트 코드에서 조회수가 반영되지 않는 문제 해결

조회수 증가 구현을 위해 Repository에 다음 코드를 작성했다.@Modifying@Query("UPDATE WikiPage w SET w.views = w.views + 1 WHERE w.id = :wikiId")fun updateViews(wikiId: Long) 그리고 실행했을 때 다음과 같은 예외가 발생했다.다른 프로젝트에서는 위 쿼리 메서드가 문제없이 실행되었지만 현재 프로젝트에서는 원하는 대로 작동하지 않았다.query executed via 'getresultlist()' or 'getsingleresult()' must be a 'select' query [update wikipage w set w.views = w.views + 1 where w.id = :wikiid] 그래서 Que..