본문 바로가기

학습/Java_Spring

Mybatis일때 Controller에서의 페이징처리

페이징 처리는 다음과 같은 과정으로 이루어집니다:

  1. 컨트롤러에서 클라이언트의 page 파라미터를 받아 서비스 계층에 전달합니다.
  2. 서비스 계층에서 pageNumber를 이용해 offset을 계산하고, 매퍼에 offset과 pageSize를 전달하여 데이터를 조회합니다.
  3. MyBatis 매퍼에서는 SQL 쿼리에서 LIMIT과 OFFSET을 사용해 페이징 처리를 합니다.
  4. Thymeleaf 뷰에서 현재 페이지와 총 페이지 수를 이용해 이전/다음 페이지로 이동할 수 있는 링크를 생성합니다.

이 과정을 통해 클라이언트에 필요한 데이터만 전송하여 성능을 최적화할 수 있습니다.

 

Spring Boot와 MyBatis를 사용하여 `board` 테이블에 대한 페이징 처리 예제를 작성해 보겠습니다. 이 예제에서는 `board` 테이블을 사용하고, Gradle과 Thymeleaf를 사용하여 프론트엔드를 구현합니다.

### 1. Gradle 설정

먼저, `build.gradle` 파일에 필요한 의존성을 추가합니다.

```gradle
plugins {
    id 'org.springframework.boot' version '2.7.17'
    id 'io.spring.dependency-management' version '1.0.15.RELEASE'
    id 'java'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.1.4'

    implementation 'org.springframework.boot:spring-boot-starter-jdbc'
    implementation 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'
    runtimeOnly 'mysql:mysql-connector-java'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'


}

test {
    useJUnitPlatform()
}
```

### 2. 데이터베이스 설정

`application.properties` 또는 `application.yml` 파일에 MySQL 데이터베이스 설정을 추가합니다.

```properties
spring.datasource.url=jdbc:mysql://localhost:3306/your_database_name?useSSL=false&serverTimezone=UTC
spring.datasource.username=your_username
spring.datasource.password=your_password
spring.datasource.driver-class-name=cohttp://m.mysql.cj.jdbc.Driver

mybatis.mapper-locations=classpath:mapper/*.xml
spring.jpa.show-sql=true
```

### 3. 데이터베이스 테이블 생성

`board` 테이블을 생성하는 SQL 스크립트입니다.

```sql
CREATE TABLE board (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    title VARCHAR(100) NOT NULL,
    content TEXT NOT NULL,
    writer VARCHAR(50) NOT NULL,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
```

### 4. 매퍼 인터페이스와 XML 설정

#### 매퍼 인터페이스

```java
@Mapper
public interface BoardMapper {
    List<Board> listAll(@Param("offset") int offset, @Param("pageSize") int pageSize);
    int count();
}
```

#### 매퍼 XML 설정

`src/main/resources/mapper/BoardMapper.xml` 파일을 생성하고 다음 내용을 추가합니다.

```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="cohttp://m.example.mapper.BoardMapper">

    <select id="listAll" resultType="cohttp://m.example.domain.Board">
        SELECT
            id,
            title,
            content,
            writer,
            created_at,
            updated_at
        FROM board
        ORDER BY created_at DESC
        LIMIT #{pageSize} OFFSET #{offset}
    </select>

    <select id="count" resultType="int">
        SELECT COUNT(*) FROM board
    </select>

</mapper>
```

### 5. 도메인 클래스

`src/main/java/com/example/domain/Board.java` 파일을 생성하고 다음 내용을 추가합니다.

```java
package cohttp://m.example.domain;

import lombok.Data;
import java.time.LocalDateTime;

@Data
public class Board {
    private Long id;
    private String title;
    private String content;
    private String writer;
    private LocalDateTime createdAt;
    private LocalDateTime updatedAt;
}
```

### 6. 서비스 계층

`src/main/java/com/example/service/BoardService.java` 파일을 생성하고 다음 내용을 추가합니다.

```java
package com.example.service;

import cohttp://m.example.domain.Board;
import cohttp://m.example.mapper.BoardMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
@RequiredArgsConstructor
public class BoardService {
    private final BoardMapper boardMapper;
    private static final int PAGE_SIZE = 10;

    public List<Board> list(int pageNumber) {
        int offset = (pageNumber - 1) * PAGE_SIZE;
        return boardMapper.listAll(offset, PAGE_SIZE);
    }

    public int count() {
        return boardMapper.count();
    }
}
```

### 7. 컨트롤러

`src/main/java/com/example/controller/BoardController.java` 파일을 생성하고 다음 내용을 추가합니다.

```java
package com.example.controller;

import cohttp://m.example.domain.Board;
import com.example.service.BoardService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

import java.util.List;

@Controller
@RequiredArgsConstructor
public class BoardController {
    private final BoardService boardService;

    @GetMapping("/board/list")
    public String list(@RequestParam(value = "page", defaultValue = "1") int pageNumber, Model model) {
        List<Board> boards = boardService.list(pageNumber);
        int totalCount = boardService.count();
        int totalPages = (int) Math.ceil((double) totalCount / 10);

        model.addAttribute("boards", boards);
        model.addAttribute("currentPage", pageNumber);
        model.addAttribute("totalPages", totalPages);
        return "board/list";
    }
}
```

### 8. Thymeleaf 뷰

`src/main/resources/templates/board/list.html` 파일을 생성하고 다음 내용을 추가합니다.

```html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Board List</title>
</head>
<body>
<h1>Board List</h1>
<table>
    <thead>
    <tr>
        <th>ID</th>
        <th>Title</th>
        <th>Writer</th>
        <th>Created At</th>
    </tr>
    </thead>
    <tbody>
    <tr th:each="board : ${boards}">
        <td th:text="${board.id}"></td>
        <td th:text="${board.title}"></td>
        <td th:text="${board.writer}"></td>
        <td th:text="${board.createdAt}"></td>
    </tr>
    </tbody>
</table>
<div>
    <span th:text="'Page ' + ${currentPage} + ' of ' + ${totalPages}"></span>
    <div>
        <a th:if="${currentPage > 1}" th:href="@{/board/list(page=${currentPage - 1})}">Previous</a>
        <a th:if="${currentPage < totalPages}" th:href="@{/board/list(page=${currentPage + 1})}">Next</a>
    </div>
</div>
</body>
</html>
```