본문 바로가기

스프링 부트58

[A-ger] Rest Api 응답 데이터 구조화하기 아래와 같은 방식으로 구조화를 진행했습니다. // 표준화한 ACCOUNT { "success": true "code": 0, "message": "성공하였습니다.", "data": { "accountId": 1, "accountName": "frank" }, } [CommonResponse 설계] /** * @Class : CommonResponse * @Description : enum으로 api 요청 결과에 대한 code, message를 정의 **/ @Getter @AllArgsConstructor public enum CommonResponse { SUCCESS(0, "성공하였습니다."), FAIL(-1, "실패하였습니다."); private final int code; private final .. 2022. 3. 2.
[스프링부트] MongoDB로 CRUD 실습해보기 [몽고디비 설치] 2022.03.02 - [맥북 M1] - 맥북으로 도커에 mongoDB 설치하기 [스프링부트 프로젝트 가져오기] start.spring.io로 아래 Dependencies를 추가했습니다. 편의를 위해 Lombok 정도만 추가로 가져오겠습니다. [application.properties]: yml로 하셔도 무방합니다. database 부분을 선언하신 데이터베이스 이름으로 할당해주세요. 아래 세 줄은 선언하신 계정 이름과 패스워드에 맞게 바꿔주세요. spring.data.mongodb.database=test spring.data.mongodb.port=27017 spring.data.mongodb.host=localhost #아래 세 줄을 꼭 추가해야 권한 오류가 나지 않습니다. spri.. 2022. 3. 2.
[스프링부트] javax.persistence와 org.springframework.data.annotation의 차이 예전에 프로젝트를 진행하던 중 @Cacheable 적용에 애를 먹었던 적이 있습니다. 라이브러리 import를 잘못 설정했던 것인데 같은 어노테이션이라도 종류가 확연히 다르므로 이에 대한 인지를 분명히 해야 합니다. 그 때 당시 javax.persistence를 import 했었습니다. 그러나 이 라이브러리는 관계형 디비에 사용되는 것이라 Redis같은 NoSQL에 사용하면 안됩니다. 비슷한 예로 엔티티에서 @Id 어노테이션 사용시에도 import를 하실때 사용하는 데이터베이스 종류에 따라 다르게 import 해야합니다. javax.persistence.*: 관계형 DB에서 사용. org.springframework.data.annotation.*: JPA에 의해 지원되지 않는 Nosql이나 프레임워크에.. 2022. 3. 2.
스프링 시큐리티 인증 필터 처리 스프링 시큐리티 처리 과정 스프링 시큐리티 인증 과정 1. 로그인을 하게 되면 AuthenticationFilter에 들어옵니다. 2. UsernamePasswordAuthenticationToken을 통해 유저의 로그인 정보를 만듭니다. 3. AuthenticationManager의 구현체인 ProviderManager가 AuthenticationProvider를 호출합니다. 4. UserDetailsServicesms UserDetails를 구현한 User 클래스를 받아 필터에 필터에 값을 전달합니다. 5. 필터는 받은 값을 SecurityContextHolder의 SecurityContext의 Authentication에 넣습니다. 6. 들어간 로그인 정보는 세션 기반 방식에서 로그인 인증을 수행할.. 2022. 2. 19.
@NotNull, @NotEmpty, @NotBlank 차이 엔티티의 필드 값을 정하다 Not Null 설정을 정하려다 @NotNull과 @NotBlank @NotEmpty라는 세 어노테이션이 있는 것을 알게 되었습니다. 세 어노테이션 모두 Bean Validation (Hibernate Validation) 에서 제공하는 표준 Validation 입니다. NotNull은 javax.validation.constraints.NotNull 으로 validation 패키지 안에 있는 어노테이션으로 기본적으로 Null 값을 허용하지 않으나 “”과 “ “으로 빈 칸과 공백을 허용합니다. NotEmpty는 null과 “”는 허용하지 않습니다. 그러나 “ “은 허용하게 됩니다. 공백 값 또한 정상 처리 되도록 하고 싶을때 사용하면 될 거 같습니다. NotBlank는 null.. 2022. 2. 19.
스프링 커버링 인덱스로 페이징 성능 개선하기 지난 글 2022.02.07 - [스프링 부트/A-ger] - 스프링 무한스크롤 페이징 검색 처리 및 동적쿼리 적용하기 지난 글에서 무한 스크롤 적용을 위해 slice와 booleanExpression으로 동적 쿼리를 적용했었습니다. 검색 기능은 아무래도 이용자들이 가장 많이 이용할 기능이기에 더 많은 성능 개선을 위해 커버링 인덱스를 적용하기로 했습니다. 일단적으로 조회 쿼리에서 성능 저하의 원인이 되는 것은 인덱스 검색 후 컬럼 값을 읽을 때입니다. select 부분에서 데이터 블록에 접근하기 때문에 많은 성능 저하를 유발합니다. 그러나 커버링 인덱싱을 적용하게 되면 where, order by, offset, limit를 인덱싱으로 빠르게 Id만 찾아내 데이터 블록에 접근하기에 성능 향상에 도움이 .. 2022. 2. 18.
스프링 부분 수정 쿼리 @DynamicUpdate 개요 프로젝트를 진행하던 중에 수정 쿼리를 날려야 할 상황이 거의 모든 엔티티에 있었습니다. JPA의 기본 설정은 모든 컬럼을 업데이트하게 되어 있습니다. 대부분의 경우 엔티티마다 전부 수정하는 쿼리를 날리는 경우는 없습니다. 따라서 부분 수정쿼리를 날리는 어노테이션을 찾던중 @DynamicUpdate 을 발견하였습니다. 사용법 사용법은 간단합니다. 엔티티 클래스에 @DynamicUpdate만 붙여주면 변경된 컬럼만 찾아 업데이트를 해줍니다. 자주 사용되는 상태변경이나 조회 수 같은 경우에 사용하면 좋을거 같습니다. @Entity @DynamicUpdate public class Product { ... } 2022. 2. 18.
스프링 레디스 최근 검색어 관리하기 거래 플랫폼 프로젝트를 진행하던중 검색 창에 최근 검색어 기능 추가를 했으면 좋겠다는 의견이 있었습니다. 2가지 방법을 생각했는데 첫번째는 search 엔티티를 만들어 관리하는 방식이었습니다. 두번째는 레디스에서 최근 검색어를 위해 리스트 자료구조를 이용해서 관리하는 방식을 생각했습니다. 첫 번째 방식은 인메모리 캐시 방식인 레디스에 비해 속도가 느릴거 같고 관리 측면에서도 원하는 사이즈가 꽉 찾을때 시간순으로 정렬한 후에 가장 오래된 컬럼을 삭제하고 다시 insert를 해야한다는 점이 번거로웠습니다. 그래서 엔티티를 아예 만들지않고 accountId로 식별할 수 있는 레디스 리스트를 만들어서 관리하는 방식을 택했습니다. 로직은 사용자가 검색을 하게되면 accesstoken으로 사용자를 조회하고, 키 값.. 2022. 2. 10.
스프링 Redis로 캐시 처리하기 조회 수, 방문자 수 업데이트 지난 글에서 우리 프로젝트에 개별 상품 조회를 redis로 캐싱 처리했었습니다. 캐시 삭제 주기를 6시간으로 많은 시간을 두고 했었는데 이렇게 설정하게 되면 그 사이에 조회 수가 올라도 이미 cacheable로 캐시에 반영이 되어 있어서 아무리 상품 조회를 많이 해도 조회수가 늘지 않는다는 것입니다. 선택지는 두 가지가 있었습니다. 첫 번째. 조회수 전용 엔티티를 만들어 따로 관리합니다. 상대적으로 적은 어트리뷰트를 가지면서 그에 따른 시간 이득이 있을 수 있으나 인메모리 기반 레디스에 비하면 속도가 현저히 늦을거라고 생각했습니다. 두 번째. redis에 조회수만 담당하는 캐시를 올리자. 본래는 product 엔티티를 전부 올려 그 때마다 데이터를 읽어 조회수 카운트를 올릴 생각이었습니다. 그러나 key.. 2022. 2. 8.
스프링 무한스크롤 페이징 검색 처리 및 동적쿼리 적용하기 목적 프로젝트에서 무한 스크롤 기능과 동적 쿼리를 활용해 카테고리별 정렬, 키워드 검색 등을 수행하기 위해 만들었습니다. 장점 원래 프로젝트에는 /api/product/views,/api/product/time, /api/product/category로 나뉘어져 각 조회마다 다른 기능을 하도록 되어 있었습니다. 그러다 보니 코드의 양도 몇 배가 늘어버리고, 단순히 검색이라는 키워드 안에 여러가지 api가 섞여버려 본래의 목적을 읽어버린 느낌까지 들었습니다. 페이징과, 동적 쿼리를 적용 시키고 난 후엔 검색용 api가 통합되어 알아보기 쉽게 만들어졌고 프론트엔드에서도 쿼리 파라미터에 추가만 하면 되니 사용법이 쉬워진 것 같습니다. 코드의 양적으로 봐도 훨씬 줄어 클린 코드가 만들어지게 됐습니다. 단점은 U.. 2022. 2. 7.
QueryDsl 기본 문법 보호되어 있는 글 입니다. 2022. 2. 7.
스프링 부트 queryDsl 환경 설정하기 사용 환경 스프링부트 : 2.5.9 버전 2.6 이상부터는 에러가 납니다 build.gradle에서 여러가지 추가해야 합니다. 1. dependencies에 추가 //querydsl 추가 implementation 'com.querydsl:querydsl-jpa' implementation 'com.querydsl:querydsl-core' 2. 쿼리 파라미터 로그 남기기 //로그 남길때 implementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.5.8' 3. build.gradle 최 상단에 추가 buildscript { ext { queryDslVersion = "5.0.0" } } 4. plugins에 아래 코드 추가 id "com.e.. 2022. 2. 5.