Spring

[Spring] 게시판 페이징 처리 (사용하는 이유 및 특징, MyBatis, JPA)

공모 2023. 11. 2. 19:06
반응형

사용하는 이유 및 특징:

  1. 효율적인 데이터 로딩:
    • 대용량 데이터를 모두 한번에 로딩하는 것은 시스템에 부하를 줄 수 있기 때문에 페이징 처리를 통해 필요한 만큼의 데이터만 로드하여 시스템의 효율성을 높일 수 있다.
  2. 사용자 경험 향상
    • 사용자가 한 페이지에서 너무 많은 정보를 한번에 볼 때, 원하는 데이터를 찾기 어렵고 혼란스러울 수 있다. 페이징 처리를 통해 정보를 구조적으로 제공하면 사용자 경험이 향상된다.
  3. 네트워크 트래픽 감소
    • 한번의 요청으로 모든 데이터를 전송하는 것보다, 필요한 부분만 요청하여 전송하는 것이 네트워크 트래픽을 줄여준다.
  4. 서버 부하 감소
    • 데이터베이스에서 필요한 부분만 쿼리하여 가져오는 것은 서버와 데이터베이스의 부하를 줄여주며, 전체 시스템의 응답 시간을 개선시켜준다.
  5. 데이터 관리 용이
    • 관리자나 사용자가 데이터를 검토하거나 관리할 때, 페이징 처리된 데이터는 보기 편하고 관리하기 쉽다.
  6. 반응 시간 최적화
    • 페이징 처리를 통해 한번에 작은 양의 데이터만 처리하므로, 웹 페이지의 로딩 및 반응 시간이 최적화된다.
  7. 자원 사용 최적화
    • 메모리와 CPU 자원을 효율적으로 사용하여 시스템 성능을 향상시킬 수 있다. 

 

MyBatis:

1. IDE / DataBase / spring initializr 정보

더보기

[IDE]

Intelij Community

 

[DataBase]

MariaDB

 

[spring initializr 정보]

Project
    Gradle - Groovy
Language
    Java
Spring Boot
    3.15
Package name
    com.paging.mybatis
Packaging
    Jar
Java
    17
Dependencies
    Spring Web
    Lombok
    MariaDB Driver
    MyBatis Framework

2. 프로젝트 구조

3. 기본 설정 (application.yml)

server:
  port: 8989

spring:
  datasource:
    driver-class-name: org.mariadb.jdbc.Driver
    url: jdbc:mariadb://접속 정보:3306/DB
    username: 아이디
    password: 비밀번호

mybatis:
  type-aliases-package: com.paging.mybatis.model;
  mapper-locations: classpath:mapper/*.xml
  configuration:
    map-underscore-to-camel-case: true
더보기

driver-class-name:
사용할 JDBC 드라이버의 클래스 이름을 지정한다. 여기서는 MariaDB의 JDBC 드라이버인 org.mariadb.jdbc.Driver를 사용한다.
url:
데이터베이스에 접속하기 위한 URL을 지정한다. jdbc:mariadb://접속 정보:3306/DB와 같이 접속 정보와 포트, 데이터베이스 이름을 입력한다.
username:
데이터베이스에 접속할 사용자의 아이디를 지정한다.
password:
데이터베이스에 접속할 사용자의 비밀번호를 지정한다.

type-aliases-package:
MyBatis의 Type Aliases를 사용하기 위해 지정된 패키지를 설정한다. 여기서는 com.paging.mybatis.model 패키지를 지정하여 해당 패키지 내에 있는 클래스들을 Type Aliases로 사용할 수 있도록 한다.
mapper-locations:
MyBatis의 매퍼 파일 위치를 설정한다. classpath:mapper/*.xml와 같이 클래스패스 상의 mapper 폴더 내에 있는 모든 XML 파일을 매퍼로 인식한다.
configuration.map-underscore-to-camel-case:
MyBatis가 데이터베이스의 컬럼명을 자바의 카멜케이스 형식에 맞게 매핑할지 여부를 설정한다. true로 설정하면 데이터베이스 컬럼명의 언더스코어(_)를 자바의 카멜케이스로 변환하여 매핑한다.

4. 소스 코드

PageInfo (java)

package com.paging.mybatis.common.paging;

import java.io.Serializable;
import java.util.List;

public class PageInfo<T> implements Serializable {

    private static final long serialVersionUID = 1L;
    
    private final int pageIndex;
    private final int pageSize;
    private final int totalCount;
    private final List<T> data;
    
    public PageInfo(int pageIndex, int pageSize, int totalCount, List<T> data) {
        this.pageIndex = pageIndex;
        this.pageSize = pageSize;
        this.totalCount = totalCount;
        this.data = data;
    }
    
    public int getPageIndex() {
        return pageIndex;
    }
    
    public int getPageSize() {
        return pageSize;
    }
    
    public int getTotalCount() {
        return totalCount;
    }
    
    public int getTotalPage() {
        return (int) Math.ceil((double) totalCount / pageSize);
    }

    public List<T> getData() {
        return data;
    }
}

BoardController (java)

package com.paging.mybatis.controller;

import com.paging.mybatis.service.BoardService;
import com.paging.mybatis.model.Board;
import com.paging.mybatis.common.paging.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;


@RestController
public class BoardController {

    @Autowired
    private BoardService boardService;

    @GetMapping("/boards")
    public PageInfo<Board> getBoards(
            @RequestParam(defaultValue = "1") int pageIndex,
            @RequestParam(defaultValue = "10") int pageSize) {
        return boardService.getBoards(pageIndex, pageSize);
    }
}

BoardMapper (interface)

package com.paging.mybatis.mapper;

import com.paging.mybatis.model.Board;
import org.apache.ibatis.annotations.Mapper;

import java.util.List;

@Mapper
public interface BoardMapper {

    int getTotalCount();
    List<Board> findBoards(int offset, int limit);

}

Board (java)

package com.paging.mybatis.model;

import lombok.Data;

import java.time.LocalDateTime;

@Data
public class Board {

    private Long id;                    // 기본 키
    private String title;               // 제목
    private String content;             // 내용
    private String createdBy;           // 생성자
    private LocalDateTime createdAt;    // 생성 일자

}

BoardService (java)

package com.paging.mybatis.service;


import com.paging.mybatis.model.Board;
import com.paging.mybatis.mapper.BoardMapper;
import com.paging.mybatis.common.paging.PageInfo;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class BoardService {

    private final BoardMapper boardMapper;

    public BoardService(BoardMapper boardMapper) {
        this.boardMapper = boardMapper;
    }

    public PageInfo<Board> getBoards(int pageIndex, int pageSize) {
        int totalCount = boardMapper.getTotalCount();
        List<Board> boards = boardMapper.findBoards((pageIndex - 1) * pageSize, pageSize);
        return new PageInfo<>(pageIndex, pageSize, totalCount, boards);
    }
}

BoardMapper (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.paging.mybatis.mapper.BoardMapper">
    <select id="getTotalCount" resultType="int">
        SELECT COUNT(*) FROM board
    </select>

    <select id="findBoards" resultType="Board">
        SELECT * FROM board LIMIT #{limit} OFFSET #{offset}
    </select>
</mapper>

5. 실행 결과 (JSON)

더보기

// 20231104022159
// http://localhost:8989/boards

{
  "pageIndex": 1,
  "pageSize": 10,
  "totalCount": 21,
  "data": [
    {
      "id": 1,
      "title": "테스트 1",
      "content": "안녕하세요",
      "createdBy": "StudyMemo",
      "createdAt": "2023-11-02T17:15:43"
    },
    {
      "id": 2,
      "title": "테스트 2",
      "content": "안녕하세요",
      "createdBy": "StudyMemo",
      "createdAt": "2023-11-02T17:15:43"
    },
    {
      "id": 3,
      "title": "테스트 3",
      "content": "안녕하세요",
      "createdBy": "StudyMemo",
      "createdAt": "2023-11-02T17:15:43"
    },
    {
      "id": 4,
      "title": "테스트 4",
      "content": "안녕하세요",
      "createdBy": "StudyMemo",
      "createdAt": "2023-11-02T17:15:43"
    },
    {
      "id": 5,
      "title": "테스트 5",
      "content": "안녕하세요",
      "createdBy": "StudyMemo",
      "createdAt": "2023-11-02T17:15:43"
    },
    {
      "id": 6,
      "title": "테스트 6",
      "content": "안녕하세요",
      "createdBy": "StudyMemo",
      "createdAt": "2023-11-02T17:15:43"
    },
    {
      "id": 7,
      "title": "테스트 7",
      "content": "안녕하세요",
      "createdBy": "StudyMemo",
      "createdAt": "2023-11-02T17:15:43"
    },
    {
      "id": 8,
      "title": "테스트 8",
      "content": "안녕하세요",
      "createdBy": "StudyMemo",
      "createdAt": "2023-11-02T17:15:43"
    },
    {
      "id": 9,
      "title": "테스트 9",
      "content": "안녕하세요",
      "createdBy": "StudyMemo",
      "createdAt": "2023-11-02T17:15:43"
    },
    {
      "id": 10,
      "title": "테스트 10",
      "content": "안녕하세요",
      "createdBy": "StudyMemo",
      "createdAt": "2023-11-02T17:15:43"
    }
  ],
  "totalPage": 3
}

 

JPA:

1. IDE / DataBase / spring initializr 정보

더보기

[IDE]

Intelij Community

 

[DataBase]

MariaDB

 

[spring initializr 정보]

Project
    Gradle - Groovy
Language
    Java
Spring Boot
    3.15
Package name
    com.paging.jpa
Packaging
    Jar
Java
    17
Dependencies
    Spring Web
    Lombok
    MariaDB Driver
    Spring Data JPA

2. 프로젝트 구조

3. 기본 설정 (application.yml)

server:
  port: 9898

spring:
  datasource:
    driver-class-name: org.mariadb.jdbc.Driver
    url: jdbc:mariadb://접속정보:3306/DB
    username: 아이디
    password: 비밀번호

  jpa:
    hibernate:
      ddl-auto: update
    show-sql: true
    properties:
      hibernate:
        format_sql: true
더보기

driver-class-name:
사용할 JDBC 드라이버의 클래스 이름을 지정한다. 여기서는 MariaDB의 JDBC 드라이버인 org.mariadb.jdbc.Driver를 사용한다.
url:
데이터베이스에 접속하기 위한 URL을 지정한다. jdbc:mariadb://접속 정보:3306/DB와 같이 접속 정보와 포트, 데이터베이스 이름을 입력한다.
username:
데이터베이스에 접속할 사용자의 아이디를 지정한다.
password:
데이터베이스에 접속할 사용자의 비밀번호를 지정한다.

hibernate.ddl-auto:
데이터베이스의 스키마를 자동으로 생성 및 갱신하는 방식을 설정한다.
update로 설정하면 애플리케이션 실행 시 엔티티 클래스에 변경이 있으면 해당 변경을 데이터베이스에 반영한다.
show-sql:
Hibernate가 실행하는 SQL 쿼리를 콘솔에 출력할지 여부를 설정한다.
true로 설정하면 실행되는 SQL 쿼리를 확인할 수 있다.
hibernate.format_sql:
출력되는 SQL 쿼리를 읽기 쉬운 형식으로 포맷팅할지 여부를 설정한다.
true로 설정하면 쿼리를 읽기 쉬운 형태로 출력다.

4. 소스 코드

BoardController (java)

package com.paging.jpa.controller;

import com.paging.jpa.model.Board;
import com.paging.jpa.service.BoardService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/boards")
public class BoardController {

    @Autowired
    private BoardService boardService;

    @GetMapping
    public Page<Board> list(@RequestParam(defaultValue = "0") int page,
                            @RequestParam(defaultValue = "10") int size) {
        return boardService.getBoards(page, size);
    }
}

Board (java)

package com.paging.jpa.model;

import jakarta.persistence.*;
import lombok.Data;

import java.time.LocalDateTime;

@Data
@Entity
@Table(name="board")
public class Board {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;                    // 기본 키

    @Column(name = "title")
    private String title;               // 제목

    @Column(name = "content")
    private String content;             // 내용

    @Column(name = "createdBy")
    private String createdBy;           // 생성자

    @Column(name = "createdAt")
    private LocalDateTime createdAt;    // 생성 일자

}

BoardRepository (java)

package com.paging.jpa.repository;

import com.paging.jpa.model.Board;
import org.springframework.data.jpa.repository.JpaRepository;

public interface BoardRepository extends JpaRepository<Board, Long> {
    // 기본 CRUD 메서드와 페이징 처리를 위한 메서드 자동으로 제공
}

BoardService (java)

package com.paging.jpa.service;

import com.paging.jpa.model.Board;
import com.paging.jpa.repository.BoardRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;

@Service
public class BoardService {
    @Autowired
    private BoardRepository boardRepository;

    public Page<Board> getBoards(int page, int size) {
        return boardRepository.findAll(PageRequest.of(page, size));
    }
}

5. 실행 결과 (JSON)

더보기

// 20231104022306
// http://localhost:9898/boards

{
  "content": [
    {
      "id": 1,
      "title": "테스트 1",
      "content": "안녕하세요",
      "createdBy": "StudyMemo",
      "createdAt": "2023-11-02T17:15:43"
    },
    {
      "id": 2,
      "title": "테스트 2",
      "content": "안녕하세요",
      "createdBy": "StudyMemo",
      "createdAt": "2023-11-02T17:15:43"
    },
    {
      "id": 3,
      "title": "테스트 3",
      "content": "안녕하세요",
      "createdBy": "StudyMemo",
      "createdAt": "2023-11-02T17:15:43"
    },
    {
      "id": 4,
      "title": "테스트 4",
      "content": "안녕하세요",
      "createdBy": "StudyMemo",
      "createdAt": "2023-11-02T17:15:43"
    },
    {
      "id": 5,
      "title": "테스트 5",
      "content": "안녕하세요",
      "createdBy": "StudyMemo",
      "createdAt": "2023-11-02T17:15:43"
    },
    {
      "id": 6,
      "title": "테스트 6",
      "content": "안녕하세요",
      "createdBy": "StudyMemo",
      "createdAt": "2023-11-02T17:15:43"
    },
    {
      "id": 7,
      "title": "테스트 7",
      "content": "안녕하세요",
      "createdBy": "StudyMemo",
      "createdAt": "2023-11-02T17:15:43"
    },
    {
      "id": 8,
      "title": "테스트 8",
      "content": "안녕하세요",
      "createdBy": "StudyMemo",
      "createdAt": "2023-11-02T17:15:43"
    },
    {
      "id": 9,
      "title": "테스트 9",
      "content": "안녕하세요",
      "createdBy": "StudyMemo",
      "createdAt": "2023-11-02T17:15:43"
    },
    {
      "id": 10,
      "title": "테스트 10",
      "content": "안녕하세요",
      "createdBy": "StudyMemo",
      "createdAt": "2023-11-02T17:15:43"
    }
  ],
  "pageable": {
    "pageNumber": 0,
    "pageSize": 10,
    "sort": {
      "empty": true,
      "unsorted": true,
      "sorted": false
    },
    "offset": 0,
    "paged": true,
    "unpaged": false
  },
  "last": false,
  "totalPages": 3,
  "totalElements": 21,
  "size": 10,
  "number": 0,
  "sort": {
    "empty": true,
    "unsorted": true,
    "sorted": false
  },
  "first": true,
  "numberOfElements": 10,
  "empty": false
}

반응형