[B -2-19] 마이바티스와 스프링에서의 페이징 처리

2019. 10. 3. 11:36Project B (SPMS)/Project B 파트3

반응형

데이터베이스 대용량 처리 

 

데이터베이스는 시간이 지남에 따라 점점 용량이 거대해져갈 수 밖에 없다.

대용량 데이터에 대한 대비를 한 쿼리문을 고려해야만 한다.

 


데이터베이스 대용량 데이터 준비 

...더보기
-- 재귀복사를 통한 데이터 개수 늘리기
insert into TBL_BOARD (
BNO, TITLE, "CONTENT", WRITER
)
(select SEQ_BOARD.nextval, TITLE, "CONTENT", WRITER 
from TBL_BOARD);

오라클 데이터베이스에 접속해서

재귀복사 쿼리를 약 200,000 건 정도의 데이터삽입이 될 때까지 반복해서 생성한다.

마지막에 commit 으로 데이터를 확정시킨다.

 


페이징 처리를 위해 필요한 파라미터의 기준 (Criteria) 

1. 페이지 번호 (pageNum)

2. 한 페이지 당 출력될 데이터 (amount)

 

src/main/java

com.spms.domain

Criteria.java

 

...더보기
package com.spms.domain;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

@Getter
@Setter
@ToString
public class Criteria {
	private int pageNum;
	private int amount;
	
	public Criteria() {
		this(1,10);
	}
	
	public Criteria(int pageNum, int amount) {
		this.pageNum = pageNum;
		this.amount = amount;
	}
}

Critera()

생성자를 통해 기본값을 1페이지, 10개 글 표시 로 지정한다.

 

Criteria(int pageNum, int amount)

페이지번호글 표시 개수를 받아서 자신의 객체로 보관한다.

 

@Getter

@Setter

롬복을 이용해서 get/set 메소드를 생성한다.

 

@ToString

롬복을 이용해서 ToString 메소드를 생성한다.


Criteria 의 내부 객체값을 이용해서 SQL이 동작하도록 설계한다.

select BNO, TITLE, "CONTENT", WRITER, REGDATE, UPDATEDATE
from (
    select /*+ INDEX_DESC(tbl_board pk_board) */
    rownum RNUM, BNO, TITLE, "CONTENT", WRITER, REGDATE, UPDATEDATE
    from TBL_BOARD
    where rownum <= 페이지번호 * 페이지당 출력 데이터양
)
where RNUM > (페이지번호 - 1) * 페이지당 출력 데이터양;

 


게시판 컨트롤러 수정

 

src/main/java

com.spms.controller

BoardController.java

@GetMapping("/list") list()

 

...더보기
package com.spms.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import com.spms.domain.BoardVO;
import com.spms.domain.Criteria;
import com.spms.service.BoardService;

import lombok.AllArgsConstructor;
import lombok.extern.log4j.Log4j;

@Controller
@Log4j
@RequestMapping("/board/*")
@AllArgsConstructor
public class BoardController {

	private BoardService boardService;
	
	@GetMapping("/list")
	public void list(Criteria cri, Model model) {
		log.info("list" + cri);
		boardService.getList(cri).forEach(board -> log.info(board));
		model.addAttribute("list", boardService.getList(cri));
	}
	
	@GetMapping("/register")
	public void register() {
		
	}
	
	@PostMapping("/register")
	public String register(BoardVO board, RedirectAttributes rttr) {

		log.info("register : " + board);
		boardService.register(board);
		rttr.addFlashAttribute("result", board.getBno());
		return "redirect:/board/list";
	}

	@GetMapping({"/get", "/modify"})
	public void get(@RequestParam("bno") Long bno, Model model) {
		log.info("/get or modify");
		model.addAttribute("board", boardService.get(bno));
	}

	@PostMapping("/modify")
	public String modify(BoardVO board, RedirectAttributes rttr) {
		log.info("modify:" + board);

		if (boardService.modify(board)) {
			rttr.addFlashAttribute("result", "success");
		}
		return "redirect:/board/list";
	}

	@PostMapping("/remove")
	public String remove(@RequestParam("bno") Long bno, RedirectAttributes rttr) {
		log.info("remove..." + bno);
		if (boardService.remove(bno)) {
			rttr.addFlashAttribute("result", "success");
		}
		return "redirect:/board/list";
	}

}

 

Criteria 클래스를 한 개 만들어놓으면 하나의 타입만으로도 파라미터나 리턴 타입을 사용할 수 있기때문에 편리하게 사용할 수 있다.

 


게시판 서비스 수정

 

src/main/java

com.spms.service

BoardService.java 인터페이스

getList()

...더보기
package com.spms.service;

import java.util.List;
import com.spms.domain.BoardVO;
import com.spms.domain.Criteria;

public interface BoardService {
	public List<BoardVO> getList(Criteria cri);
	public void register(BoardVO board);
	public BoardVO get(Long bno);
	public boolean modify(BoardVO board);
	public boolean remove(Long bno);
}

 


게시판 서비스 구현 수정 

 

src/main/java

com.spms.service

BoardServiceImpl.java

getList()

...더보기
package com.spms.service;

import java.util.List;

import org.springframework.stereotype.Service;

import com.spms.domain.BoardVO;
import com.spms.domain.Criteria;
import com.spms.mapper.BoardMapper;

import lombok.AllArgsConstructor;
import lombok.extern.log4j.Log4j;

@Log4j
@Service
@AllArgsConstructor
public class BoardServiceImpl implements BoardService {
	
	private BoardMapper boardMapper;

	@Override
	public List<BoardVO> getList(Criteria cri) {
		// TODO Auto-generated method stub
		log.info("get List with Criteria : " + cri);
		return boardMapper.getListWithPaging(cri);
	}
	
	@Override
	public void register(BoardVO board) {
		log.info("register......" + board);
		boardMapper.insertSelectKey(board);
	}

	@Override
	public BoardVO get(Long bno) {
		log.info("get......" + bno);
		return boardMapper.read(bno);
	}

	@Override
	public boolean modify(BoardVO board) {
		// TODO Auto-generated method stub
		log.info("modify......" + board);
		return boardMapper.update(board) == 1;
	}

	@Override
	public boolean remove(Long bno) {
		log.info("remove...." + bno);
		return boardMapper.delete(bno) == 1;
	}

}

 

Criteria 객체는 전달용도로도 사용된다.


게시판 매퍼 수정

 

src/main/java

com.spms.mapper

BoardMapper.java 인터페이스

getListWithPaging() 

...더보기
package com.spms.mapper;

import java.util.List;
import com.spms.domain.BoardVO;
import com.spms.domain.Criteria;

public interface BoardMapper {
	public List<BoardVO> getListWithPaging(Criteria cri);
	public Long insertSelectKey(BoardVO board);
	public BoardVO read(Long bno);
	public int update(BoardVO board);
	public int delete(Long bno);
}

 


게시판 매퍼 SQL 수정

 

src/main/resources

com

spms

mapper

BoardMapper.xml

getListWithPaging()

 

...더보기
<?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.spms.mapper.BoardMapper">

	<!-- 페이징 목록 조회 -->
	<select id="getListWithPaging" resultType="com.spms.domain.BoardVO">
	<![CDATA[
		select 
			BNO, TITLE, "CONTENT", WRITER, REGDATE, UPDATEDATE
		from (
		    select /*+ INDEX_DESC(tbl_board pk_board) */
		    	rownum RNUM, BNO, TITLE, "CONTENT", WRITER, REGDATE, UPDATEDATE
		    from TBL_BOARD
		    where rownum <= #{pageNum} * #{amount}
		)
		where RNUM > (#{pageNum} - 1) * #{amount}
	]]>
	</select>
		
	<!-- 등록 (선택키 활용) -->
	<insert id="insertSelectKey">
		<selectKey keyProperty="bno" order="BEFORE" resultType="long">
			select SEQ_BOARD.nextval 
			from DUAL
		</selectKey>
		insert into TBL_BOARD (
			BNO, TITLE, CONTENT, WRITER
		)
		values (
			#{bno}, #{title}, #{content}, #{writer}
		)
	</insert>
	
	<!-- 조회 -->
	<select id="read" resultType="com.spms.domain.BoardVO">
		select * 
		from TBL_BOARD 
		where BNO = #{bno}
	</select>
	
	<!-- 수정 -->
	<update id="update">
		update TBL_BOARD set 
				TITLE = #{title},
				CONTENT = #{content},
				WRITER = #{writer},
				UPDATEDATE = SYSDATE
		where BNO = #{bno}
	</update>
	
	<!-- 삭제 -->
	<delete id="delete">
		delete TBL_BOARD
		where BNO = #{bno}
	</delete>
	
</mapper>

 


게시판 컨트롤러 유닛 테스트

 

src/test/java

com.spms.controller

BoardControllerTests.java

testListPaging()

...더보기
package com.spms.controller;


import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;

import lombok.Setter;
import lombok.extern.log4j.Log4j;

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(classes = {
com.spms.config.RootConfig.class,
com.spms.config.ServletConfig.class} )
@Log4j
public class BoardControllerTests {

	@Setter(onMethod_ = { @Autowired })
	private WebApplicationContext ctx;

	private MockMvc mockMvc;

	@Before
	public void setup() {
		this.mockMvc = MockMvcBuilders.webAppContextSetup(ctx).build();
	}
	
	public void testList() throws Exception {

		log.info(
			mockMvc.perform(MockMvcRequestBuilders.get("/board/list")
		).andReturn().getModelAndView().getModelMap());
	}

	public void testRegister() throws Exception {

		String resultPage = mockMvc
				.perform(MockMvcRequestBuilders.post("/board/register")
				.param("title", "테스트 새글 제목")
				.param("content", "테스트 새글 내용")
				.param("writer", "user00"))
				.andReturn().getModelAndView().getViewName();

		log.info(resultPage);

	}
	
	public void testGet() throws Exception{
		log.info(mockMvc.perform(MockMvcRequestBuilders
					.get("/board/get")
					.param("bno", "2")
				).andReturn().getModelAndView().getModelMap()
		);
	}

	public void testModify() throws Exception {
		String resultPage = mockMvc
				.perform(MockMvcRequestBuilders.post("/board/modify")
						.param("bno", "2")
						.param("title", "수정된 테스트 새글 제목")
						.param("content", "수정된 테스트 새글 내용")
						.param("writer", "editor01"))
				.andReturn().getModelAndView().getViewName();

		log.info(resultPage);
	}
	
	public void testRemove() throws Exception {
		// 삭제전 데이터베이스에 게시물 번호 확인할 것
		String resultPage = mockMvc
				.perform(MockMvcRequestBuilders
						.post("/board/remove")
						.param("bno", "9"))
				.andReturn().getModelAndView().getViewName();

		log.info(resultPage);
	}
	
	@Test
	public void testListPaging() throws Exception {
		log.info(mockMvc.perform(MockMvcRequestBuilders.get("/board/list")
								.param("pageNum", "2")
								.param("amount", "10")
								)
			.andReturn().getModelAndView().getModelMap()
		);
	}
	
}

게시판 컨트롤러 유닛 테스트 결과 

 

src/test/java

com.spms.controller

BoardControllerTests.java

testListPaging()

 

...더보기
INFO : com.spms.controller.BoardController - listCriteria(pageNum=2, amount=10)
INFO : com.spms.controller.BoardController - BoardVO(bno=524304, title=게시판 등록 자바스크립트 새창 테스트, content=게시판 등록 내용 테스트입니다., writer=tester02, regdate=Thu Oct 03 10:25:58 JST 2019, updateDate=Thu Oct 03 10:25:58 JST 2019)
INFO : com.spms.controller.BoardController - BoardVO(bno=524303, title=아하하, content=내용, writer=tester01, regdate=Thu Oct 03 10:25:58 JST 2019, updateDate=Thu Oct 03 10:25:58 JST 2019)
INFO : com.spms.controller.BoardController - BoardVO(bno=524302, title=테스트 새글 제목, content=테스트 새글 내용, writer=user00, regdate=Thu Oct 03 10:25:58 JST 2019, updateDate=Thu Oct 03 10:25:58 JST 2019)
INFO : com.spms.controller.BoardController - BoardVO(bno=524301, title=등록 테스트 ㅇㅇ, content=내용 ㅇㅋ, writer=tester03, regdate=Thu Oct 03 10:25:58 JST 2019, updateDate=Thu Oct 03 10:25:58 JST 2019)
INFO : com.spms.controller.BoardController - BoardVO(bno=524300, title=다섯번째 테스트 제목, content=다섯번째 테스트 내용, writer=guest5, regdate=Thu Oct 03 10:25:58 JST 2019, updateDate=Thu Oct 03 10:25:58 JST 2019)
INFO : com.spms.controller.BoardController - BoardVO(bno=524299, title=네번째 테스트 제목., content=네번째 테스트 내용, writer=guest4, regdate=Thu Oct 03 10:25:58 JST 2019, updateDate=Thu Oct 03 10:25:58 JST 2019)
INFO : com.spms.controller.BoardController - BoardVO(bno=524298, title=세번째 테스트 제목, content=세번째 테스트 내용, writer=guest3, regdate=Thu Oct 03 10:25:58 JST 2019, updateDate=Thu Oct 03 10:25:58 JST 2019)
INFO : com.spms.controller.BoardController - BoardVO(bno=524297, title=191003 글 써보기, content=ㅇㅋ, writer=개발자, regdate=Thu Oct 03 10:25:58 JST 2019, updateDate=Thu Oct 03 10:25:58 JST 2019)
INFO : com.spms.controller.BoardController - BoardVO(bno=524296, title=수정된 테스트 새글 제목, content=수정된 테스트 새글 내용, writer=editor01, regdate=Thu Oct 03 10:25:58 JST 2019, updateDate=Thu Oct 03 10:25:58 JST 2019)
INFO : com.spms.controller.BoardController - BoardVO(bno=524295, title=두번째 테스트 제목, content=두번째 테스트 내용, writer=guest2, regdate=Thu Oct 03 10:25:58 JST 2019, updateDate=Thu Oct 03 10:25:58 JST 2019)

 

반응형