[Spring Boot]JPACustom

JPAExam과 동일하게 설정

2023.10.16 - [분류 전체보기] - JPAExam

 

JPAExam

06_Backend 하위폴더에 04_JPAExam 폴더생성 JPAExam 프로젝트 만들기 버전 2.7.16으로 설정하고 종속성 5개 체크 build gradle (dependencies 수정) dependencies { // TODO : 오라클 라이브러리( 19c ) implementation 'co m.oracl

dobear.tistory.com

Dept

DeptRespository

package com.example.jpacustomexam.repository;

import com.example.jpacustomexam.dto.DeptEmpDto;
import com.example.jpacustomexam.dto.DeptGroupDto;
import com.example.jpacustomexam.model.Dept;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import java.util.List;

/**
 * packageName : com.example.jpacustomexam.repository
 * fileName : DeptRepository
 * author : GGG
 * date : 2023-10-17
 * description : 부서 레포지토리 (기본 CRUD 함수)
 * 요약 :
 * <p>
 * ===========================================================
 * DATE            AUTHOR             NOTE
 * —————————————————————————————
 * 2023-10-17         GGG          최초 생성
 */
@Repository
public interface DeptRepository extends JpaRepository<Dept, Integer> {
    //    개발자 직접 sql 작성 하는 기능(JPQL) : 1) 쿼리메소드 : 함수이름으로 sql문 만들기(낙타표기법 비슷)
//                                         예) 컬럼명 사용 : 첫글자는 대문자 , 단어사이는 대문자
//                                       2) @Query 쓰는 방법
//    쿼리메소드 예) findAllByOrderByDnoDesc : findAll - 전체조회
//                                           OrderBy - 정렬(Order by)
//                                           Dno     - 대상 컬럼명
//                                           Desc    - 내림차순 [Asc]
//    ------------------------------------------------
//    쿼리메소드 예제
//    ------------------------------------------------
//    todo: 1) 전체 조회 + 정렬(내림차순)
    List<Dept> findAllByOrderByDnoDesc();

    //    todo: 2) 전체 조회 + 정렬(부서명 내림차순)
    List<Dept> findAllByOrderByDnameDesc();

    //    todo: 3) 전체 조회 + 오름차순(dno) : Asc 생략가능
    List<Dept> findAllByOrderByDno();

    //    todo: 4) dname like 검색(DnameContaining) + dname 내림차순 조회
    List<Dept> findAllByDnameContainingOrderByDnameDesc(String dname);
//    ---------------------------------------
//    @Query 예제 : 1) 오라클 쿼리 2) 객체 쿼리
//    ---------------------------------------
//  todo: 1) dname like 검색
@Query(value = "SELECT TD.* FROM TB_DEPT TD WHERE TD.DNAME LIKE '%' || :dname || '%'", nativeQuery = true)
List<Dept> selectByDname(@Param("dname") String dname);

// todo: 1-1) 위의 꺼 다르게 코딩 : 참고
//@Query(value = "SELECT TD.* FROM TB_DEPT TD WHERE TD.DNAME LIKE '%' || :dname || '%'", nativeQuery = true)
//List<Dept> selectByDname(String dname);
// todo: 1-2) 위의 꺼 다르게 코딩 : 참고
//@Query(value = "SELECT TD.* FROM TB_DEPT TD WHERE TD.DNAME LIKE '%' || ?1 || '%'", nativeQuery = true)
//List<Dept> selectByDname(String dname);

// todo: 2) dname like 검색 : 추천 ( 객체 쿼리)
//    객체쿼리 만드는 방법 : 테이블 -> 클래스명
//                       컬럼명 -> 속성명
//                       * -> 사용하지 않음, 클래스명의 별칭을 붙여서 사용
//                       (대소문자 구분)
//@Query(value = "SELECT TD FROM TB_Dept TD WHERE TD.dname LIKE '%' || :dname || '%'")
//List<Dept> selectByDname(@Param("dname") String dname);

//    todo: 3) 부서테이블에서 부서명(dname)과 위치(loc)를 매개변수로 받아
//    조회하는 함수를 작성하려고 한다.
//    단, nativeQuery = true 사용하세요

    @Query(value = "SELECT D.* FROM TB_DEPT D " +
            "WHERE D.DNAME = :dname " +
            "AND   D.LOC   = :loc "
            , nativeQuery = true)
    List<Dept> selectByDnameAndLoc(@Param("dname") String dname,
                                   @Param("loc") String loc);

//  todo:4) 부서테이블의 부서번호를 sum, avg, max, min 값을
//      출력하는 함수를 작성하세요.
//      단,  nativeQuery = true 사용하세요
//      , DTO 클래스에 저장하세요
@Query(value = "SELECT SUM(D.DNO) AS sumVar " +
        "     , AVG(D.DNO) AS avgVar " +
        "     , MAX(D.DNO) AS maxVar  " +
        "     , MIN(D.DNO) AS minVar  " +
        "FROM TB_DEPT D",
        nativeQuery = true)
List<DeptGroupDto> selectByGroupFunc();

//    todo: 5) SQL 기본 내장 함수를 사용하는 함수를 작성하세요.
//      단,  nativeQuery = true 사용하세요
    @Query(value = "SELECT UPPER(D.DNAME) AS upperDname\n" +
            "     , LOWER(D.DNAME) AS lowerDname\n" +
            "     , Trim(' Oracle ') As trimOracle\n" +
            "     , TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS') AS charSysdate\n" +
            "FROM TB_DEPT D",
            nativeQuery = true)
    List<DeptGroupDto> selectByBasicFunc();

//    todo: 6) SQL 기본 내장 함수를 사용하는 함수를 작성하세요.
//      단,  nativeQuery = true 사용하세요
//    todo: 6) case when 사용 쿼리
//     dno < 20 연말 보너스 100%
//     dno > 20   연말 보너스 200%
//     모두 아니면 연말 보너스 없음 이라고 출력하세요
@Query(value = "SELECT D.DNO, " +
        "       CASE WHEN D.DNO <20 THEN '연말 보너스 100%' " +
        "            WHEN D.DNO >20 THEN '연말 보너스 200%' " +
        "            ELSE '연말 보너스 없음' " +
        "        END AS incentive " +
        "FROM TB_DEPT D ",
        nativeQuery = true)
List<DeptGroupDto> selectByCase();

//    ----------------------------------------------
//    JPA 페이징 처리 : 요청 페이징 객체 - Pageable (매개변수)
//                    결과 페이징 객체 - Page      (리턴값)
//    -----------------------------------------------
//    1) 쿼리 메소드 : 함수명으로 sql 문 실행하기
//    1-1) dname like 검색
    Page<Dept> findAllByDnameContaining(String dname, Pageable pageable);


//    1-2) 쿼리 메소드 : findAll() (jpa 기본함수)

    //    2) @Query : 페이징 처리 (오라클 쿼리 : countQuery 속성 추가)
    @Query(value = "SELECT D.* FROM TB_DEPT D " +
            "WHERE D.DNAME LIKE '%' || :dname || '%'",
            countQuery = "SELECT COUNT(*) FROM TB_DEPT D " +
                    "WHERE D.DNAME LIKE '%' || :dname || '%'",
            nativeQuery = true)
    Page<Dept> selectByDnamePage(@Param("dname") String dname,
                                 Pageable pageable);

    //    3) @Query 페이징 + 조인(부서 + 사원) : DeptEmpDto
    @Query(value = "SELECT D.*, E.ENO, E.ENAME, E.SALARY " +
            "FROM TB_DEPT D, TB_EMP E " +
            "WHERE D.DNO = E.DNO ",
            countQuery = "SELECT COUNT(*) " +
                    "FROM TB_DEPT D, TB_EMP E " +
                    "WHERE D.DNO = E.DNO ",
            nativeQuery = true)
    Page<DeptEmpDto> selectNativeJoinPage(Pageable pageable);
}


dto폴더에

DeptEmpDto

package com.example.jpacustomexam.dto;

/**
 * packageName : com.example.jpacustomexam.dto
 * fileName : DeptEmpDto
 * author : GGG
 * date : 2023-10-18
 * description : 부서 + 사원 조인용 DTO
 * 요약 :
 * <p>
 * ===========================================================
 * DATE            AUTHOR             NOTE
 * —————————————————————————————
 * 2023-10-18         GGG          최초 생성
 */
public interface DeptEmpDto {
    //    부서번호
    Integer getDno();

    //    부서명
    String getDname();
    //    부서위치
    String getLoc();
    //    사원번호
    Integer getEno();
    //    사원명
    String getEname();
    //    월급
    Integer getSalary();
}

DeptGroupDto

package com.example.jpacustomexam.dto;

/**
 * packageName : com.example.jpacustomexam.dto
 * fileName : DeptGroupDto
 * author : GGG
 * date : 2023-10-18
 * description : DTO 인터페이스 (부서 그룹함수용)
 * 요약 :
 * <p>
 * ===========================================================
 * DATE            AUTHOR             NOTE
 * —————————————————————————————
 * 2023-10-18         GGG          최초 생성
 */
public interface DeptGroupDto {
    //    속성 => 상수 x
//    getter 함수
//    sumVar, avgVar, maxVar, minVar
    Integer getSumVar();
    Integer getAvgVar();
    Integer getMaxVar();
    Integer getMinVar();

    //    예제 5) upperDname(String), lowerDname(String),
//           trimOracle(String), charSysdate(String)
    String getUpperDname();
    String getLowerDname();
    String getTrimOracle();
    String getCharSysdate();

    //    예제 6) dno(Integer), incentive(String)
    Integer getDno();
    String getIncentive();

}

 

DeptService

package com.example.jpacustomexam.service;

import com.example.jpacustomexam.dto.DeptEmpDto;
import com.example.jpacustomexam.dto.DeptGroupDto;
import com.example.jpacustomexam.model.Dept;
import com.example.jpacustomexam.repository.DeptRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * packageName : com.example.jpacustomexam.service
 * fileName : DeptService
 * author : GGG
 * date : 2023-10-17
 * description : 부서 서비스
 * 요약 :
 * <p>
 * ===========================================================
 * DATE            AUTHOR             NOTE
 * —————————————————————————————
 * 2023-10-17         GGG          최초 생성
 */
@Service
public class DeptService {

    @Autowired
    DeptRepository deptRepository; // DI

    /** 전체조회 + 정렬(dno 내림차순) */
//    쿼리메소드 사용한 함수
    public List<Dept> findAllByOrderByDnoDesc() {
        List<Dept> list = deptRepository.findAllByOrderByDnoDesc();

        return list;
    }

    /** 전체조회 + 정렬(dname 내림차순) : 쿼리메소드 */
    public List<Dept> findAllByOrderByDnameDesc() {
        List<Dept> list = deptRepository.findAllByOrderByDnameDesc();

        return list;
    }

    /** 전체조회 + 정렬(dno 오름차순) : 쿼리메소드 */
    public List<Dept> findAllByOrderByDno() {
        List<Dept> list = deptRepository.findAllByOrderByDno();

        return list;
    }

    /** 전체조회 + dname like(Containing) 검색 +정렬(dname 내림차순) : 쿼리메소드 */
    public List<Dept> findAllByDnameContainingOrderByDnameDesc(String dname) {
        List<Dept> list
                = deptRepository.findAllByDnameContainingOrderByDnameDesc(dname);

        return list;
    }

    /** 전체조회 + dname like 검색 : @Query */
    public List<Dept> selectByDname(String dname) {
        List<Dept> list
                = deptRepository.selectByDname(dname);

        return list;
    }

    /** 전체조회 + dname like 검색 : @Query */
    public List<Dept> selectByDnameAndLoc(String dname, String loc) {
        List<Dept> list
                = deptRepository.selectByDnameAndLoc(dname, loc);

        return list;
    }

    /** 전체조회 그룹 함수 검색(dto) : @Query */
    public List<DeptGroupDto> selectByGroupFunc() {
        List<DeptGroupDto> list
                = deptRepository.selectByGroupFunc();

        return list;
    }

    /** 5) 전체조회 기본 함수 검색(dto) : @Query */
    public List<DeptGroupDto> selectByBasicFunc() {
        List<DeptGroupDto> list
                = deptRepository.selectByBasicFunc();

        return list;
    }

    /** 6) 전체조회 case when 검색(dto) : @Query */
    public List<DeptGroupDto> selectByCase() {
        List<DeptGroupDto> list
                = deptRepository.selectByCase();

        return list;
    }
//    --------------------------------------------------
//    페이지 예제
//    --------------------------------------------------
public Page<Dept> findAllByDnameContaining(String dname, Pageable pageable) {
    Page<Dept> page
            = deptRepository.findAllByDnameContaining(dname, pageable);

    return page;
}

    //    2) 기본 제공되는 전체 조회 함수 : 페이징처리 기능 추가
    public Page<Dept> findAllPage(Pageable pageable) {
        Page<Dept> page
                = deptRepository.findAll(pageable);

        return page;
    }

//    --------------------------
//    @Query : 페이징 처리
//    --------------------------
    //    2)  : 페이징처리 기능 추가
    public Page<Dept> selectByDnamePage(String dname, Pageable pageable) {
        Page<Dept> page
                = deptRepository.selectByDnamePage(dname, pageable);

        return page;
    }

    //    3)  조인 : 페이징처리 기능 추가
    public Page<DeptEmpDto> selectNativeJoinPage(Pageable pageable) {
        Page<DeptEmpDto> page
                = deptRepository.selectNativeJoinPage(pageable);

        return page;
    }

}

DeptController

package com.example.jpacustomexam.controller;

import com.example.jpacustomexam.dto.DeptEmpDto;
import com.example.jpacustomexam.dto.DeptGroupDto;
import com.example.jpacustomexam.model.Dept;
import com.example.jpacustomexam.service.DeptService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * packageName : com.example.jpacustomexam.controller
 * fileName : DeptController
 * author : GGG
 * date : 2023-10-17
 * description : 부서 컨트롤러 (react 용)
 * 요약 :
 * <p>
 * ===========================================================
 * DATE            AUTHOR             NOTE
 * —————————————————————————————
 * 2023-10-17         GGG          최초 생성
 */
@Slf4j
@RestController
public class DeptController {

    @Autowired
    DeptService deptService; // DI

    /** 전체 조회 + 정렬(dno 내림차순) : 쿼리메소드 */
    @GetMapping("/dept/desc")
    public ResponseEntity<Object> getDeptAllDesc() {
        try {
//         전체 조회 + 정렬(dno 내림차순) 호출
            List<Dept> list = deptService.findAllByOrderByDnoDesc();

            if (list.isEmpty() == false) {
//                성공
                return new ResponseEntity<>(list, HttpStatus.OK);
            } else {
//                데이터 없음
                return new ResponseEntity<>(HttpStatus.NO_CONTENT);
            }

        } catch (Exception e){
            log.debug(e.getMessage());
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    /** 전체 조회 + 정렬(dname 내림차순) : 쿼리메소드  */
    @GetMapping("/dept/dname/desc")
    public ResponseEntity<Object> findAllByOrderByDnameDesc() {
        try {
//         전체 조회 + 정렬(dno 내림차순) 호출
            List<Dept> list = deptService.findAllByOrderByDnameDesc();

            if (list.isEmpty() == false) {
//                성공
                return new ResponseEntity<>(list, HttpStatus.OK);
            } else {
//                데이터 없음
                return new ResponseEntity<>(HttpStatus.NO_CONTENT);
            }

        } catch (Exception e){
            log.debug(e.getMessage());
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }


    /** 전체 조회 + 정렬(dno 오름차순) : 쿼리메소드  */
    @GetMapping("/dept/dno/asc")
    public ResponseEntity<Object> findAllByOrderByDno() {
        try {
//         전체 조회 + 정렬(dno 오름차순) 호출
            List<Dept> list = deptService.findAllByOrderByDno();

            if (list.isEmpty() == false) {
//                성공
                return new ResponseEntity<>(list, HttpStatus.OK);
            } else {
//                데이터 없음
                return new ResponseEntity<>(HttpStatus.NO_CONTENT);
            }

        } catch (Exception e){
            log.debug(e.getMessage());
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }


    /** 전체조회 + dname like(Containing) 검색 +정렬(dname 내림차순) : 쿼리메소드 */
    @GetMapping("/dept/dname/containing/desc/{dname}")
    public ResponseEntity<Object> findAllByOrderByDno(
            @PathVariable String dname
    ) {
        try {
//         전체 조회 + 정렬(dno 오름차순) 호출
            List<Dept> list
                    = deptService
                    .findAllByDnameContainingOrderByDnameDesc(dname);

            if (list.isEmpty() == false) {
//                성공
                return new ResponseEntity<>(list, HttpStatus.OK);
            } else {
//                데이터 없음
                return new ResponseEntity<>(HttpStatus.NO_CONTENT);
            }

        } catch (Exception e){
            log.debug(e.getMessage());
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }


    /** 전체조회 + dname like 검색 : @Query */
    @GetMapping("/dept/dname/{dname}")
    public ResponseEntity<Object> selectByDname(
            @PathVariable String dname
    ) {
        try {
//         전체 조회 + 정렬(dno 오름차순) 호출
            List<Dept> list
                    = deptService.selectByDname(dname);

            if (list.isEmpty() == false) {
//                성공
                return new ResponseEntity<>(list, HttpStatus.OK);
            } else {
//                데이터 없음
                return new ResponseEntity<>(HttpStatus.NO_CONTENT);
            }

        } catch (Exception e){
            log.debug(e.getMessage());
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    /** 전체조회 + dname and loc 검색 : @Query */
    @GetMapping("/dept/dname/{dname}/loc/{loc}")
    public ResponseEntity<Object> selectByDnameAndLoc(
            @PathVariable String dname,
            @PathVariable String loc
    ) {
        try {
            List<Dept> list
                    = deptService.selectByDnameAndLoc(dname, loc);

            if (list.isEmpty() == false) {
//                성공
                return new ResponseEntity<>(list, HttpStatus.OK);
            } else {
//                데이터 없음
                return new ResponseEntity<>(HttpStatus.NO_CONTENT);
            }

        } catch (Exception e){
            log.debug(e.getMessage());
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    /** 전체조회 + 그룹함수(dto) : @Query */
    @GetMapping("/dept/groupfunc")
    public ResponseEntity<Object> selectByDnameAndLoc() {
        try {
            List<DeptGroupDto> list
                    = deptService.selectByGroupFunc();

            if (list.isEmpty() == false) {
//                성공
                return new ResponseEntity<>(list, HttpStatus.OK);
            } else {
//                데이터 없음
                return new ResponseEntity<>(HttpStatus.NO_CONTENT);
            }

        } catch (Exception e){
            log.debug(e.getMessage());
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }


    /** 5) 전체조회 + 일반함수(dto) : @Query */
    @GetMapping("/dept/basicfunc")
    public ResponseEntity<Object> selectByBasicFunc() {
        try {
            List<DeptGroupDto> list
                    = deptService.selectByBasicFunc();

            if (list.isEmpty() == false) {
//                성공
                return new ResponseEntity<>(list, HttpStatus.OK);
            } else {
//                데이터 없음
                return new ResponseEntity<>(HttpStatus.NO_CONTENT);
            }

        } catch (Exception e){
            log.debug(e.getMessage());
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }


    /** 6) 전체조회 + case when(dto) : @Query */
    @GetMapping("/dept/case")
    public ResponseEntity<Object> selectByCase() {
        try {
            List<DeptGroupDto> list
                    = deptService.selectByCase();

            if (list.isEmpty() == false) {
//                성공
                return new ResponseEntity<>(list, HttpStatus.OK);
            } else {
//                데이터 없음
                return new ResponseEntity<>(HttpStatus.NO_CONTENT);
            }

        } catch (Exception e){
            log.debug(e.getMessage());
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }


//  ----------------------------------------
//    페이징 예제
//  ------------------------------------------
    /** 1)  : @Query */
    @GetMapping("/dept/dname/{dname}/paging")
    public ResponseEntity<Object> getDeptDnamePage(

            @PathVariable String dname,
            Pageable pageable
    ) {
        try {
            Page<Dept> page
                    = deptService.findAllByDnameContaining(dname, pageable);

//          todo: Map 자료구조 정보 저장 : 1) 부서객체, 2) 페이징 정보 (3개)
            Map<String, Object> response = new HashMap<>();
            response.put("dept", page.getContent()); // 부서 객체
            response.put("currentPage", page.getNumber()); // 현재페이지번호
            response.put("totalItems", page.getTotalElements()); // 전체테이블건수
            response.put("totalPages", page.getTotalPages()); // 전체 페이지 수



            if (page.isEmpty() == false) {
//                성공
                return new ResponseEntity<>(page, HttpStatus.OK);
            } else {
//                데이터 없음
                return new ResponseEntity<>(HttpStatus.NO_CONTENT);
            }

        } catch (Exception e){
            log.debug(e.getMessage());
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    /** 2) findAll() + 페이징  : @Query */
//    page=현재페이지번호(0~n), size=전체페이지수
    @GetMapping("/dept/all/paging")
    public ResponseEntity<Object> getDeptAllPage(
            Pageable pageable
    ) {
        try {
            Page<Dept> page
                    = deptService.findAllPage(pageable);

//          todo: Map 자료구조 정보 저장 : 1) 부서객체, 2) 페이징 정보 (3개)
            Map<String, Object> response = new HashMap<>();
            response.put("dept", page.getContent()); // 부서 객체
            response.put("currentPage", page.getNumber()); // 현재페이지번호
            response.put("totalItems", page.getTotalElements()); // 전체테이블건수
            response.put("totalPages", page.getTotalPages()); // 전체 페이지 수



            if (page.isEmpty() == false) {
//                성공
                return new ResponseEntity<>(page, HttpStatus.OK);
            } else {
//                데이터 없음
                return new ResponseEntity<>(HttpStatus.NO_CONTENT);
            }

        } catch (Exception e){
            log.debug(e.getMessage());
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    //    ---------------------
//    @Query 2) 예제
//    ----------------------
    /** 2)  페이징 : @Query */
//    page=현재페이지번호(0 ~ n), size=전체페이지수
    @GetMapping("/dept/all/paging/query/{dname}")
    public ResponseEntity<Object> getDeptAllPage(
            @PathVariable String dname,
            Pageable pageable
    ) {
        try {
            Page<Dept> page
                    = deptService.selectByDnamePage(dname, pageable);

//          todo: Map 자료구조 정보 저장 : 1) 부서객체, 2) 페이징 정보 (3개)
            Map<String, Object> response = new HashMap<>();
            response.put("dept", page.getContent()); // 부서 객체
            response.put("currentPage", page.getNumber()); // 현재페이지번호
            response.put("totalItems", page.getTotalElements()); // 전체테이블건수
            response.put("totalPages", page.getTotalPages()); // 전체 페이지 수

            if (page.isEmpty() == false) {
//                성공
                return new ResponseEntity<>(response, HttpStatus.OK);
            } else {
//                데이터 없음
                return new ResponseEntity<>(HttpStatus.NO_CONTENT);
            }

        } catch (Exception e){
            log.debug(e.getMessage());
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    /** 3)  조인 페이징 : @Query */
//    page=현재페이지번호(0 ~ n), size=전체페이지수
    @GetMapping("/dept/native/join/paging")
    public ResponseEntity<Object> selectNativeJoinPage(Pageable pageable) {
        try {
            Page<DeptEmpDto> page
                    = deptService.selectNativeJoinPage(pageable);

//          todo: Map 자료구조 정보 저장 : 1) 부서객체, 2) 페이징 정보 (3개)
            Map<String, Object> response = new HashMap<>();
            response.put("dept", page.getContent()); // 부서 객체
            response.put("currentPage", page.getNumber()); // 현재페이지번호
            response.put("totalItems", page.getTotalElements()); // 전체테이블건수
            response.put("totalPages", page.getTotalPages()); // 전체 페이지 수

            if (page.isEmpty() == false) {
//                성공
                return new ResponseEntity<>(response, HttpStatus.OK);
            } else {
//                데이터 없음
                return new ResponseEntity<>(HttpStatus.NO_CONTENT);
            }

        } catch (Exception e){
            log.debug(e.getMessage());
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

}

Emp

EmpGroupDto

package com.example.jpacustomexam.dto;

/**
 * packageName : com.example.jpacustomexam.dto
 * fileName : EmpGroupDto
 * author : GGG
 * date : 2023-10-18
 * description : DTO 인터페이스(Emp Group 용)
 * 요약 :
 * <p>
 * ===========================================================
 * DATE            AUTHOR             NOTE
 * —————————————————————————————
 * 2023-10-18         GGG          최초 생성
 */
public interface EmpGroupDto {
    //    속성 (상수) x
//    연습 5) getter 함수 : dno(Integer), job(String), salary(Integer)
    Integer getDno();
    String getJob();
    Integer getSalary();

    //    연습 6) DNO, avgSalary(Integer)
    Integer getAvgSalary();

    //  연습 7) countEno, maxSalary
    Integer getCountEno();
    Integer getSumSalary();

    //    연습 8) maxHiredate(Integer), minHiredate(Integer)
    String getMaxHiredate();
    String getMinHiredate();



}

EmpRespository

package com.example.jpacustomexam.repository;

import com.example.jpacustomexam.dto.EmpGroupDto;
import com.example.jpacustomexam.model.Dept;
import com.example.jpacustomexam.model.Emp;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import java.util.List;

/**
 * packageName : com.example.jpacustomexam.repository
 * fileName : EmpRepository
 * author : GGG
 * date : 2023-10-17
 * description : 사원 레포지토리( 기본 CRUD 함수 )
 * 요약 :
 * <p>
 * ===========================================================
 * DATE            AUTHOR             NOTE
 * —————————————————————————————
 * 2023-10-17         GGG          최초 생성
 */
@Repository
public interface EmpRepository extends JpaRepository<Emp, Integer> {
    //    JPA : ORM(Object-Relational Mapping) 프레임워크
//    개발자 직접 sql 작성 하는 기능(JPQL) : 1) 쿼리메소드
//                                       2) @Query 쓰는 방법
//    todo:  연습 1) 전체 조회 + 정렬(eno 내림차순)
    List<Emp> findAllByOrderByEnoDesc();

    //    todo: 연습 2) 전체 조회 + (ename 오름차순)
    List<Emp> findAllByOrderByEname();

    //    todo: 연습 3) ename like 검색
    List<Emp> findAllByEnameContaining(String ename);

    //    todo: 응용 연습문제 : 구글링 (JPA 쿼리메소드)
//    todo: 연습 4) EMP 테이블에서 Job 이 manager 이고
//              매개변수로 부서번호(dno)를 받는 함수를 작성하세요.
//       where job = 'manager' and dno = 10
//     힌트 : JobAndDno(매개변수1, 매개변수2)
    List<Emp> findAllByJobAndDno(String job, int dno);

    //    todo: 연습 5) Emp 테이블에서 salary 가 1000 ~ 1500 사이의 값을 같는
//     사원을 조회하려고 합니다.  함수를 작성해 주세요
//      where salary between 1000 and 1500
//     힌트 : SalaryBetween(매개변수1, 매개변수2)
    List<Emp> findAllBySalaryBetween(int first, int last);

    //    todo: 6) Emp 테이블에서 Job 이 manager 인 사원의 정보를
//         출력하는 함수를 작성하세요.
//       단, Job 의 매개변수는 소문자 또는 대문자가 들어올 수 있음
//         where job = UPPER('manager')
//     힌트 : 컬럼명IgnoreCase
    List<Emp> findAllByJobIgnoreCase(String job);

    //    todo: 7) commission 을 받는 사원을 모두 출력하는 함수를 작성하세요.
//     힌트 : where commission is not null
    List<Emp> findAllByCommissionNotNull();

    //    todo: 8) salary desc, ename asc 로 정렬하는 함수를 작성하세요.
//    힌트 : 컬럼1Desc컬럼2Asc
    List<Emp> findAllByOrderBySalaryDescEnameAsc();

    //    todo: 9) salary < 1000 또는 salary > 1500 사이에
//         해당하는 사원을 출력하는 함수를 작성하세요.
//    where salary < 1000 or salary > 1500
//    힌트 : < - LessThan , > - GreaterThan
    List<Emp> findAllBySalaryLessThanOrSalaryGreaterThan(int first, int last);

    //
//    todo: 10) commission 이 300 이거나 500
//         또는 1500 인 사원을 출력하는 함수를 작성하세요.
//    where commission = 300 or commission = 500 or commission = 1500
//    힌트: Or 조건 사용
    List<Emp> findAllByCommissionOrCommissionOrCommission(int x, int y, int z);


//    ---------------------------------------
//    @Query 예제 : 1) 오라클 쿼리 2) 객체 쿼리
//    ---------------------------------------
//  todo: 1) dname like 검색(단, % 1개만 사용)

    @Query(value = "SELECT TD.* FROM TB_EMP TD WHERE TD.ENAME LIKE '%' || :ename || '%'",
            nativeQuery = true)
    List<Emp> selectByEname(@Param("ename") String ename);

    //  todo: 2) salary 내림차순, ename 오름차순으로 정렬
    //    단, nativeQuery = true 사용하세요

    @Query(value = "SELECT D.* FROM TB_EMP D " +
            "ORDER BY D.SALARY desc, D.ENAME"
            , nativeQuery = true)
    List<Emp> selectDesc();

//  todo: 3) commission 이 null 이고
//         salary 매개변수값보다 같거나 큰 사원 정보를 모두 출력하세요.
//    단, nativeQuery = true 사용하세요

    @Query(value = "SELECT * FROM TB_EMP " +
            "WHERE COMMISSION is null " +
            "AND SALARY >=:salary"
            , nativeQuery = true)
    List<Emp> selectSalary(@Param("salary") Integer salary);

//      todo: 4) 1982년도에 입사한 사원 출력하기, 입사일 내림차순하세요
//    nativeQuery = true 사용

    @Query(value = "SELECT * FROM TB_EMP " +
            "WHERE HIREDATE BETWEEN :first AND :last "
            , nativeQuery = true)
    List<Emp> selectHiredate(@Param("first") String first,
                             @Param("last") String last);

//    todo: 5) dno, job 별 월급여의 합을 출력하는 함수를 작성하세요.(tb_emp)
//      nativeQuery = true 사용,
//      dto : EmpGroupDto
@Query(value = "SELECT dno, job, SUM(SALARY) AS salary " +
        "FROM TB_EMP " +
        "GROUP BY DNO, JOB",
        nativeQuery = true)
    List<EmpGroupDto> selectGroupDnoJob();

    //    todo: 6) dno 별 월급여의 평균을 출력하는 함수를 작성하세요.
//       단, 소수점 절삭(버림, trunc) 하세요
//       nativeQuery = true 사용,
//       dto : EmpGroupDto
    @Query(value = "SELECT dno, TRUNC(AVG(SALARY)) AS avgSalary " +
            "FROM TB_EMP " +
            "GROUP BY DNO "
            , nativeQuery = true)
    List<EmpGroupDto> selectGroupDnoTrunc();
//}

    //    todo: 7) 사원의 수와 최고월급을 출력하세요.
//       nativeQuery = true 사용,
//       dto : EmpGroupDto
    @Query(value = "SELECT COUNT(ENO) AS countEno, " +
            "MAX(SALARY) AS sumSalary " +
            "FROM TB_EMP "
            , nativeQuery = true)
    List<EmpGroupDto> selectGroupSumMax();


    //    todo: 8) 사원 테이블에서 가장 오래된 입사일(HIREDATE)과(MAX)
//            가장 빠른 입사일을(MIN) 출력하세요.
//       nativeQuery = true 사용,
//       dto : EmpGroupDto
    @Query(value = "SELECT MAX(HIREDATE) AS maxHiredate, " +
            "       MIN(HIREDATE) AS minHiredate " +
            "FROM TB_EMP "
            , nativeQuery = true)
    List<EmpGroupDto> selectGroupHiredate();

//    ---------------------------------------
//  연습1) 페이징 연습 :
//    -------------------------------------
//    1) ename like 검색 함수를 만드세요 : 쿼리메소드
//     단, 페이징처리를 하세요

    Page<Emp> findAllByEnameContaining(String ename, Pageable pageable);

    //    2) findAll() : 페이징 기능을 추가하세요 : 기본함수

//   ----------------------
//    @Query 페이징
//   연습2) ename like 검색 함수를 만드세요 : @Query

    @Query(value = "SELECT D.* FROM TB_EMP D " +
            "WHERE D.ENAME LIKE '%' || :ename || '%'",
            countQuery = "SELECT COUNT(*) FROM TB_EMP D " +
                    "WHERE D.ENAME LIKE '%' || :ename || '%'",
            nativeQuery = true)
    Page<Emp> selectByEnamePage(@Param("ename") String ename,
                                 Pageable pageable);
}

EmpService

package com.example.jpacustomexam.service;


import com.example.jpacustomexam.dto.EmpGroupDto;
import com.example.jpacustomexam.model.Dept;
import com.example.jpacustomexam.model.Emp;
import com.example.jpacustomexam.repository.EmpRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * packageName : com.example.jpacustomexam.service
 * fileName : EmpService
 * author : GGG
 * date : 2023-10-17
 * description : 사원 서비스
 * 요약 :
 * <p>
 * ===========================================================
 * DATE            AUTHOR             NOTE
 * —————————————————————————————
 * 2023-10-17         GGG          최초 생성
 */
@Service
public class EmpService {

    @Autowired
    EmpRepository empRepository; // DI

    /**
     * 전체조회 + 정렬(eno 내림차순) : 쿼리메소드
     */
    public List<Emp> findAllByOrderByEnoDesc() {
        List<Emp> list = empRepository.findAllByOrderByEnoDesc();

        return list;
    }

    /**
     * 전체조회 + 정렬(ename 오름차순) : 쿼리메소드
     */
    public List<Emp> findAllByOrderByEname() {
        List<Emp> list = empRepository.findAllByOrderByEname();

        return list;
    }

    /**
     * 전체조회 + like(Containing) 검색( ename ) : 쿼리메소드
     */
    public List<Emp> findAllByEnameContaining(String ename) {
        List<Emp> list = empRepository.findAllByEnameContaining(ename);

        return list;
    }

    //    todo: 연습 4) EMP 테이블에서 Job 이 manager 이고
//              매개변수로 부서번호(dno)를 받는 함수를 작성하세요.
    public List<Emp> findAllByJobAndDno(String job, int dno) {
        List<Emp> list = empRepository.findAllByJobAndDno(job, dno);

        return list;
    }

    //    todo: 연습 5) Emp 테이블에서 salary 가 1000 ~ 1500 사이의 값을 같는
//     사원을 조회하려고 합니다.  함수를 작성해 주세요
    public List<Emp> findAllBySalaryBetween(int first, int last) {
        List<Emp> list = empRepository.findAllBySalaryBetween(first, last);

        return list;
    }

    //    todo: 연습 6)
    public List<Emp> findAllByJobIgnoreCase(String job) {
        List<Emp> list = empRepository.findAllByJobIgnoreCase(job);

        return list;
    }

    //    todo: 연습 7)
    public List<Emp> findAllByCommissionNotNull() {
        List<Emp> list = empRepository.findAllByCommissionNotNull();

        return list;
    }

    //    todo: 연습 8)
    public List<Emp> findAllByOrderBySalaryDescEnameAsc() {
        List<Emp> list = empRepository.findAllByOrderBySalaryDescEnameAsc();

        return list;
    }

    //    todo: 연습 9)
    public List<Emp> findAllBySalaryLessThanOrSalaryGreaterThan(int first,
                                                                int last) {
        List<Emp> list
                = empRepository
                .findAllBySalaryLessThanOrSalaryGreaterThan(first,last);

        return list;
    }


    //    todo: 연습 10)
    public List<Emp> findAllByCommissionOrCommissionOrCommission(int x, int y, int z) {
        List<Emp> list = empRepository.findAllByCommissionOrCommissionOrCommission(x, y, z);

        return list;
    }

//    -------------------------------------------------
//    @Query 예제
//    -------------------------------------------------
    /** 전체조회 + ename like 검색 : @Query */
    public List<Emp> selectByEname(String ename) {
        List<Emp> list
                = empRepository.selectByEname(ename);

        return list;
    }

    /** 전체조회 + ename like 검색 : @Query */
    public List<Emp> selectDesc() {
        List<Emp> list
                = empRepository.selectDesc();

        return list;
    }

    /** 전체조회 + ename like 검색 : @Query */
    public List<Emp> selectSalary(int salary) {
        List<Emp> list
                = empRepository.selectSalary(salary);

        return list;
    }

    /** 전체조회 + ename like 검색 : @Query */
    public List<Emp> selectHiredate(String first, String last) {
        List<Emp> list
                = empRepository.selectHiredate(first, last);

        return list;
    }

    /** 전체조회 그룹 함수 검색(dto) : @Query */
    public List<EmpGroupDto> selectGroupDnoJob() {
        List<EmpGroupDto> list
                = empRepository.selectGroupDnoJob();

        return list;
    }

    /** 전체조회 그룹 함수 검색(dto) : @Query */
    public List<EmpGroupDto> selectGroupDnoTrunc() {
        List<EmpGroupDto> list
                = empRepository.selectGroupDnoTrunc();

        return list;
    }

    /** 연습 7) : @Query(dto)*/
    public List<EmpGroupDto> selectGroupSumMax() {
        List<EmpGroupDto> list
                = empRepository.selectGroupSumMax();

        return list;
    }

    /** 연습 8) : @Query(dto) */
    public List<EmpGroupDto> selectGroupHiredate() {
        List<EmpGroupDto> list
                = empRepository.selectGroupHiredate();

        return list;
    }

//    --------------------------------------------------
//    페이지 예제
//    --------------------------------------------------
    public Page<Emp> findAllByEnameContaining(String ename, Pageable pageable) {
        Page<Emp> page
                = empRepository.findAllByEnameContaining(ename, pageable);

        return page;
    }

    //    2) 기본 제공되는 전체 조회 함수 : 페이징처리 기능 추가
    public Page<Emp> findAllPage(Pageable pageable) {
        Page<Emp> page
                = empRepository.findAll(pageable);

        return page;
    }
//    --------------------------
//    @Query : 페이징 처리
//    --------------------------
    //    2)  : 페이징처리 기능 추가
    public Page<Emp> selectByEnamePage(String ename, Pageable pageable) {
        Page<Emp> page
                = empRepository.selectByEnamePage(ename, pageable);

        return page;
    }

}

EmpController

package com.example.jpacustomexam.controller;

import com.example.jpacustomexam.dto.EmpGroupDto;
import com.example.jpacustomexam.model.Dept;
import com.example.jpacustomexam.model.Emp;
import com.example.jpacustomexam.service.EmpService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * packageName : com.example.jpacustomexam.controller
 * fileName : EmpController
 * author : GGG
 * date : 2023-10-17
 * description : 사원 컨트롤러
 * 요약 :
 * <p>
 * ===========================================================
 * DATE            AUTHOR             NOTE
 * —————————————————————————————
 * 2023-10-17         GGG          최초 생성
 */
@Slf4j
@RestController
public class EmpController {

    @Autowired
    EmpService empService; // DI

    /**
     * 전체조회 + 정렬(eno 내림차순)
     */
    @GetMapping("/emp/desc")
    public ResponseEntity<Object> getEmpAllDesc() {
        try {
//         전체 조회 + 정렬(dno 내림차순) 호출
            List<Emp> list = empService.findAllByOrderByEnoDesc();

            if (list.isEmpty() == false) {
//                성공
                return new ResponseEntity<>(list, HttpStatus.OK);
            } else {
//                데이터 없음
                return new ResponseEntity<>(HttpStatus.NO_CONTENT);
            }

        } catch (Exception e) {
            log.debug(e.getMessage());
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }


    /**
     * 전체조회 + 정렬(ename 오름차순)
     */
    @GetMapping("/emp/ename/asc")
    public ResponseEntity<Object> findAllByOrderByEname() {
        try {
//         전체 조회 + 정렬(dno 내림차순) 호출
            List<Emp> list = empService.findAllByOrderByEname();

            if (list.isEmpty() == false) {
//                성공
                return new ResponseEntity<>(list, HttpStatus.OK);
            } else {
//                데이터 없음
                return new ResponseEntity<>(HttpStatus.NO_CONTENT);
            }

        } catch (Exception e) {
            log.debug(e.getMessage());
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    /**
     * 전체조회 + like(Containing) 검색( ename ) : 쿼리메소드
     */
    @GetMapping("/emp/ename/containing/{ename}")
    public ResponseEntity<Object> findAllByEnameContaining(
            @PathVariable String ename
    ) {
        try {
//         전체 조회 + 정렬(dno 내림차순) 호출
            List<Emp> list
                    = empService.findAllByEnameContaining(ename);

            if (list.isEmpty() == false) {
//                성공
                return new ResponseEntity<>(list, HttpStatus.OK);
            } else {
//                데이터 없음
                return new ResponseEntity<>(HttpStatus.NO_CONTENT);
            }

        } catch (Exception e) {
            log.debug(e.getMessage());
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    /**
     * 연습 4) : 쿼리메소드
     */
    @GetMapping("/emp/dno/{dno}")
    public ResponseEntity<Object> findAllByJobAndDno(
            @PathVariable int dno
    ) {
        try {
//         전체 조회 + 정렬(dno 내림차순) 호출
            List<Emp> list
                    = empService.findAllByJobAndDno("MANAGER", dno);

            if (list.isEmpty() == false) {
//                성공
                return new ResponseEntity<>(list, HttpStatus.OK);
            } else {
//                데이터 없음
                return new ResponseEntity<>(HttpStatus.NO_CONTENT);
            }

        } catch (Exception e) {
            log.debug(e.getMessage());
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }


    /**
     * 연습 5) : 쿼리메소드
     */
    @GetMapping("/emp/salary/{first}/{last}")
    public ResponseEntity<Object> findAllBySalaryBetween(
            @PathVariable int first,
            @PathVariable int last
    ) {
        try {
//         전체 조회 + 정렬(dno 내림차순) 호출
            List<Emp> list
                    = empService.findAllBySalaryBetween(first, last);

            if (list.isEmpty() == false) {
//                성공
                return new ResponseEntity<>(list, HttpStatus.OK);
            } else {
//                데이터 없음
                return new ResponseEntity<>(HttpStatus.NO_CONTENT);
            }

        } catch (Exception e) {
            log.debug(e.getMessage());
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    /**
     * 연습 6) : 쿼리메소드
     */
    @GetMapping("/emp/job/{job}")
    public ResponseEntity<Object> findAllByJobIgnoreCase(
            @PathVariable String job
    ) {
        try {
//         전체 조회 + 정렬(dno 내림차순) 호출
            List<Emp> list
                    = empService.findAllByJobIgnoreCase(job);

            if (list.isEmpty() == false) {
//                성공
                return new ResponseEntity<>(list, HttpStatus.OK);
            } else {
//                데이터 없음
                return new ResponseEntity<>(HttpStatus.NO_CONTENT);
            }

        } catch (Exception e) {
            log.debug(e.getMessage());
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    /**
     * 연습 7) : 쿼리메소드
     */
    @GetMapping("/emp/commission")
    public ResponseEntity<Object> findAllByCommissionNotNull() {
        try {
//         전체 조회 + 정렬(dno 내림차순) 호출
            List<Emp> list
                    = empService.findAllByCommissionNotNull();

            if (list.isEmpty() == false) {
//                성공
                return new ResponseEntity<>(list, HttpStatus.OK);
            } else {
//                데이터 없음
                return new ResponseEntity<>(HttpStatus.NO_CONTENT);
            }

        } catch (Exception e) {
            log.debug(e.getMessage());
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    /**
     * 연습 8) : 쿼리메소드
     */
    @GetMapping("/emp/salary/desc/ename/asc")
    public ResponseEntity<Object> findAllByOrderBySalaryDescEnameAsc() {
        try {
//         전체 조회 + 정렬(dno 내림차순) 호출
            List<Emp> list
                    = empService.findAllByOrderBySalaryDescEnameAsc();

            if (list.isEmpty() == false) {
//                성공
                return new ResponseEntity<>(list, HttpStatus.OK);
            } else {
//                데이터 없음
                return new ResponseEntity<>(HttpStatus.NO_CONTENT);
            }

        } catch (Exception e) {
            log.debug(e.getMessage());
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }


    /**
     * 연습 9) : 쿼리메소드
     */
    @GetMapping("/emp/or/salary/{first}/{last}")
    public ResponseEntity<Object> findAllBySalaryLessThanOrSalaryGreaterThan(
            @PathVariable int first,
            @PathVariable int last
    ) {
        try {
//         전체 조회 + 정렬(dno 내림차순) 호출
            List<Emp> list
                    = empService
                    .findAllBySalaryLessThanOrSalaryGreaterThan(first, last);

            if (list.isEmpty() == false) {
//                성공
                return new ResponseEntity<>(list, HttpStatus.OK);
            } else {
//                데이터 없음
                return new ResponseEntity<>(HttpStatus.NO_CONTENT);
            }

        } catch (Exception e) {
            log.debug(e.getMessage());
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }


    /** 연습 10) : 쿼리메소드 */
    @GetMapping("/emp/commission/{first}/{second}/{third}")
    public ResponseEntity<Object> findAllBySalaryLessThanOrSalaryGreaterThan(
            @PathVariable int first,
            @PathVariable int second,
            @PathVariable int third
    ) {
        try {
//         전체 조회 + 정렬(dno 내림차순) 호출
            List<Emp> list
                    = empService
                    .findAllByCommissionOrCommissionOrCommission(first,
                            second,
                            third);

            if (list.isEmpty() == false) {
//                성공
                return new ResponseEntity<>(list, HttpStatus.OK);
            } else {
//                데이터 없음
                return new ResponseEntity<>(HttpStatus.NO_CONTENT);
            }

        } catch (Exception e){
            log.debug(e.getMessage());
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    /** 전체조회 + ename like 검색 : @Query */
    @GetMapping("/emp/desc/asc")
    public ResponseEntity<Object>selectDesc() {
        try {
//         전체 조회 + 정렬(dno 오름차순) 호출
            List<Emp> list
                    = empService
                    .selectDesc();

            if (list.isEmpty() == false) {
//                성공
                return new ResponseEntity<>(list, HttpStatus.OK);
            } else {
//                데이터 없음
                return new ResponseEntity<>(HttpStatus.NO_CONTENT);
            }

        } catch (Exception e){
            log.debug(e.getMessage());
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    /** 전체조회 + ename like 검색 : @Query */
    @GetMapping("/emp/salary/{salary}")
    public ResponseEntity<Object>selectSalary(
            @PathVariable int salary
    ) {
        try {
//         전체 조회 + 정렬(dno 오름차순) 호출
            List<Emp> list
                    = empService
                    .selectSalary(salary);

            if (list.isEmpty() == false) {
//                성공
                return new ResponseEntity<>(list, HttpStatus.OK);
            } else {
//                데이터 없음
                return new ResponseEntity<>(HttpStatus.NO_CONTENT);
            }

        } catch (Exception e){
            log.debug(e.getMessage());
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    /** 전체조회 + ename like 검색 : @Query */
    @GetMapping("/emp/hiredate/{first}/{last}")
    public ResponseEntity<Object>selectHiredate(
            @PathVariable String first,
            @PathVariable String last
    ) {
        try {
//         전체 조회 + 정렬(dno 오름차순) 호출
            List<Emp> list
                    = empService
                    .selectHiredate(first, last);

            if (list.isEmpty() == false) {
//                성공
                return new ResponseEntity<>(list, HttpStatus.OK);
            } else {
//                데이터 없음
                return new ResponseEntity<>(HttpStatus.NO_CONTENT);
            }

        } catch (Exception e){
            log.debug(e.getMessage());
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    /** 전체조회 + ename like 검색 : @Query */
    @GetMapping("/emp/group")
    public ResponseEntity<Object>selectGroupDnoJob() {
        try {
//         전체 조회 + 정렬(dno 오름차순) 호출
            List<EmpGroupDto> list
                    = empService
                    .selectGroupDnoJob();

            if (list.isEmpty() == false) {
//                성공
                return new ResponseEntity<>(list, HttpStatus.OK);
            } else {
//                데이터 없음
                return new ResponseEntity<>(HttpStatus.NO_CONTENT);
            }

        } catch (Exception e){
            log.debug(e.getMessage());
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    /** 전체조회 + ename like 검색 : @Query */
    @GetMapping("/emp/dno/group")
    public ResponseEntity<Object> selectGroupDnoTrunc() {
        try {
            List<EmpGroupDto> list
                    = empService.selectGroupDnoTrunc();



            if (list.isEmpty() == false) {
//                성공
                return new ResponseEntity<>(list, HttpStatus.OK);
            } else {
//                데이터 없음
                return new ResponseEntity<>(HttpStatus.NO_CONTENT);
            }

        } catch (Exception e){
            log.debug(e.getMessage());
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    /** 연습 7) : @Query(dto) */
    @GetMapping("/emp/sum/max")
    public ResponseEntity<Object> selectGroupSumMax() {
        try {
            List<EmpGroupDto> list
                    = empService.selectGroupSumMax();

            if (list.isEmpty() == false) {
//                성공
                return new ResponseEntity<>(list, HttpStatus.OK);
            } else {
//                데이터 없음
                return new ResponseEntity<>(HttpStatus.NO_CONTENT);
            }

        } catch (Exception e){
            log.debug(e.getMessage());
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    /** 연습 8) : @Query(dto) */
    @GetMapping("/emp/hiredate/min/max")
    public ResponseEntity<Object> selectGroupHiredate() {
        try {
            List<EmpGroupDto> list
                    = empService.selectGroupHiredate();

            if (list.isEmpty() == false) {
//                성공
                return new ResponseEntity<>(list, HttpStatus.OK);
            } else {
//                데이터 없음
                return new ResponseEntity<>(HttpStatus.NO_CONTENT);
            }

        } catch (Exception e){
            log.debug(e.getMessage());
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }
//  ----------------------------------------
//    페이징 예제
//  ------------------------------------------
    /** 1)  : @Query */
    @GetMapping("/emp/ename/{ename}/paging")
    public ResponseEntity<Object> getDeptEnamePage(

            @PathVariable String ename,
            Pageable pageable
    ) {
        try {
            Page<Emp> page
                    = empService.findAllByEnameContaining(ename, pageable);

//          todo: Map 자료구조 정보 저장 : 1) 부서객체, 2) 페이징 정보 (3개)
            Map<String, Object> response = new HashMap<>();
            response.put("emp", page.getContent()); // 부서 객체
            response.put("currentPage", page.getNumber()); // 현재페이지번호
            response.put("totalItems", page.getTotalElements()); // 전체테이블건수
            response.put("totalPages", page.getTotalPages()); // 전체 페이지 수



            if (page.isEmpty() == false) {
//                성공
                return new ResponseEntity<>(page, HttpStatus.OK);
            } else {
//                데이터 없음
                return new ResponseEntity<>(HttpStatus.NO_CONTENT);
            }

        } catch (Exception e){
            log.debug(e.getMessage());
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    /** 2) findAll() + 페이징  : @Query */
//    page=현재페이지번호(0~n), size=전체페이지수
    @GetMapping("/emp/all/paging")
    public ResponseEntity<Object> getEmpAllPage(
            Pageable pageable
    ) {
        try {
            Page<Emp> page
                    = empService.findAllPage(pageable);

//          todo: Map 자료구조 정보 저장 : 1) 부서객체, 2) 페이징 정보 (3개)
            Map<String, Object> response = new HashMap<>();
            response.put("emp", page.getContent()); // 부서 객체
            response.put("currentPage", page.getNumber()); // 현재페이지번호
            response.put("totalItems", page.getTotalElements()); // 전체테이블건수
            response.put("totalPages", page.getTotalPages()); // 전체 페이지 수



            if (page.isEmpty() == false) {
//                성공
                return new ResponseEntity<>(page, HttpStatus.OK);
            } else {
//                데이터 없음
                return new ResponseEntity<>(HttpStatus.NO_CONTENT);
            }

        } catch (Exception e){
            log.debug(e.getMessage());
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    //    ---------------------
//    @Query 2) 예제
//    ----------------------
    /** 2)  페이징 : @Query */
//    page=현재페이지번호(0 ~ n), size=전체페이지수
    @GetMapping("/emp/all/paging/query/{ename}")
    public ResponseEntity<Object> getEmpAllPage(
            @PathVariable String ename,
            Pageable pageable
    ) {
        try {
            Page<Emp> page
                    = empService.selectByEnamePage(ename, pageable);

//          todo: Map 자료구조 정보 저장 : 1) 부서객체, 2) 페이징 정보 (3개)
            Map<String, Object> response = new HashMap<>();
            response.put("emp", page.getContent()); // 부서 객체
            response.put("currentPage", page.getNumber()); // 현재페이지번호
            response.put("totalItems", page.getTotalElements()); // 전체테이블건수
            response.put("totalPages", page.getTotalPages()); // 전체 페이지 수

            if (page.isEmpty() == false) {
//                성공
                return new ResponseEntity<>(response, HttpStatus.OK);
            } else {
//                데이터 없음
                return new ResponseEntity<>(HttpStatus.NO_CONTENT);
            }

        } catch (Exception e){
            log.debug(e.getMessage());
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }
}