반응형
해당 글에서는 QueryDSL을 초기 환경설정을 하는 방법과 이를 이용하여서 간단한 예시를 구성하는 방법에 대해 알아봅니다.
💡 [참고] JPA 관련해서 구성 내용에 대해 궁금하시면 아래의 글을 참고하시면 도움이 됩니다.
분류 | 링크 |
Spring Boot Data JPA -1: ORM, JPA, Hibernate, QueryDSL 이론 | https://adjh54.tistory.com/421 |
Spring Boot Data JPA -2: 초기 환경 구성 + JpaRepository 활용 방법 | https://adjh54.tistory.com/422 |
Spring Boot Data JPA -3: 상세 JpaRepository 활용 방법 | https://adjh54.tistory.com/481 |
Spring Boot Data JPA 엔티티 어노테이션 -1 : 테이블 컬럼 단위 | https://adjh54.tistory.com/466 |
Spring Boot Data JPA 엔티티 어노테이션 -2 : 엔티티(테이블)간의 관계 | https://adjh54.tistory.com/477 |
Spring Boot Data JPA FetchType 이해하기 : 즉시/지연로딩 | https://adjh54.tistory.com/476 |
Spring Boot Data JPA : JPQL 활용 방법 | https://adjh54.tistory.com/479 |
Spring Boot Data JPA : Criteria API 활용 방법 | https://adjh54.tistory.com/483 |
Spring Boot Data JPA : QueryDSL 활용 방법-1 : 정의 및 구성요소 | https://adjh54.tistory.com/484 |
Spring Boot Data JPA : QueryDSL 활용 방법-2 : 초기환경 설정 및 사용예시 | https://adjh54.tistory.com/485 |
1) QueryDSL(Domain-Specific Languages)
💡 QueryDSL
- Java 언어를 기반으로 타입-세이프한 쿼리 빌더 프레임워크를 의미합니다.
- 다양한 데이터베이스 플랫폼(RDBMS, NoSQL 등)에 접근하여 SQL과 유사한 문법을 ‘자바 코드’를 통해서 작성하고 데이터 처리를 수행합니다. 또한, 쿼리를 작성할 때, 컴파일 시점에 타입에 대한 오류를 검출하여 런타임 시점에서 발생할 오류를 사전에 방지합니다.
[ 더 알아보기 ]
💡 타입-세이프(Type-Safe)
- 데이터 타입을 엄격하게 검사하여 타입의 불일치로 인한 오류를 방지하는 것을 의미합니다.
- 이는 컴파일 시점에 데이터 타입이 맞지 않는 경우 오류를 검출하며, 런타임에서 발생할 수 있는 오류를 최소화하고 코드의 안정성과 신뢰성을 높이는데 도움을 줍니다.
2) QueryDSL 사전 설정
1. 환경 설정 전 알아야 할 것 : Spring Boot 버전 별 패키지 참조
💡 환경 설정 전 알아야 할 것 : Spring Boot 버전 별 패키지 참조
- Spring Boot 2.6.x인 경우와 Spring Boot 3.x.x인 경우에 따라서 각각 '패키지'가 달라지기에 환경에 따라 확인해보아야 합니다.
버전 | JPA 패키지 |
Spring Boot 2.6.x | import javax.persistence.*; |
Spring Boot 3.x.x | import jakarta.persistence.*; |
💡 Spring Boot 2.6.x 버전의 경우 import javax.persistence.*; 를 사용하며 import jakarta.persistence.*; 는 사용되지 않습니다.
💡 Spring Boot 3.x.x 패키지인 경우 import jakarta.persistence.*; 를 사용하며 import javax.persistence.*; 는 사용되지 않습니다.
2. IntelliJ 설정 : Build and Run
💡 IntelliJ 설정 : Build and Run
- QueryDSL 사용에 있어서 ‘IntelliJ IDEA’의 내장 기능을 이용하는 것이 좋습니다. 이는 IntelliJ IDEA가 제공하는 자동완성, 코드 생성, 리팩토링 도구 등을 활용하여 QueryDSL 코드를 더욱 효율적으로 작성하고 관리할 수 있기 때문입니다.
- 또한, IntelliJ IDEA는 QueryDSL과 호환되는 플러그인을 제공하므로, 이를 설치하면 QueryDSL 작업을 더욱 용이하게 할 수 있습니다
Build and run using / Run tests using | 설명 |
Gradle | Gradle를 이용해 빌드와 테스트를 실행합니다. |
IntelliJ IDEA | IntelliJ IDEA의 내장 기능을 이용해 빌드와 테스트를 실행합니다. |
2.1. Settings.. 를 선택합니다.
2.2. Build, Execution, Deployment > build Tools > Gradle
💡 Build, Execution, Deployment > build Tools > Gradle
- Build and run using : Gradle에서 IntelliJ IDEA로 변경
- Run and tests using :Gradle에서 IntelliJ IDEA로 변경
3. .gitignore 파일 내 경로 추가
💡 .gitignore 파일 내 경로 추가
- Q-Class가 생성될 예정일 경로에 github 내에 저장소에 포함되지 않기 위해 제외할 경로를 추가합니다.
/src/main/generated/
3) QueryDSL 환경설정 : build.gradle
1. dependencies 추가
💡 dependencies 추가
- QueryDSL에 주요 사용되는 라이브러리를 추가합니다
패키지 | 설명 | 상세 설명 |
com.querydsl:querydsl-jpa | QueryDSL 내에서 JPA 사용을 지원을 제공합니다. | - SQL, NoSQL을 사용할 때 데이터 액세스하기 위한 방법을 제공하며, 컴파일 시점에 쿼리에 대한 오류를 감지하고 IDE의 자동 완성 기능을 사용하여 쿼리를 쉽게 작성하고 유지 관리할 수 있게 돕습니다. |
com.querydsl:querydsl-apt | QueryDSL의 어노테이션 처리 도구를 제공합니다. | - 도메인 클래스의 구조가 변경될 때마다 메타 모델(Q-Class)를 수동으로 수정하는 번거로움 없이, 변경된 구조에 맞는 쿼리를 안전하게 작성할 수 있습니다. |
jakarta.annotation:jakarta.annotation-api | Jakarta의 어노테이션 API를 제공합니다. | - 개발자들은 웹 애플리케이션 개발 시 필요한 어노테이션들을 활용하여 코드를 작성할 수 있습니다. |
jakarta.persistence:jakarta.persistence-api | Jakarta의 Persistence API를 제공합니다. | - 데이터베이스와의 상호작용을 추상화하여 개발자가 직접 SQL 쿼리를 작성하지 않고도 데이터를 저장하고 검색할 수 있게 합니다. 이는 개발 과정을 단순화하고 개발 시간을 줄여주는 장점을 제공합니다. |
// 프로젝트에서 사용하는 전역 변수를 설정
ext {
set('queryDslVersion', "5.0.0")
}
dependencies {
implementation "com.querydsl:querydsl-jpa:${queryDslVersion}:jakarta"
annotationProcessor "com.querydsl:querydsl-apt:${queryDslVersion}:jakarta"
annotationProcessor "jakarta.annotation:jakarta.annotation-api"
annotationProcessor "jakarta.persistence:jakarta.persistence-api"
}
2. QueyDSL 관련 설정 : build.gradle
💡 QueyDSL 관련 설정 : build.gradle
- Gradle 빌드 스크립트 내에 QueryDSL 관련 설정을 합니다. 해당 설정의 주요 목적은 메타 모델(Q-Class)을 생성/삭제하기 위함에 설정을 합니다.
- build complie을 수행하면 엔티티 클래스를 기반으로 지정한 디렉터리 내에 Q-Class를 생성합니다.
- build clean을 수행하면 생성된 디렉터리 내에 Q-Class를 삭제합니다.
1. Q-Class를 생성할 디렉터리 경로를 설정합니다.
- srcDir 내에 추가할 디렉터리 경로를 위해 지정합니다.
2. JavaCompile Task를 수행하는 경우 생성될 소스코드의 출력 디렉터리를 queryDslSrcDir로 설정합니다.
- Gradle의 Task 중 build complie을 수행하면 ‘src/main/generated/querydsl/’ 디렉터리 경로에 파일을 생성합니다.
3. 소스 코드로 인식할 디렉토리에 경로에 Q-Class 파일을 추가합니다. 이렇게 하면 Q-Class가 일반 Java 클래스처럼 취급되어 컴파일과 실행 시 클래스패스에 포함됩니다.
- ‘src/main/generated/querydsl/’ 경로에 소스코드로 인식할 Q-Class를 생성합니다.
4. clean Task를 수행하는 경우 지정한 디렉터리를 삭제하도록 설정합니다. : 자동 생성된 Q-Class를 제거합니다.
- Gradle의 Task 중 build clean을 수행하면 ‘build/generated/querydsl’ 디렉터리 경로의 파일을 삭제합니다.
5. QueryDSL과 관련된 라이브러리들이 컴파일 시점에만 필요하도록 설정합니다. 또한, QueryDSL 설정을 컴파일 클래스패스에 추가합니다.
- 컴파일 시점에 QueryDSL 코드를 인식하고 처리할 수 있게 합니다. 이렇게 함으로써, 불필요한 메모리 사용을 줄이고 런타임 선능을 향상할 수 있습니다.
// 1. Q-Class를 생성할 디렉토리 경로를 설정합니다.
def queryDslSrcDir = 'src/main/generated/querydsl/'
// 2. JavaCompile Task를 수행하는 경우 생성될 소스코드의 출력 디렉토리를 queryDslSrcDir로 설정합니다.
tasks.withType(JavaCompile).configureEach {
options.getGeneratedSourceOutputDirectory().set(file(queryDslSrcDir))
}
// 3. 소스 코드로 인식할 디렉토리에 경로에 Q-Class 파일을 추가합니다. 이렇게 하면 Q-Class가 일반 Java 클래스처럼 취급되어 컴파일과 실행 시 클래스패스에 포함됩니다.
sourceSets {
main.java.srcDirs += [queryDslSrcDir]
}
// 4. clean Task를 수행하는 경우 지정한 디렉토리를 삭제하도록 설정합니다. : 자동 생성된 Q-Class를 제거합니다.
clean {
delete file(queryDslSrcDir)
}
configurations {
compileOnly {
extendsFrom annotationProcessor
}
// 5. QueryDSL과 관련된 라이브러리들이 컴파일 시점에만 필요하도록 설정합니다. 또한, QueryDSL 설정을 컴파일 클래스패스에 추가합니다.
querydsl.extendsFrom compileClasspath
}
[ 더 알아보기 ]
💡 엔티티 클래스의 필드가 변경되는 경우 컴파일만 수행하면 갱신이 되나? 아니면 build clean을 수행해야 하는가?
- 엔티티 클래스의 필드가 변경되는 경우, 컴파일만 수행해도 갱신이 됩니다. 그러나 혹시 모를 상황을 대비하여 변경사항이 반영되지 않았을 경우에는 build clean을 수행한 후 다시 컴파일을 수행하면 됩니다.
💡 서버를 수행하면 complie 과정이 수행되며, buildDir 경로와 srcDir 경로 내에 Q-Class가 생성이 됩니다.
💡 Gradle clean을 수행하면 생성된 파일들이 모두 삭제가 됩니다.
[ 더 알아보기 ]
💡 build.gradle Task
- Gradle 빌드 스크립트에서 특정 작업을 정의하는 블록입니다. 이는 빌드 프로세스의 단계를 나타내며, 각 태스크는 독립적으로 실행될 수 있습니다.
4. JPAQueryFactory 구성
💡 JPAQueryFactory 구성
- JPA 환경을 구성하고 QueryDSL을 사용할 수 있도록 설정하는 클래스입니다.
- 해당 부분에서는 매번 EntityManager를 주입받아서 구성해야 하는 JPAQueryFactory를 bean으로 등록하여 간편하게 사용하기 위한 목적으로 구성하였습니다.
- @EnableJpaAuditing를 통해서 Auditing 기능을 활성화합니다. 이 기능을 활용하면, 엔티티의 생성시간, 수정시간 등을 자동으로 관리할 수 있습니다.
- @PersistenceContext: 이 어노테이션은 JPA의 EntityManager를 주입받습니다. EntityManager는 JPA를 통해 데이터베이스를 사용하는 데 필요한 주요 인터페이스입니다.
package com.adjh.multiflex.jpa.config;
import com.querydsl.jpa.impl.JPAQueryFactory;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
/**
* JPA의 환경설정을 구성합니다.
*
* @author : lee
* @fileName : JPAConfig
* @since : 4/26/24
*/
@Configuration
// Auditing 기능을 활성화하여 엔티티의 생성시간, 수정시간 등을 자동으로 관리합니다.
@EnableJpaAuditing
public class JPAConfig {
// 데이터베이스를 사용하기 위한 주요 인터페이스를 주입받습니다.
@PersistenceContext
private EntityManager em;
/**
* JPAQueryFactory 를 bean으로 구성하여 매번 EntityManager로 부터 주입받는 부분을 줄임.
*
* @return JPAQueryFactory
*/
@Bean
public JPAQueryFactory jpaQueryFactory() {
return new JPAQueryFactory(em);
}
}
💡 [참고] QueryDSL JPAQueryFactory API Document
- JPAQueryFactory의 파라미터로 EntityManager 클래스를 받는 생성자를 이용하여 구성하였습니다.
5. Entity & DTO 구성
💡 Entity & DTO 구성
- Entity는 테이블과 직접적인 매핑이 되는 객체들을 담고 있습니다. 또한 @Entity 어노테이션을 기반으로 Q-Class가 생성되기에 필수적으로 구성이 되어야 합니다.
- DTO의 경우는 API 환경에서 데이터를 주고받는 경우에 데이터를 담고 있고 또한 추가적인 데이터를 포함할 수 있기에 추가적인 구성이 필요합니다.
💡 BoardEntity
- 테이블과 매핑되는 BoardEntity를 구성하였습니다.
package com.adjh.multiflex.jpa.entity;
import jakarta.persistence.*;
/**
* Please explain the class!!
*
* @author : lee
* @fileName : BoardEntity
* @since : 4/8/24
*/
@Entity
@Table(name = "tb_board")
public class BoardEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "board_sq")
private long boardSq;
@Column
private String title;
@Column
private String content;
}
💡 BoardDto
- API 환경에서 데이터를 주고받을 수 있는 DTO(Data Transfer Object)를 구성하였습니다.
package com.adjh.multiflex.jpa.dto;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;
/**
* Please explain the class!!
*
* @author : lee
* @fileName : BoardDto
* @since : 5/2/24
*/
@Getter
@ToString
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class BoardDto {
private long boardSq;
private String title;
private String content;
}
[ 더 알아보기 ]
💡 QueryDSL 내에서는 DTO와 Entity 중 어떤 것을 이용해야 할까?
- 테이블과 직접 매핑되며 데이터 구조를 포함하고 있는 Entity와 데이터를 주고받을 수 있는 DTO(Data Transfer Object)를 별도로 구성하는 것이 좋습니다.
- 별도로 구현을 하게 되면 아래와 같은 장점을 가지고 있습니다.
1. API는 클라이언트에게 필요한 데이터만 전달해야 하는데, 이 경우 DTO는 필요한 데이터만을 선택적으로 포함할 수 있어 효율적입니다.
2. API를 통해 Entity를 직접 전달하게 되면, Entity 클래스의 변경이 API 스펙에 영향을 주게 됩니다. 이는 유지보수를 어렵게 만듭니다. 반면에 DTO를 사용하면 이러한 문제를 방지할 수 있습니다.
3. DTO를 사용하면, 클라이언트가 Entity의 모든 데이터를 알 필요 없이 필요한 데이터만을 간결하게 전달받을 수 있습니다.
6. Dao & DaoImpl 구성
💡 Dao & DaoImpl 구성
- QueryDSL을 이용하여 데이터 처리를 하는 레이어를 구성합니다. 해당 레이어에서 데이터 처리를 위한 인터페이스와 구현체를 구현합니다.
💡 BoardDao(interface) 사용예시
- 데이터 처리를 처리하기 위한 인터페이스를 구성하였습니다.
메서드 | 리턴 값 | 설명 |
selectBoardList | List<BoardDto> | 게시판 리스트를 조회합니다. |
insertBoard | long | 게시판 글을 등록합니다 |
updateBoard | long | 게시판 글을 수정합니다 |
deleteBoard | long | 게시판 글을 삭제합니다. |
package com.adjh.multiflex.jpa.dao;
import com.adjh.multiflex.jpa.dto.BoardDto;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
* 게시판 DAO 인터페이스
*
* @author : lee
* @fileName : BoardDao
* @since : 5/2/24
*/
@Repository
public interface BoardDao {
// 게시판 리스트를 조회합니다.
List<BoardDto> selectBoardList(BoardDto boardDto);
// 게시판 글을 등록합니다.
long insertBoard(BoardDto boardDto);
// 게시판 글을 수정합니다.
long updateBoard(BoardDto boardDto);
// 게시판 글을 삭제합니다.
long deleteBoard(BoardDto boardDto);
}
💡 BoardDaoImpl 사용예시
- QueryDSL을 이용하여서 데이터베이스와 연결되어 데이터 처리를 수행합니다.
메서드 | 리턴 값 | 설명 |
selectBoardList | List<BoardDto> | 게시판 리스트를 조회합니다. |
insertBoard | long | 게시판 글을 등록합니다 |
updateBoard | long | 게시판 글을 수정합니다 |
deleteBoard | long | 게시판 글을 삭제합니다. |
package com.adjh.multiflex.jpa.dao.impl;
import com.adjh.multiflex.jpa.dao.BoardDao;
import com.adjh.multiflex.jpa.dto.BoardDto;
import com.adjh.multiflex.jpa.entity.QBoardEntity;
import com.querydsl.core.types.Projections;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.core.util.StringUtils;
import com.querydsl.jpa.impl.JPADeleteClause;
import com.querydsl.jpa.impl.JPAQueryFactory;
import com.querydsl.jpa.impl.JPAUpdateClause;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
/**
* QueryDSL의 데이터 처리를 위한 Dao의 구현체
*
* @author : lee
* @fileName : BoardDaoImpl
* @since : 5/2/24
*/
@Repository
public class BoardDaoImpl implements BoardDao {
// 1. 구성한 JPAQueryFactory를 로드 합니다.
private final JPAQueryFactory queryFactory;
// 데이터베이스와 매핑된 boardEntity 클래스를 Q-Class
private final QBoardEntity qBoard = QBoardEntity.boardEntity;
@PersistenceContext
private EntityManager em;
public BoardDaoImpl(JPAQueryFactory queryFactory) {
this.queryFactory = queryFactory;
}
/**
* 게시판 리스트를 전체 조회합니다.
*
* @param boardDto
* @return
*/
@Override
@Transactional(readOnly = true)
public List<BoardDto> selectBoardList(BoardDto boardDto) {
return queryFactory
.select(Projections.fields(BoardDto.class, qBoard.boardSq, qBoard.title, qBoard.content, qBoard.boardType))
.from(qBoard)
.where(
eqTitle(boardDto.getTitle()),
eqContent(boardDto.getContent())
)
.orderBy(qBoard.boardSq.desc())
.fetch();
}
/**
* 게시판 글을 등록합니다.
*
* @param boardDto
* @return
*/
@Override
@Transactional
public long insertBoard(BoardDto boardDto) {
return queryFactory
.insert(qBoard)
.columns(qBoard.title, qBoard.content)
.values(boardDto.getTitle(), boardDto.getContent())
.execute();
}
/**
* 게시판 글을 수정합니다.
*
* @param boardDto
* @return
*/
@Override
@Transactional
public long updateBoard(BoardDto boardDto) {
JPAUpdateClause updateClause = new JPAUpdateClause(em, qBoard);
// title 값이 존재하는 경우 수행
if (boardDto.getTitle() != null && !boardDto.getTitle().equals("")) {
updateClause.set(qBoard.title, boardDto.getTitle());
}
// content 값이 존재하는 경우 수행
if (boardDto.getContent() != null && !boardDto.getContent().equals("")) {
updateClause.set(qBoard.content, boardDto.getContent());
}
return updateClause
.where(qBoard.boardSq.eq(boardDto.getBoardSq()))
.execute();
}
/**
* 게시판 글을 삭제합니다.
*
* @param boardDto
* @return
*/
@Override
@Transactional
public long deleteBoard(BoardDto boardDto) {
return queryFactory
.delete(qBoard)
.where(qBoard.boardSq.eq(boardDto.getBoardSq()))
.execute();
}
/**
* title 값이 존재하는 경우 조건절로 추가 됩니다.
*
* @param title {String}
* @return BooleanExpression
*/
private BooleanExpression eqTitle(String title) {
if (StringUtils.isNullOrEmpty(title)) return null;
return qBoard.title.eq(title);
}
/**
* content 값이 존재하는 경우 조건절로 추가됩니다.
*
* @param content {String}
* @return BooleanExpression
*/
private BooleanExpression eqContent(String content) {
if (StringUtils.isNullOrEmpty(content)) return null;
return qBoard.content.containsIgnoreCase(content);
}
}
7. Service & ServiceImpl 구성
💡 Service & ServiceImpl 구성
- 비즈니스 로직을 처리하는 레이어입니다. 해당 레이어에서는 간단하게 호출을 하는 인터페이스와 구현체 형태로 구성하였습니다.
💡 BoardService(Interface) 사용예시
- 비즈니스 로직에 대한 인터페이스로 구성하였습니다.
메서드 | 리턴 값 | 설명 |
selectBoardList | List<BoardDto> | 게시판 리스트를 조회합니다. |
insertBoard | long | 게시판 글을 등록합니다 |
updateBoard | long | 게시판 글을 수정합니다 |
deleteBoard | long | 게시판 글을 삭제합니다. |
package com.adjh.multiflex.jpa.service;
import com.adjh.multiflex.jpa.dto.BoardDto;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* 게시판 서비스 인터페이스
*
* @author : jonghoon
* @fileName : BoardService
* @since : 5/4/24
*/
@Service
public interface BoardService {
// 게시판 리스트를 조회합니다.
List<BoardDto> selectBoardList(BoardDto boardDto);
// 게시판 글을 등록합니다.
long insertBoard(BoardDto boardDto);
// 게시판 글을 업데이트 합니다.
long updateBoard(BoardDto boardDto);
// 게시판 글을 삭제합니다.
long deleteBoard(BoardDto boardDto);
}
💡 BoardServiceImpl 사용예시
- 해당 비즈니스 로직은 별도 처리를 포함하지 않아서 호출을 하는 형태로만 구성되어 있습니다.
메서드 | 리턴 값 | 설명 |
selectBoardList | List<BoardDto> | 게시판 리스트를 조회합니다. |
insertBoard | long | 게시판 글을 등록합니다 |
updateBoard | long | 게시판 글을 수정합니다 |
deleteBoard | long | 게시판 글을 삭제합니다. |
package com.adjh.multiflex.jpa.service.impl;
import com.adjh.multiflex.jpa.dao.BoardDao;
import com.adjh.multiflex.jpa.dto.BoardDto;
import com.adjh.multiflex.jpa.service.BoardService;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* 게시판과 관련된 비즈니스 로직을 구성합니다.
*
* @author : jonghoon
* @fileName : BoardServiceImpl
* @since : 5/4/24
*/
@Service
public class BoardServiceImpl implements BoardService {
private BoardDao boardDao;
public BoardServiceImpl(BoardDao boardDao) {
this.boardDao = boardDao;
}
@Override
public List<BoardDto> selectBoardList(BoardDto boardDto) {
return boardDao.selectBoardList(boardDto);
}
@Override
public long insertBoard(BoardDto boardDto) {
return boardDao.insertBoard(boardDto);
}
@Override
public long updateBoard(BoardDto boardDto) {
return boardDao.updateBoard(boardDto);
}
@Override
public long deleteBoard(BoardDto boardDto) {
return boardDao.deleteBoard(boardDto);
}
}
8. Controller 구성
💡 Controller 구성
- Restful API 형태로 Controller를 구성하였습니다.
Endpoint | HTTP Method | 메서드 | 리턴 값 | 설명 |
/api/v1/board/boards | POST | selectBoardList | List<BoardDto> | 게시판 리스트를 조회합니다. |
/api/v1/board/board | POST | insertBoard | long | 게시판 글을 등록합니다 |
/api/v1/board/board | PUT | updateBoard | long | 게시판 글을 수정합니다 |
/api/v1/board/board | DELETE | deleteBoard | long | 게시판 글을 삭제합니다. |
package com.adjh.multiflex.jpa.controller;
import com.adjh.multiflex.jpa.dto.BoardDto;
import com.adjh.multiflex.jpa.service.BoardService;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 게시판 관리 Controller
*
* @author : jonghoon
* @fileName : BoardController
* @since : 5/4/24
*/
@RestController
@RequestMapping("/api/v1/board")
public class BoardController {
private final BoardService boardService;
public BoardController(BoardService boardService) {
this.boardService = boardService;
}
/**
* 게시판 리스트 조회
*
* @param boardDto
* @return
*/
@PostMapping("/boards")
public ResponseEntity<List<BoardDto>> selectUserList(@RequestBody BoardDto boardDto) {
List<BoardDto> boardDtoList = boardService.selectBoardList(boardDto);
return new ResponseEntity<>(boardDtoList, HttpStatus.OK);
}
/**
* 게시판 글 등록
*
* @param boardDto
* @return
*/
@PostMapping("/board")
public ResponseEntity<Long> insertBoard(@RequestBody BoardDto boardDto) {
long result = boardService.insertBoard(boardDto);
return new ResponseEntity<>(result, HttpStatus.OK);
}
/**
* 게시판 글 수정
*
* @param boardDto
* @return
*/
@PutMapping("/board")
public ResponseEntity<Long> updateBoard(@RequestBody BoardDto boardDto) {
long result = boardService.updateBoard(boardDto);
return new ResponseEntity<>(result, HttpStatus.OK);
}
/**
* 게시판 글 삭제
*
* @param boardDto
* @return
*/
@DeleteMapping("/board")
public ResponseEntity<Long> deleteBoard(@RequestBody BoardDto boardDto) {
long result = boardService.deleteBoard(boardDto);
return new ResponseEntity<>(result, HttpStatus.OK);
}
}
4) 결과 확인
1. 게시판 글 등록
💡 게시판 글 등록 : API 호출
- 호출 결과 값으로 1을 반환받았습니다.
💡 게시판 글 등록 : 서버 콘솔 확인
- 아래와 같은 insert 쿼리가 수행이 되었습니다.
2. 게시판 글 목록 조회
💡 게시판 글 등록 : API 호출
- 호출 결과값을 반환받음을 확인하였습니다.
💡 게시판 글 등록 : 서버 콘솔 확인
- 아래와 같은 쿼리가 수행됨을 확인하였습니다.
3. 게시판 글 목록 수정
💡 게시판 글 목록 수정 : API 호출
- 호출 결과 값으로 1을 반환받았습니다.
💡 게시판 글 수정 : 서버 콘솔 확인
- 아래와 같은 쿼리가 수행됨을 확인하였습니다.
4. 게시판 글 목록 삭제
💡 게시판 글 목록 삭제 : API 호출
- 호출 결과 값으로 1을 반환받았습니다.
💡 게시판 글 목록 삭제 : 서버 콘솔 확인
- 아래와 같은 쿼리가 수행됨을 확인하였습니다.
오늘도 감사합니다. 😀
반응형