Oracle Database 강좌

오라클 페이징 구현 및 스토어드 프로시저 활용: 심층 분석 및 실제 예제

_Blue_Sky_ 2024. 12. 14. 09:31
728x90

오라클(Oracle) 데이터베이스에서 페이징(Paging)을 구현하려면 ROWNUM 또는 ROW_NUMBER()를 사용하는 방식이 일반적입니다. 최신 오라클 버전에서는 FETCH FIRST를 활용하는 방식도 지원됩니다. 아래에 세 가지 방식을 각각 예제를 들어 설명드리겠습니다.


1. ROWNUM을 사용한 페이징

SELECT *
FROM (
    SELECT ROWNUM AS RNUM, A.*
    FROM ( 
        SELECT * 
        FROM 테이블명 
        ORDER BY 컬럼명 ASC
    ) A
    WHERE ROWNUM <= :최대_행_번호 -- 끝 번호
) 
WHERE RNUM >= :최소_행_번호; -- 시작 번호

설명:

  • 내부 쿼리에서 데이터를 정렬 후 ROWNUM으로 행 번호를 부여합니다.
  • 원하는 시작 번호와 끝 번호 범위에 맞게 필터링합니다.

2. ROW_NUMBER()를 사용한 페이징

SELECT *
FROM (
    SELECT 
        ROW_NUMBER() OVER (ORDER BY 컬럼명 ASC) AS RNUM, 
        A.*
    FROM 테이블명 A
) 
WHERE RNUM BETWEEN :시작_번호 AND :끝_번호;

설명:

  • ROW_NUMBER() 함수는 정렬 기준에 따라 고유한 행 번호를 생성합니다.
  • 외부 쿼리에서 BETWEEN 조건으로 범위를 지정하여 페이징 처리합니다.

3. FETCH FIRST를 사용한 페이징 (Oracle 12c 이상)

SELECT *
FROM 테이블명
ORDER BY 컬럼명 ASC
OFFSET :건너뛸_행_수 ROWS FETCH NEXT :가져올_행_수 ROWS ONLY;

설명:

  • OFFSET은 건너뛸 행의 수를 지정합니다.
  • FETCH NEXT는 가져올 행의 수를 지정합니다.
  • 더 간단하고 가독성이 좋지만, 오라클 12c 이상에서만 사용할 수 있습니다.

예제 데이터 및 실행

예를 들어, 직원 테이블에서 10번째부터 19번째 데이터를 가져오려면:

ROWNUM 방식

SELECT *
FROM (
    SELECT ROWNUM AS RNUM, A.*
    FROM ( 
        SELECT * 
        FROM EMPLOYEES 
        ORDER BY EMPLOYEE_ID ASC
    ) A
    WHERE ROWNUM <= 20
) 
WHERE RNUM >= 10;

ROW_NUMBER() 방식

SELECT *
FROM (
    SELECT 
        ROW_NUMBER() OVER (ORDER BY EMPLOYEE_ID ASC) AS RNUM, 
        A.*
    FROM EMPLOYEES A
) 
WHERE RNUM BETWEEN 10 AND 19;

FETCH FIRST 방식

SELECT *
FROM EMPLOYEES
ORDER BY EMPLOYEE_ID ASC
OFFSET 9 ROWS FETCH NEXT 10 ROWS ONLY;

 

728x90

페이징을 스토어프로시져로 한다면 ?

오라클에서 페이징 처리를 스토어드 프로시저(Stored Procedure)로 구현하는 방법을 예제로 보여드리겠습니다. 아래는 ROW_NUMBER()를 활용한 방식으로 구현한 스토어드 프로시저입니다.


스토어드 프로시저 구현

1. 기본 구조

CREATE OR REPLACE PROCEDURE PAGING_PROC (
    P_PAGE_NUMBER IN NUMBER,         -- 요청 페이지 번호
    P_PAGE_SIZE IN NUMBER,           -- 페이지 크기 (한 페이지당 행 수)
    P_RESULT OUT SYS_REFCURSOR       -- 결과를 반환할 커서
)
AS
    V_OFFSET NUMBER;                 -- 건너뛸 행의 수
    V_FETCH_SIZE NUMBER;             -- 가져올 행의 수
BEGIN
    -- OFFSET 계산
    V_OFFSET := (P_PAGE_NUMBER - 1) * P_PAGE_SIZE;
    V_FETCH_SIZE := P_PAGE_SIZE;

    -- REF CURSOR에 결과 할당
    OPEN P_RESULT FOR
    SELECT *
    FROM (
        SELECT 
            ROW_NUMBER() OVER (ORDER BY EMPLOYEE_ID ASC) AS RNUM, -- 정렬 기준 필요
            E.* 
        FROM EMPLOYEES E
    ) 
    WHERE RNUM BETWEEN V_OFFSET + 1 AND V_OFFSET + V_FETCH_SIZE;
END PAGING_PROC;
/

2. 프로시저 호출

스토어드 프로시저를 호출하려면 아래처럼 실행합니다:

VARIABLE P_CURSOR REFCURSOR;

BEGIN
    PAGING_PROC(
        P_PAGE_NUMBER => 2,    -- 두 번째 페이지
        P_PAGE_SIZE => 10,     -- 페이지당 10행
        P_RESULT => :P_CURSOR  -- 결과 커서에 저장
    );
END;
/

-- 결과 확인
PRINT P_CURSOR;

상세 설명

  1. 매개변수
    • P_PAGE_NUMBER: 요청한 페이지 번호를 지정합니다.
    • P_PAGE_SIZE: 한 페이지에 표시할 행 수를 지정합니다.
    • P_RESULT: 결과를 반환받기 위한 커서입니다.
  2. 페이징 로직
    • V_OFFSET은 (페이지 번호 - 1) * 페이지 크기로 계산됩니다.
    • ROW_NUMBER()를 사용하여 각 행에 고유 번호를 부여합니다.
    • BETWEEN을 통해 OFFSET + 1부터 OFFSET + 페이지 크기까지 필터링합니다.
  3. REF CURSOR 반환
    • SYS_REFCURSOR를 사용하여 결과를 반환합니다.
    • 호출 후 PRINT 명령어로 결과를 확인하거나, 애플리케이션에서 커서를 처리할 수 있습니다.

FETCH FIRST 방식으로 변경한 예제 (12c 이상)

오라클 12c 이상에서는 OFFSET과 FETCH NEXT를 활용할 수도 있습니다.

CREATE OR REPLACE PROCEDURE PAGING_PROC (
    P_PAGE_NUMBER IN NUMBER,
    P_PAGE_SIZE IN NUMBER,
    P_RESULT OUT SYS_REFCURSOR
)
AS
    V_OFFSET NUMBER;
BEGIN
    V_OFFSET := (P_PAGE_NUMBER - 1) * P_PAGE_SIZE;

    OPEN P_RESULT FOR
    SELECT *
    FROM EMPLOYEES
    ORDER BY EMPLOYEE_ID ASC
    OFFSET V_OFFSET ROWS FETCH NEXT P_PAGE_SIZE ROWS ONLY;
END PAGING_PROC;
/

테스트 데이터

아래와 같은 테이블(EMPLOYEES)이 있다고 가정합니다:

EMPLOYEE_ID FIRST_NAME LAST_NAME DEPARTMENT
1 John Doe HR
2 Jane Smith IT
3 Alice Johnson Finance
... ... ... ...

 

728x90

P_CURSOR 를 mybatis에서 활용하는 예제

 

MyBatis에서 Oracle의 SYS_REFCURSOR를 활용하려면, REF CURSOR를 매핑할 수 있는 MyBatis 설정과 매퍼 인터페이스를 작성해야 합니다. 아래는 MyBatis에서 P_CURSOR를 활용하는 예제를 단계별로 설명드립니다.


1. Oracle Stored Procedure

아래는 기존의 PAGING_PROC 프로시저입니다:

CREATE OR REPLACE PROCEDURE PAGING_PROC (
    P_PAGE_NUMBER IN NUMBER,         -- 요청 페이지 번호
    P_PAGE_SIZE IN NUMBER,           -- 페이지 크기 (한 페이지당 행 수)
    P_RESULT OUT SYS_REFCURSOR       -- 결과를 반환할 커서
)
AS
BEGIN
    OPEN P_RESULT FOR
    SELECT *
    FROM EMPLOYEES
    ORDER BY EMPLOYEE_ID ASC
    OFFSET (P_PAGE_NUMBER - 1) * P_PAGE_SIZE ROWS FETCH NEXT P_PAGE_SIZE ROWS ONLY;
END PAGING_PROC;
/

2. MyBatis Mapper XML

MyBatis에서 SYS_REFCURSOR를 처리하려면 매퍼 XML에서 RESULT_MAP과 CALL 구문을 작성해야 합니다.

매퍼 XML (PagingMapper.xml)

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.example.mapper.PagingMapper">

    <!-- REF CURSOR 결과를 매핑 -->
    <resultMap id="employeeResultMap" type="com.example.model.Employee">
        <result property="employeeId" column="EMPLOYEE_ID" />
        <result property="firstName" column="FIRST_NAME" />
        <result property="lastName" column="LAST_NAME" />
        <result property="department" column="DEPARTMENT" />
    </resultMap>

    <!-- Stored Procedure 호출 -->
    <select id="getPagedEmployees" statementType="CALLABLE" resultMap="employeeResultMap">
        {CALL PAGING_PROC(
            #{pageNumber, mode=IN, jdbcType=INTEGER},
            #{pageSize, mode=IN, jdbcType=INTEGER},
            #{cursor, mode=OUT, jdbcType=CURSOR, resultMap=employeeResultMap}
        )}
    </select>

</mapper>

3. 매퍼 인터페이스

MyBatis 매퍼 인터페이스에서 프로시저 호출 메서드를 정의합니다.

인터페이스 (PagingMapper.java)

package com.example.mapper;

import com.example.model.Employee;
import org.apache.ibatis.annotations.Param;

import java.util.List;

public interface PagingMapper {
    List<Employee> getPagedEmployees(
        @Param("pageNumber") int pageNumber,
        @Param("pageSize") int pageSize
    );
}

4. Employee 모델 클래스

Oracle EMPLOYEES 테이블에 매핑되는 Java 클래스입니다.

모델 클래스 (Employee.java)

package com.example.model;

public class Employee {
    private int employeeId;
    private String firstName;
    private String lastName;
    private String department;

    // Getters and Setters
    public int getEmployeeId() {
        return employeeId;
    }

    public void setEmployeeId(int employeeId) {
        this.employeeId = employeeId;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getDepartment() {
        return department;
    }

    public void setDepartment(String department) {
        this.department = department;
    }
}

5. Service Layer

서비스 계층에서 MyBatis 매퍼를 호출하여 데이터를 가져옵니다.

서비스 클래스 (EmployeeService.java)

package com.example.service;

import com.example.mapper.PagingMapper;
import com.example.model.Employee;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class EmployeeService {
    private final PagingMapper pagingMapper;

    public EmployeeService(PagingMapper pagingMapper) {
        this.pagingMapper = pagingMapper;
    }

    public List<Employee> getPagedEmployees(int pageNumber, int pageSize) {
        return pagingMapper.getPagedEmployees(pageNumber, pageSize);
    }
}

6. Controller Layer

컨트롤러에서 요청을 받아 페이징 결과를 반환합니다.

컨트롤러 (EmployeeController.java)

package com.example.controller;

import com.example.model.Employee;
import com.example.service.EmployeeService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
public class EmployeeController {
    private final EmployeeService employeeService;

    public EmployeeController(EmployeeService employeeService) {
        this.employeeService = employeeService;
    }

    @GetMapping("/employees")
    public List<Employee> getPagedEmployees(
        @RequestParam("page") int pageNumber,
        @RequestParam("size") int pageSize
    ) {
        return employeeService.getPagedEmployees(pageNumber, pageSize);
    }
}

7. 실행 및 테스트

  1. 서버를 실행합니다.
  2. REST API 호출:
    • 예: GET /employees?page=1&size=10
  3. 결과는 JSON 형식으로 반환됩니다.

참고 사항

  • MyBatis에서 SYS_REFCURSOR를 사용하려면 Oracle JDBC 드라이버가 제대로 설정되어 있어야 합니다.
  • 성능을 위해 페이징 처리 시 적절한 인덱스를 활용하세요.

 

35개 행이 있고 페이지당 10개행이라고 할때 10페이지를 호출하면 마지막페이지 3페이지를 리턴하고 리턴한 페이지가 3이라는걸 알려주도록 수정해

 

요청하신 "마지막 페이지를 리턴하고, 리턴한 페이지가 몇 페이지인지 반환"하는 방식으로 MyBatis와 프로시저를 수정해 보겠습니다. 아래는 수정된 예제입니다.


1. Oracle Stored Procedure 수정

프로시저에서 총 페이지 수를 계산하고, 요청한 페이지가 총 페이지 수를 초과하면 마지막 페이지의 데이터를 반환하도록 수정합니다.

CREATE OR REPLACE PROCEDURE PAGING_PROC (
    P_PAGE_NUMBER IN NUMBER,          -- 요청 페이지 번호
    P_PAGE_SIZE IN NUMBER,            -- 페이지 크기
    P_ACTUAL_PAGE OUT NUMBER,         -- 실제 반환된 페이지 번호
    P_RESULT OUT SYS_REFCURSOR        -- 결과를 반환할 커서
)
AS
    V_TOTAL_ROWS NUMBER;              -- 총 행 수
    V_TOTAL_PAGES NUMBER;             -- 총 페이지 수
    V_OFFSET NUMBER;                  -- 건너뛸 행의 수
BEGIN
    -- 총 행 수 계산
    SELECT COUNT(*) INTO V_TOTAL_ROWS FROM EMPLOYEES;

    -- 총 페이지 수 계산
    V_TOTAL_PAGES := CEIL(V_TOTAL_ROWS / P_PAGE_SIZE);

    -- 요청 페이지가 총 페이지를 초과하면 마지막 페이지로 설정
    IF P_PAGE_NUMBER > V_TOTAL_PAGES THEN
        P_PAGE_NUMBER := V_TOTAL_PAGES;
    END IF;

    -- 실제 반환된 페이지 번호 설정
    P_ACTUAL_PAGE := P_PAGE_NUMBER;

    -- OFFSET 계산
    V_OFFSET := (P_PAGE_NUMBER - 1) * P_PAGE_SIZE;

    -- REF CURSOR에 결과 할당
    OPEN P_RESULT FOR
    SELECT *
    FROM EMPLOYEES
    ORDER BY EMPLOYEE_ID ASC
    OFFSET V_OFFSET ROWS FETCH NEXT P_PAGE_SIZE ROWS ONLY;
END PAGING_PROC;
/

2. MyBatis Mapper XML 수정

P_ACTUAL_PAGE를 OUT 파라미터로 추가합니다.

매퍼 XML (PagingMapper.xml)

<select id="getPagedEmployees" statementType="CALLABLE">
    {CALL PAGING_PROC(
        #{pageNumber, mode=IN, jdbcType=INTEGER},
        #{pageSize, mode=IN, jdbcType=INTEGER},
        #{actualPage, mode=OUT, jdbcType=INTEGER},
        #{cursor, mode=OUT, jdbcType=CURSOR, resultMap=employeeResultMap}
    )}
</select>

3. Mapper 인터페이스 수정

actualPage를 매핑하기 위해 반환값을 담을 객체를 사용합니다.

인터페이스 (PagingMapper.java)

package com.example.mapper;

import com.example.model.Employee;
import org.apache.ibatis.annotations.Param;

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

public interface PagingMapper {
    void getPagedEmployees(
        @Param("pageNumber") int pageNumber,
        @Param("pageSize") int pageSize,
        @Param("actualPage") Map<String, Object> actualPage, // OUT 파라미터 저장
        @Param("cursor") List<Employee> cursor             // 결과 데이터 저장
    );
}

4. Service Layer 수정

결과와 실제 반환된 페이지 번호를 함께 처리하도록 수정합니다.

서비스 클래스 (EmployeeService.java)

package com.example.service;

import com.example.mapper.PagingMapper;
import com.example.model.Employee;
import org.springframework.stereotype.Service;

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

@Service
public class EmployeeService {
    private final PagingMapper pagingMapper;

    public EmployeeService(PagingMapper pagingMapper) {
        this.pagingMapper = pagingMapper;
    }

    public Map<String, Object> getPagedEmployees(int pageNumber, int pageSize) {
        Map<String, Object> result = new HashMap<>();
        Map<String, Object> actualPage = new HashMap<>();
        List<Employee> employees;

        pagingMapper.getPagedEmployees(pageNumber, pageSize, actualPage, employees);

        result.put("employees", employees);
        result.put("actualPage", actualPage.get("actualPage"));
        return result;
    }
}

5. Controller Layer 수정

최종 반환값에 실제 페이지 번호를 포함합니다.

컨트롤러 (EmployeeController.java)

package com.example.controller;

import com.example.service.EmployeeService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;

@RestController
public class EmployeeController {
    private final EmployeeService employeeService;

    public EmployeeController(EmployeeService employeeService) {
        this.employeeService = employeeService;
    }

    @GetMapping("/employees")
    public Map<String, Object> getPagedEmployees(
        @RequestParam("page") int pageNumber,
        @RequestParam("size") int pageSize
    ) {
        return employeeService.getPagedEmployees(pageNumber, pageSize);
    }
}

6. REST API 호출 결과 예시

  1. 요청: GET /employees?page=10&size=10
  2. 결과 (JSON):
{
    "employees": [
        {"employeeId": 31, "firstName": "Alice", "lastName": "Johnson", "department": "Finance"},
        {"employeeId": 32, "firstName": "Bob", "lastName": "Smith", "department": "IT"},
        {"employeeId": 33, "firstName": "Carol", "lastName": "Jones", "department": "HR"},
        {"employeeId": 34, "firstName": "David", "lastName": "Brown", "department": "Marketing"},
        {"employeeId": 35, "firstName": "Eve", "lastName": "Davis", "department": "Sales"}
    ],
    "actualPage": 3
}

주요 변경 사항

  1. Stored Procedure에서 요청 페이지가 총 페이지를 초과하면 마지막 페이지를 반환하도록 처리.
  2. P_ACTUAL_PAGE를 통해 실제 반환된 페이지 번호를 전달.
  3. MyBatis와 서비스, 컨트롤러 계층을 수정하여 결과에 actualPage 값을 포함.

페이지 리본이 10개 단위라고 할때 actualPage가 3이면 1~10 까지고 15이면 11~20 까지 잖아.. 이걸 구현해봐

 

페이지 리본이 10개 단위로 나뉘는 방식으로 요청에 따라 리본 범위를 계산하고 반환하도록 구현하겠습니다. 아래는 이를 포함하여 수정된 예제입니다.


1. Stored Procedure 수정

PAGE RIBBON의 범위(START_PAGE, END_PAGE)를 계산하고 반환하도록 프로시저를 수정합니다.

프로시저 (PAGING_PROC)

CREATE OR REPLACE PROCEDURE PAGING_PROC (
    P_PAGE_NUMBER IN NUMBER,          -- 요청 페이지 번호
    P_PAGE_SIZE IN NUMBER,            -- 페이지 크기
    P_ACTUAL_PAGE OUT NUMBER,         -- 실제 반환된 페이지 번호
    P_START_RIBBON OUT NUMBER,        -- 페이지 리본 시작 번호
    P_END_RIBBON OUT NUMBER,          -- 페이지 리본 끝 번호
    P_RESULT OUT SYS_REFCURSOR        -- 결과를 반환할 커서
)
AS
    V_TOTAL_ROWS NUMBER;              -- 총 행 수
    V_TOTAL_PAGES NUMBER;             -- 총 페이지 수
    V_OFFSET NUMBER;                  -- 건너뛸 행의 수
BEGIN
    -- 총 행 수 계산
    SELECT COUNT(*) INTO V_TOTAL_ROWS FROM EMPLOYEES;

    -- 총 페이지 수 계산
    V_TOTAL_PAGES := CEIL(V_TOTAL_ROWS / P_PAGE_SIZE);

    -- 요청 페이지가 총 페이지를 초과하면 마지막 페이지로 설정
    IF P_PAGE_NUMBER > V_TOTAL_PAGES THEN
        P_PAGE_NUMBER := V_TOTAL_PAGES;
    END IF;

    -- 실제 반환된 페이지 번호 설정
    P_ACTUAL_PAGE := P_PAGE_NUMBER;

    -- 페이지 리본 범위 계산
    P_START_RIBBON := FLOOR((P_PAGE_NUMBER - 1) / 10) * 10 + 1;
    P_END_RIBBON := P_START_RIBBON + 9;

    -- 리본 끝 페이지가 총 페이지를 초과하면 조정
    IF P_END_RIBBON > V_TOTAL_PAGES THEN
        P_END_RIBBON := V_TOTAL_PAGES;
    END IF;

    -- OFFSET 계산
    V_OFFSET := (P_PAGE_NUMBER - 1) * P_PAGE_SIZE;

    -- REF CURSOR에 결과 할당
    OPEN P_RESULT FOR
    SELECT *
    FROM EMPLOYEES
    ORDER BY EMPLOYEE_ID ASC
    OFFSET V_OFFSET ROWS FETCH NEXT P_PAGE_SIZE ROWS ONLY;
END PAGING_PROC;
/

2. MyBatis Mapper XML 수정

P_START_RIBBON과 P_END_RIBBON을 OUT 파라미터로 추가합니다.

매퍼 XML (PagingMapper.xml)

<select id="getPagedEmployees" statementType="CALLABLE">
    {CALL PAGING_PROC(
        #{pageNumber, mode=IN, jdbcType=INTEGER},
        #{pageSize, mode=IN, jdbcType=INTEGER},
        #{actualPage, mode=OUT, jdbcType=INTEGER},
        #{startRibbon, mode=OUT, jdbcType=INTEGER},
        #{endRibbon, mode=OUT, jdbcType=INTEGER},
        #{cursor, mode=OUT, jdbcType=CURSOR, resultMap=employeeResultMap}
    )}
</select>

3. Mapper 인터페이스 수정

startRibbon과 endRibbon을 추가합니다.

인터페이스 (PagingMapper.java)

package com.example.mapper;

import com.example.model.Employee;
import org.apache.ibatis.annotations.Param;

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

public interface PagingMapper {
    void getPagedEmployees(
        @Param("pageNumber") int pageNumber,
        @Param("pageSize") int pageSize,
        @Param("actualPage") Map<String, Object> actualPage,   // 실제 페이지
        @Param("startRibbon") Map<String, Object> startRibbon, // 리본 시작
        @Param("endRibbon") Map<String, Object> endRibbon,     // 리본 끝
        @Param("cursor") List<Employee> cursor                // 결과 데이터
    );
}

4. Service Layer 수정

리본 범위 값을 반환하도록 로직을 수정합니다.

서비스 클래스 (EmployeeService.java)

package com.example.service;

import com.example.mapper.PagingMapper;
import com.example.model.Employee;
import org.springframework.stereotype.Service;

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

@Service
public class EmployeeService {
    private final PagingMapper pagingMapper;

    public EmployeeService(PagingMapper pagingMapper) {
        this.pagingMapper = pagingMapper;
    }

    public Map<String, Object> getPagedEmployees(int pageNumber, int pageSize) {
        Map<String, Object> result = new HashMap<>();
        Map<String, Object> actualPage = new HashMap<>();
        Map<String, Object> startRibbon = new HashMap<>();
        Map<String, Object> endRibbon = new HashMap<>();
        List<Employee> employees;

        pagingMapper.getPagedEmployees(pageNumber, pageSize, actualPage, startRibbon, endRibbon, employees);

        result.put("employees", employees);
        result.put("actualPage", actualPage.get("actualPage"));
        result.put("startRibbon", startRibbon.get("startRibbon"));
        result.put("endRibbon", endRibbon.get("endRibbon"));
        return result;
    }
}

5. Controller Layer 수정

결과에 리본 범위를 포함하도록 수정합니다.

컨트롤러 (EmployeeController.java)

package com.example.controller;

import com.example.service.EmployeeService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;

@RestController
public class EmployeeController {
    private final EmployeeService employeeService;

    public EmployeeController(EmployeeService employeeService) {
        this.employeeService = employeeService;
    }

    @GetMapping("/employees")
    public Map<String, Object> getPagedEmployees(
        @RequestParam("page") int pageNumber,
        @RequestParam("size") int pageSize
    ) {
        return employeeService.getPagedEmployees(pageNumber, pageSize);
    }
}

6. REST API 호출 결과 예시

  1. 요청: GET /employees?page=15&size=10
  2. 결과 (JSON):
{
    "employees": [
        {"employeeId": 141, "firstName": "Alice", "lastName": "Johnson", "department": "Finance"},
        {"employeeId": 142, "firstName": "Bob", "lastName": "Smith", "department": "IT"},
        {"employeeId": 143, "firstName": "Carol", "lastName": "Jones", "department": "HR"},
        {"employeeId": 144, "firstName": "David", "lastName": "Brown", "department": "Marketing"},
        {"employeeId": 145, "firstName": "Eve", "lastName": "Davis", "department": "Sales"}
    ],
    "actualPage": 15,
    "startRibbon": 11,
    "endRibbon": 20
}

주요 변경 사항

  1. Stored Procedure
    • P_START_RIBBON과 P_END_RIBBON을 계산.
    • 요청 페이지에 따라 리본 범위를 조정.
    •  
    • Service & Controller
    • 리본 범위를 클라이언트에 반환.

추가적인 요청이 있으시면 언제든 말씀해 주세요! 😊

 

 

2024.12.14 - [Oracle Database 강좌] - 오라클 페이지네이션 성능 최적화: ROWNUM vs ROW_NUMBER() 심층 분석 및 추가 최적화 방안

 

오라클 페이지네이션 성능 최적화: ROWNUM vs ROW_NUMBER() 심층 분석 및 추가 최적화 방안

2024.12.14 - [Oracle Database 강좌] - 오라클 페이징 구현 및 스토어드 프로시저 활용: 심층 분석 및 실제 예제 오라클 페이징 구현 및 스토어드 프로시저 활용: 심층 분석 및 실제 예제오라클(Oracle) 데

notion4570.tistory.com

 

728x90