전체 글 70

QueryDSL 이란?

하이버네이트 쿼리 언어의 쿼리를 타입에 안전하게 생성 및 관리해주는 프레임워크로, 자바 백엔드에서 Spring Data JPA를 함께 사용한다. 하지만 JPA로 복잡한 쿼리, 동적 쿼리를 구현하는데 한계가 있기 때문에 이를 해결할 수 있는 것이 QueryDSL 이다.Mybatis, JPQL 등 문자열 형태로 쿼리문을 작성하여 컴파일 시에 오류를 발견하는 것이 불가능했지만, QueryDSL은 자바 코드로 SQL문을 작성할 수 있기 때문에 컴파일 시에 발생하는 오류를 확인할 수 있다. 예를 들어서 복잡한 검색 조건이 있다고 가정해보자public interface MemberRepository extends JpaRepository { // 이름이 포함되고, 특정 나이 이상이며, 특정 지역에 사는 활..

Spring Security + JWT 로그인 구현하기

Spring Security 란?스프링 기반의 애플리케이션의 보안을 담당하는 프레임워크이다.필터 기반으로 동작하기 때문에 스프링 MVC와 분리되어 관리 및 동작한다. Spring에서 모든 호출은 DispatcherServlet을 통과하게 되고seungg8361.tistory.comController에서 @PostMapping("/login")을 처리하지 않고 filter에서 로그인을 처리해 보자. 먼저 Spring Security 관련 작업을 진행해 보자// Spring Security에서 사용자의 상세 정보를 담는 클래스 -> 실제 인증된 사용자의 정보를 담고있다.public class UserDetailsImpl implements UserDetails { private final User us..

RestTemplate란?

RESTful 웹 서비스를 호출하고 응답을 처리하기 위한 템플릿 클래스로, HTTP 요청 및 응답을 보다 쉽게 주고받을 수 있도록 도와준다. HTTP GET 메서드   getForObject(url, responseType)   getForEntity(url, responseType)HTTP POST 메서드   postForObject(url, request, responseType)   postForEntity(url, request, responseType)HTTP PUT 메서드   put(url, request)HTTP DELETE 메서드   delete(url)HTTP HEAD 메서드   headForHeaders(url)HTTP OPTIONS 메서드   optionsForAllow(url)HTT..

Docker를 배워보자

. jar 파일과 같이 실행되지 않는 os이다. 라이브러리와 기타 종속성에 대한 정의, 실행되는 코드가 포함되어 있다.애플리케이션과 관련된 모든 파일과 라이브러리를 포함하고 있기 때문에 다른 환경에서도 동일한 애플리케이션을 실행할 수 있다.이미지가 한 번 생성되면 변경할 수 없다.도커 이미지는 필요한 파일만 포함하고 있기 때문에 용량이 적다. 만약 이미지를 변경해야 한다면 새로운 이미지를 생성해야 한다. Registry/ dockerhub에 저장되어 있는 image를 pull 하고 Container를 run 하게 된다.Dockerfile로 image를 build 하고 dockerhub에 push를 할 수도 있다. 또는 자신의 Container에서 run 할 수 있다.cd ~mkdir {하위 디렉토리}cd..

JPA의 N+1 문제란?

연관 관계가 설정된 entity를 조회할 경우에, 조회된 데이터 개수만큼 연관 관계의 조회 쿼리가 추가로 발생하는 현상이다. ex) 게시글과 댓글이 있는 경우, 게시글을 조회한 후 게시글마다 댓글을 조회하기 위한 추가 쿼리가 발생 # JPQL 구문ex) findAll() == SELECT u FROM User uSpring Data Jpa에서 제공하는 repository의 findAll() 메서드를 Global Fetch 전략을 즉시로딩으로 설정하고 실행하면 N+1 문제가 발생한다. JPQL은 Global Fetch 전략을 고려하지 않고 쿼리를 실행한다.즉, 모든 user를 조회하는 쿼리를 실행 후, 즉시로딩 설정을 보고 연관관계에 있는 모든 entity를 조회하는 쿼리를 실행한다. Global Fetc..

🖥️ Back-end 2025.02.21

프로젝트 기록하기 3

메뉴 등록 (Owner, Manager)메뉴를 등록하기 위해 POST /api/menus 기능을 구현함.메뉴 등록은 OWNER, MANAGER만 가능하도록 @PreAuthorize() 어노테이션 사용.메뉴를 등록할 때 이미지를 리스트로 요청해서 메뉴 이미지 목록을 보여줄 수 있는 기능을 사용.특정 매장의 메뉴 목록 조회 (All)특정 매장의 메뉴 목록을 조회하기 위해 GET /api/menus? storeId=? 기능을 구현함.메뉴의 존재 유·무를 false, true로 관리해서 메뉴가 존재한다면 false로 관리함. true상태의 메뉴는 조회 불가능.메뉴 상세 조회 (All)메뉴를 상세하게 조회하기 위해 GET /api/menus/{menuId} 기능을 구현함.매장의 정보와 관심 있는 메뉴의 상세한 정..

프로젝트 기록하기 2

전체 매장 목록 조회 (Master)전체 매장을 조회하기 위해 GET /api/admin/stores/{userId} 기능 구현.조회를 시도하는 유저의 권한을 확인한 뒤 매장의 유·무와 상태를 반환했기에 간단하게 구현했다.특정 매장 강제 삭제 (Master)특정 매장을 삭제하기 위해 DELETE /api/admin/stores/{storeId} 기능 구현.불법 매장 또는 관리자가 매장 폐업을 결정하고 삭제할 수 있도록 기능을 구현.삭제 요청을 승인하는 흐름과 비슷하게 실제로 데이터베이스에 삭제되지 않고 상태값을 변경함.매장 등록, 삭제 요청 승인 (Master)매장을 등록, 삭제 요청하기 위해 PUT /api/admin/stores/{storeId}/approve 기능 구현.매장 주인이 매장을 등록. 삭..

프로젝트 기록하기 1

프로젝트 이름: bedelivery개발 환경:Java: 17Spring Boot: 3.3.9데이터베이스: PostgreSQL개발 도구: Docker, Github매장 등록 요청 (Owner)매장 등록을 요청하기 위한 GET /api/stores/{userId} Controller 기능 구현.응답 객체와 메시지, HttpStatus code를 같이 묶어서 응답할 수 있게 ApiResponseData 클래스 생성.매장 등록을 요청할 시 enum 으로 정의한 Status.PENDING 으로 설정하게 함.업종과 지역을 관리하는 엔티티 구현 (매장과 업종은 N:N 단방향 관계, 매장과 지역은 1:N 단방향 관계).매장 등록 요청 사항을 먼저 저장한 뒤, 업종 테이블을 조회해서 가져온 데이터를 매장과 업종의 중간 ..

JPA의 ddl-auto 옵션이란?

스프링 부트 애플리케이션에서 Hibernate와 같은 JPA 구현체를 사용할 때 데이터베이스 스키마 관리를 제어하는 설정이다.application.properties 또는 application.yml 파일에 설정할 수 있다.  application.properties ▼# 중에 상황에 맞는 설정을 하나 추가해주면 된다.spring.jpa.hibernate.ddl-auto=nonespring.jpa.hibernate.ddl-auto=validatespring.jpa.hibernate.ddl-auto=updatespring.jpa.hibernate.ddl-auto=createspring.jpa.hibernate.ddl-auto=create-drop  none : 데이터베이스 스키마와 관련된 어떠한 작업도 수..

🖥️ Back-end 2025.02.17

Spring Data JPA에서 새로운 Entity를 판단하는 방법?

새로운 Entity인지 판단하는 이유는 SimpleJpaRepository의 save() 메서드에서 isNew()를 사용하여 persist와 merge를 수행할지 결정하는데, 만약 ID를 직접 지정해 주는 경우에는 신규 entity라고 판단하지 않아서 merge를 수행하게 된다. 이때 해당 entity는 신규임에도 불구하고 DB를 조회하기 때문에 비효율적이기 때문에 새로운 entity인지 판단하는 것은 매우 중요하다.@Transactional public S save(S entity) { Assert.notNull(entity, "Entity must not be null"); if (this.entityInformation.isNew(entity)) { ..

🖥️ Back-end 2025.02.14