2022-04-27

GGAE99·2022년 4월 27일
0

진도

목록 보기
40/43

한달만이라니... 너무 오래 블로그를 안한 것 같다.
오늘 부터 꾸준하게 다시 글을 올려볼 생각이다.
프로젝트를 진행하느라 이론적인 부분을 올릴게 없기도 했고,
사실 이론 진행도 했지만 귀찮은 부분이 너무 컸다ㅋㅋㅋ.
핑계를 대고 한번 안하기 시작하니까 손이 정말 안가더라.
이번에 spring 진행하면서 정리를 다시 해봐야겠다고 생각하고 있었는데,
오늘은 진짜 좀 헷갈리는 내용이 나와서 이 기회에 다시 시작해보려고한다.

오늘 정리할거

  1. 스프링 프로젝트 만들 때 기본 설정
  2. 페이징 처리

1. 스프링 프로젝트 기본 설정

프로젝트 생성
1. Spring Legacy Project 생성 (Spring MVC Project) 선택 -> 프로젝트 이름설정
2. 주소 설정하기 [ex)velog.io.kr]
3. 생성한 프로젝트 우클릭 -> Properties -> Project Facets
4. 본인의 자바 버전에 맞춰서 버전 변경
5. Runtime에서 서버 설정
6. 서버 창을 열어서 path를 사용할 path로 변경

프로젝트 설정
1. pom.xml에서 자바 버전과 스프링 버전 확인
2. WEB-INF에 lib(라이브러리) 폴더 생성 후 jstl.jar 넣어주기
3. index.jsp생성해주기
4. pom.xml에 사용할 라이브러리들 추가 (메이븐 리포지터리에서 찾아서 추가 / mybatis 등)
5. web.xml에서 인코딩 추가 및 appServlet 세팅 (Servlet 받아줄 주소 설정)
6. WEB-INF/spring/appServlet/servlet-context.xml에서 객체 생성
(DB접속 객체, 파일 업로드 객체, Controller,service,dao 객체 등)

mybatis 설정
1. pom.xml에 mybatis 라이브러리 추가
2. servlet-context.xml에서 mybatis 설정용 객체 추가
3. db작업을 수행하는 sqlSessionTemplate객체 추가
4. src/main/resources에 mapper폴더와 mybatis-config.xml을 추가한다.
mybatis-config.xml은 생성시에 미리 설정해둔 confid.dtd 속성으로 생성한다.
(Window > Preferences > XML > XML Catalog > User Specified Entries > Add

  1. mapper 안에 사용할 SQL.xml들을 생성한다.
    이 때 미리 설정해둔 mapper.dtd설정을 넣어서 생성한다.
  2. mapper의 xml파일들의 namespace를 미리 설정해둔다.
<mapper namespace="board">
</mapper>
와 같이 설정한다.

이정도로 정리할 수 있을 것 같다.

2. 페이징 처리

필자가 프로젝트 할 때 페이징 처리가 필요없는 부분들을 맡아서 다뤄볼일이 없었다. 그래서 잘 모른다. 정리 안하면 평생 모르고 살 것 같아서 정리해본다.

1.현재 페이지 지정
가장 먼저 페이징 처리를 위해 현재 페이지 값을 받을 필요가 있다.
int형 reqPage를 선언해 받도록하자.

<h3><a href="/boardList.do?reqPage=1">게시판</a></h3>

게시판을 처음 열때는 현재페이지를 1로 설정해서 받기로했다.

  1. 한 페이지에서 보여줄 데이터를 저장할 VO객체를 생성한다.
public class BoardPageData {
	private ArrayList<Board> list;
	private String pageNavi;
}

현재 페이지에서 보여줄 게시글들을 배열 타입으로 묶어 list라는 변수로 지정하고, 이동할 페이지를 나타내줄 변수를 pageNavi로 지정한다.

3-1. 페이지당 보여줄 데이터 수를 지정하고, 지정된 수 만큼 데이터를 받아오기 위해 값을 보내준다.

한 페이지당 보여줄 게시물 수 : 10
int numPerPage = 10;

한 페이지당 10개씩 게시물을 보여주기 위해 numPerPage를 10으로 선언했다.
reqPage(현재 페이지)가 1인경우 마지막 게시물 번호는 10, 2일경우 마지막 게시물 번호는 20이다.
그러므로 마지막 게시물번호를 reqPage * numPerPage로 지정해준다.

마지막 페이지 번호
int end = reqPage * numPerPage;

첫번째 게시물 번호는 마지막 게시물 번호에서 한페이지당 게시물 수를 빼고 1을 더해준다.

//해당페이지 첫번째 게시물 번호
int start = end-numPerPage + 1;		

계산을 마친 첫번째, 마지막 게시물 번호를 사용해서 게시물 목록을 조회할 수 있도록 값을
HashMap<String, Object> 로 묶어서 데이터베이스에 보내준다.

		HashMap<String, Object> map = new HashMap<String, Object>();
		map.put("start",start);
		map.put("end",end);
		ArrayList<Board> list = dao.selectBoardList(map);

3-2. DB에 연결해서 선택한 페이지 수 만큼 게시글을 받아온다.
먼저 아까 보내준 데이터를 받을 수 있도록 dao 부터 설정해보자.

	public ArrayList<Board> selectBoardList(HashMap<String, Object> map) {
		List list = sqlSession.selectList("board.selectBoardList",map);
		return (ArrayList<Board>)list;
	}

Board타입의 배열을 반환하는 함수이다. sqlSessoion은 SqlSessionTemplate의 객체이다. dao를 생성할 때 미리 생성해둔다.

@Autowired
private SqlSessionTemplate sqlSession;

selectList는 리스트를 받아올때 사용하는 sqlSession의 메소드이다. 첫번째 매개변수는 접속할 mapper의 namespace와 sql문의 아이디를 뜻하고, 두번째 매개변수는 sql문에 보내줄 값을 뜻한다.
미리 설정해준 mapper에 sql문을 넣어준다.

  <select id="selectBoardList" parameterType="map" resultType="b">
	select * from
	(select rownum as rnum, b.* from
	(select 
				board_no as boardNo,
				board_title as boardTitle,
				board_writer as boardWriter,
				board_date as boardDate
	from board order by board_no desc)b)
	where rnum between #{start} and #{end}
  </select>

이 부분이 참 쿼리가 복잡한데,
1. 먼저 order by board_no desc를 사용해서
board테이블을 최신순으로 정렬한다.
2. 이렇게 최신순으로 정렬하는 쿼리문을 b로 지칭하고, rownum을 사용해 정렬되어있는 테이블에 조회순서대로 번호를 매겨준다. 가장 최근에 등록한 요소가 1번을 가지게된다.
1번부터 정렬한다.
왜 이렇게 쿼리를 짜야하는지는 나도 모른다. rownum을 사용할때는 이렇게 쿼리를 묶어서 지칭해주고 사용하더라. 구글링해도 이렇게 사용하라고 예시가 나왔다.
3. 마지막으로 받아온 데이터인 map에 저장되어있는 start와 end를 사용해서 페이지의 첫번째 요소부터 마지막 요소까지 받아오도록 where절을 써준다.
// 예를들어 reqPage(현재 페이지) = 1 이라면 start는 10-10+1 해서 1이고, end 는 1*10해서 10이된다. 그러면 조회하는 게시글은 rownum 기준 1~10번 사이의 게시글이된다.
4. 마지막으로 DB에서 받아온 값을 내보내는 타입을 정해준다.
그 코드가 resultType="b"이다. b 는 현재 Board객체를 뜻하고 있는데, 그냥 b로 사용할 수 있는 이유는 mybatis-config.xml에서 미리 Board객체를 b로 지정해놨기 때문이다.

<typeAliases>
	<typeAlias type="board.model.vo.Board" alias="b"/>
</typeAliases>

위와 같은 코드를 config에 넣어서 Board객체를 b로 지정해서 사용할 수 있다.
마지막으로 받아온 DB에서 받아온 리스트를 변수에 저장해준다. 아까 쓴 코드이다.

ArrayList<Board> list = dao.selectBoardList(map);
list에 조회결과를 저장
  1. 페이지 이동
    아까 이동할 페이지를 지정하는 변수 pageNavi가 있었다.
    거기에 html 태그들을 넣어 누르면 페이지를 이동할 수 있도록 만들어줄 것 이다.
  • 먼저 전체 페이지 수를 계산하고 시작해야한다. 그래야지 어느 페이지에서 더이상 번호를 넘기는 것을 멈출 수 있는지 정할 수 있다. 전체 페이지 수를 DB에서 꺼내오자
//전체 게시물 수
int totalCount = dao.selectBoardCount();

totalCount라는 변수에 전체 게시물 수를 저장해두었다. 별로 어렵지 않은 내용이니 코드만 넣어놓고 다음 내용을 정리해보도록 그러도록 하도록 하겠다!

  <select id="selectTotalCount" resultType="int">
  	select count(*) from board
  </select>

구해온 전체 페이지 수를 이용햐, 필요한 페이지 수를 계산한다.

//구해온 전체 게시물 수를 통해 전체 페이지 수 계산
	//전체 페이지 수를 0으로 초기화하고 시작한다.
    int totalPage = 0;
	if(totalCount%numPerPage==0) { //총 게시글 수 / 한페이지당 게시글 수 == 0 일때
		totalPage = totalCount/numPerPage; 
        // 총 페이지 수 = 총 게시글 수 / 한페이지당 게시글 수
	}else { 총 게시글 수 / 한페이지당 게시글 수 == 0 이 아닐때
		totalPage = totalCount/numPerPage + 1; 
        //총 페이지 수 = 총 게시글 수 / 한페이지당 게시글 수 + 1
	}

위와 같은 조건을 사용해서 필요한 총 페이지 수를 구해준다.

  • 다음으로 페이지 네비의 길이를 설정해야한다. 임의로 5로 설정하도록 하자.
//페이지네비 길이
int pageNaviSize = 5;
  • 현재 페이지 에서 보여줄 페이징 넘버들을 설정해보자.
		int pageNo=1;
		//페이지네비 시작번호
		if(reqPage>3) {
			pageNo = reqPage - 2;			
		}

pageNo를 1로 설정해두고, 만약에 현재 페이지가 3페이지 이상이면 pageNo를 현재 페이지 - 2로 설정해준다. 이러는 이유는 페이지네비의 길이가 5이기 때문에, 그 중간 지점인 3을 넘아가면 (2~6)번을 페이징 번호로 띄워주기 위함이다. 즉 pageNo는 현재 페이지에서 보여지는 첫번째 페이징 넘버라고 생각하면 편할 것 이다.

  • 다음으로 페이지네비 생성을 시작해보자.
//pageNavi 생성 시작
String pageNavi = "";

pageNavi는 html코드를 넣어줄 것 이기 때문에 비어있는 String으로 시작한다.

//이전버튼
if(pageNo != 1) {
	pageNavi += "<a href='/boardList.do?reqPage="+(reqPage-1)+"'>[이전]</a>";
}

1페이지가 페이지의 처음인 경우에는 이전 버튼이 필요 없으므로 pageNo가 1이 아닌 경우부터 이전버튼을 만들어주도록 설정한다.
이전 버튼을 클릭하면 현재 페이지 - 1 의 페이지로 넘어갈 수 있도록 값을 넘겨준다.
조건부로 이전 버튼을 넣었으니 다음은 페이징 넘버를 넣어보자.

//페이지 숫자 생성
for(int i=0;i<pageNaviSize;i++) { //페이지 네비의 길이를 5로 설정했으므로 5번 반복
	if(pageNo == reqPage) { // 현재 페이지와 페이징 넘버가 같을 경우는 선택할 수 없도록 설정
		pageNavi +="<span>"+pageNo+"</span>";
	}else { // 이외에는 pageNo를 현재 페이지 값으로 받도록 설정해서 서블릿으로 넘겨줌
		pageNavi += "<a href='/boardList.kh?reqPage="+pageNo+"'>"+pageNo+"</a>";
	}
	pageNo++; //pageNo를 1씩 올려가면서 총 5번 실행
	if(pageNo>totalPage) { //만약 올려준 pageNo가 총 페이지 수 보다 높다면 for문 중지
		break;
	}
}

이전 버튼, 페이징 넘버를 다 넣어줬으니 다음 버튼을 넣어보자.

//다음버튼
if(pageNo<=totalPage) {
	pageNavi += "<a href='/boardList.kh?reqPage="+(reqPage+1)+"'>[다음]</a>";
}

pageNo가 총 페이지 수보다 작거나 같을때까지는 계속해서 현재 페이지에서 1 큰 페이지로 넘어갈 수 있는 버튼을 만들어주도록 설정했다.

  1. 리스트와 페이징 네비를 받아서 출력
    마지막으로 게시슬 리스트와 페이징 네비를 받아서 출력하기만 하면 끝이다.
    일단 컨트롤러에 값을 다시 보내주자.
BoardPageData bdp = new BoardPageData(list, pageNavi);
return bdp;

이러면 아까 생성해놨던 리스트와 페이지네비가 들어가는 객체를 컨트롤러에 반환해준다.

public String boardList(int reqPage, Model model) {
	BoardPageData bdp = service.selectBoardLit(reqPage);
	model.addAttribute("list", bdp.getList()); // 게시글 리스트 보내기
	model.addAttribute("pageNavi", bdp.getPageNavi()); // 페이지 네비 보내기
	model.addAttribute("reqPage", reqPage); // 현재 페이지 보내기
	return "board/boardList";
}

Model(org.springframework.ui.Model;)를 사용해서 띄워줄 페이지에 리스트와 페이지네비, 그리고 현재 페이지를 보내준다.

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h1>게시판</h1>
	<hr>
	<c:if test="${not empty sessionScope.m }">
		<a href="/boardWriteFrm.do">게시글 작성</a>
	</c:if>
	<table border="1">
			<tr>
			<th>번호</th><th>제목</th><th>작성자</th><th>작성일</th>
			<c:forEach items="${list }" var="b" varStatus="i">
			<tr>
				<td>${(reqPage-1)*10 + i.count }</td>
				<td><a href="/boardView.do?boardNo=${b.boardNo }">${b.boardTitle }</a></td>
				<td>${b.boardWriter }</td>
				<td>${b.boardDate }</td>
			</tr>
			</c:forEach>
			<tr>
				<th colspan="4">${pageNavi }</th>
			</tr>
	</table>
</body>
</html>

게시글 목록을 띄워주는 페이지의 코드이다.
번호,제목,작성자,작성일 순서로 띄워주고, 받아온 리스트는
(현재 페이지 수 - 1)*10 + (반복 횟수)
의 공식을 사용해 번호를 매겨주었다.
마지막으로 열심히 설정해둔 pageNavi를 글의 하단에 넣어주면 끝이다.

쓰는데 얼마 안걸리는 것 처럼 보이지만 이해하면서 쉽게 전달하는게 꽤 힘들었다...
내일 다시 와야겠다! 안뇽!

0개의 댓글