[SpringBoot] Redis 적용 시 @Indexed 사용 문제점
·
Framework/SpringBoot
🩸 문제redis에 refresh token을 저장 중 → idx가 붙은 것과, value이름과 함께 토큰 값이 여러 개가 한번에 나오고 있다. redis:filed:value 형태가 옳게 나오는 걸까?    🩺 원인 value를 이용해 검색할 수 있는 @Indexed를 이용하면 인덱스 처리가 된다.@Getter@RedisHash(value = "refresh_token", timeToLive = 86400)public class RefreshToken { @Id private String userId; @Indexed private String token; public RefreshToken(String userId, String token) { this.userId = userId; this...
[SpringBoot] 테스트 코드 작성 시 Mock과 Spy, 그리고 BCryptPasswordEncoder의 encode
·
Framework/SpringBoot
첫번째 이슈: BCryptPasswordEncoder 동작  1. 문제Mock으로 BCryptPasswordEncoder 를 주입 받아 proxy로 생성돼 비밀번호가 제대로 저장되지 않는 문제 발생비밀번호가 인코딩되어 저장되지 않고, 비밀번호 검증도 하지 못해 예외가 발생하고 있다.  2. 원인 @Mock private BCryptPasswordEncoder passwordEncoder; 테스트 주체는 UserService니 BCryptPasswordEncoder는 Mock으로 지정하였다.그로 인해 matches()와 encode()가 동작하지 않았고, password를 제대로 검증하지 못하고 있었다.  3. 해결 방안 given - willReturn 이용given(passwordEncoder.matc..
[SpringBoot/JPA] 조회 성능 개선하기 - FULLTEXT Index 사용
·
Database/JPA
부트캠프 과제 구현 중 기록100만 건의 데이터를 생성해 저장하고, 목록을 조회 하기목록 조회 시 성능을 개선하기 위한 방법 기록대용량 데이터 생성 후 저장: https://rvrlo.tistory.com/entry/SpringBootJPA-JDBC-Batch-Insert를-통해-대용량-데이터-저장하기      🔎 과제 분석저번 글에서 대용량 데이터를 생성하여 테이블에 저장했으니, 이번에는 조회 성능을 개선해보기로 한다.조회 속도를 개선하기 위해 여러 방법을 고려해보라고 했고, 제일 먼저 떠오른 것은 인덱스를 이용하는 것이었다.   ✨ MySQL - Searchall, index: 테이블 전체 스캔(인덱스x)range: 인덱스를 사용한 범위 검색fulltext: MATCH .. AGAINST 구문을 사..
[SpringBoot/JPA] JDBC Batch Insert를 통해 대용량 데이터 저장하기
·
Database/JPA
부트캠프 과제 구현 중 기록100만 건의 데이터를 생성해 저장하고, 목록을 조회 하기대용량 데이터를 저장하기 위한 방법 기록데이터 조회 성능 개선: https://rvrlo.tistory.com/entry/SpringBootJPA-조회-성능-개선하기-FULLTEXT-Index-사용      🔎 과제 분석100만 건의 데이터를 저장하기 위해 랜덤한 값을 생성해야 했다.먼저 목표인 users 테이블은 pk인 id와 unique로 지정된 email이 존재한다.id는 auto_increment로 지정되어 상관없지만, 공통된 값이 나오면 곤란할 email을 랜덤하게 생성해야 했다. 그리고 과제에 주어진 조건은 → 닉네임은 랜덤으로 지정하고, 동일한 닉네임이 들어가지 않도록 하는 것  결국 email과 nickn..
[SpringBoot] Cache 값을 저장하지 못하던 문제 해결 및 @Cacheable과 @CachePut 차이
·
Framework/SpringBoot
부트캠프 과제 中 트러블슈팅 과정 작성  🛠️ 트러블 슈팅0. 배경사장이 어떤 가게를 소유하고 있는지 한번에 처리하기 위한 로직을 빼기 위해 고민했다.Filter, Inteceptor 등 방법을 생각했지만, 다 포기하고 말았다. 사장이 소유하고 있는 가게를 확인하기 위해서는 결국 DB에 접근해야 하는데, 구현 로직이 아닌 완전 밖에 있는 filter나 interceptor에서 repository접근이 옳지 않아 보였다. 결국 공통으로 처리하는 걸 포기해야 하나 싶을 때 'Cache를 사용하라'는 조언을 들었다.   1. 문제가게가 생성될 때 userId를 key로 캐시에 저장하고, 그 캐시는 List형태로 만들고 싶었다.하지만 가장 첫단추인 캐시 저장부터 문제가 생겼다. 가게 생성 메서드 안에 있는 캐..
[SpringBoot] access token과 refresh token을 만들어 postman으로 테스트하기 (1)
·
Framework/SpringBoot
내배캠 4ch 개인 과제 수행 중 lv5에 해당하는 "스스로 문제 정의"를 진행하며 작성한 글    🔒 Access Token접근을 위해서 사용하는 access token정보가 저장되어 노출되지 않도록 로컬 변수에 저장하여 보호해야 한다.백엔드가 Authorization헤더에 저장하면 프론트에서 로컬 변수에 저장한다.  🔑 Refresh Token토큰을 재발급받기 위해 사용하는 refresh tokenaccess token이 만료되었을 때 재발급을 받을 수 있게 하며, access token과 refresh token을 비교한다.cookie에 저장해 외부로 노출될 위험이 있기 때문에 아무 정보도 담지 않는다.  🔐 재발급 방법access token & refresh token 만료 → 재발급 (로그..
[Spring] Enum에 i18n 적용하는 방법
·
Framework/Spring
부트캠프 과제 中 트러블슈팅 과정 작성 글일정 관리 앱 서버 ver.2  ※ 이용 방법만 필요하면 목차에서 [구현 과정] 클릭    💡트러블 슈팅 1. 문제Exception을 처리할 Enum을 만들 때 message_ko와 message_en을 한번에 같이 전달하고 있었다.USER_NOT_FOUND(HttpStatus.NOT_FOUND,"해당 id를 찾을 수 없습니다.", "The ID cannot be found.")   2. 원인다국어처리를 지원하는 i18n에 대해서 이야기를 들었고, 이 방법을 이용하면 사용자가 설정한 언어에 따라서 그에 맞는 메세지가 전달할 수 있다는 방법을 알았다. 이 방법을 이용하기 위해서 i18n에 대해서 알아보았지만, Enum에서 이 값을 전달하기 위해서는 추가 설정이 필..
[Spring] try-catch에서 SQLException이 잡아지지 않을 때 해결
·
etc/error
부트캠프 과제 中 트러블슈팅 과정 작성 글일정 관리 앱 서버 ver.2    1. 문제Spring Data Jpa 실습 중 [회원가입]을 시도하는 부분에서 email을 Unique로 지정해 가입을 하려고 했다.만약 같은 email로 가입을 시도하면, 이미 존재하는 email이라는 메세지를 전달하려고 했지만 그 예외가 잡히지 않았다.   2. 원인 java.sql.SQLIntegrityConstraintViolationException: Duplicate entry '_@email' for key 'user.UKob8kqyqqgmefl0aco34akdtpe'  분명 같은 email로 가입을 시도하면 SQLIntegrityConstraintViolationException 예외가 뜬다.가입 시도를 위해 jp..
[Spring] Global Exception Handler에서 Enum 사용하기
·
Framework/Spring
부트캠프 과제 中 트러블슈팅 과정 작성 글일정 관리 앱 서버 ver.2  ※ 이용 방법만 필요하면 목차에서 [구현 과정] 클릭    💡트러블 슈팅 1. 문제상황마다 Exception을 만들고, Global Exception Handler를 사용하다 Exception Class를 여러 개 만들어야 하는 문제가 생겼다. 상황에 맞는 정확한 이름이 담긴 Exception을 만드는 것이 좋지만, 대부분 접근 권한이나 path입력, null입력 등 유효성 문제에 대한 예외 처리였기 때문에 그 의도는 모두 같았다. 발생되는 원인만 다른 것 뿐. 2. 원인문제가 발생될 시점에서 if로 확인하고, throw new로 상황에 맞는 Exception을 만들어 발생시키고 있었지만, 최종 응답은 같은 모양이었다. 응답에 필..