예외처리
1. CommonExceptionAdvice.java --> controller에
package org.zerock.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
//@ControllerAdvice //이 클래스가 객체가 컨트롤러에서 발생하는 Exception을 전문적으로 처리하는 클래스(프로젝트 젤 마지막에 넣을 것!)
public class CommonExceptionAdvice {
private static final Logger logger = LoggerFactory.getLogger(CommonExceptionAdvice.class);
@ExceptionHandler(Exception.class)
public String common(Exception e) { //common() 메소드를 이용해서 Exception 타입으로 처리되는 모든 예외를 처리하도록 설정된다.
logger.info("common()......에러처리 부분...");
logger.info(e.toString());
return "/error_common"; // 절대경로로 forward
//http://localhost:8080/board/read?bno=1634 (잘못된 값으로 테스트 확인)
// 주소는 그대로지만 error_common.jsp 를 보여줌
}
}
2. error_common.jsp --> view에
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<center>
공사중입니다. <br>
잘못된 경로로 들어왔습니다.
</center>
</body>
</html>
페이징 처리
ㄴ> limit 두 변수 없이 page 변수 하나를 계속 전달
1. 변수처리
1) BoardDAO.java --> 한줄 추가
public List<BoardVO> listPage(int page) throws Exception; // 페이징
2) BoardDAOImpl.java --> 추가
@Override //추가
public List<BoardVO> listPage(int page) throws Exception {
if(page <= 0) {
page = 1;
}
page = (page - 1) * 10; //limit 첫번째 항목
return session.selectList(namespace+".listPage", page);
}
3) boardMapper.xml --> 추가
<select id="listPage" resultType="BoardVO">
<!-- resultType="BoardVO" 줄여서 사용할 수 있는 이유 -->
<!-- mybatis-config.xml에서 <typeAliases> 추가 했기 때문이다. -->
<![CDATA[
select * from tbl_board where bno > 0 order by bno desc, regdate desc limit #{page}, 10
]]>
</select>
4) BoardDAOTest.java ( 테스트 )
@Test //페이징 테스트
public void testListPage() throws Exception {
int page = 1;
List<BoardVO> list = dao.listPage(page);
for (BoardVO boardVO : list) {
logger.info(boardVO.getBno() + ":" + boardVO.getTitle());
}
}
2. 객체 처리
ㄴ> Criteria 클래스 생성 --> 페이징 limit 담당
1) Criteria.java --> domain에
package org.zerock.domain;
public class Criteria {
private int page; // limit ?,0에 해당(첫번째 변수)
private int perPageNum; // limit 0,? 에 해당(두번째 변수)
// 초기화
public Criteria() { //첫페이지 실행시 적용될 값들 (기본 생성자)
this.page = 1; //첫 페이지 초기화
this.perPageNum = 10; //한 페이지당 출력 할 게시물 수
}
// set,get page
public void setPage(int page) { // get 방식으로 페이지 값이 초기화 안되어있다면
if(page <= 0) {
this.page = 1;
return;
}
this.page = page; // get 방식으로 넘어온 값을 전역변수에 전달
}
public int getPage() {
return page;
}
// perPageNum set,get
//Mybatis SQL mapper -
//sql 구문에서 limit ?,페이지당 출력 수 설정
public void setPerPageNum(int perPageNum) {
if(perPageNum <= 0) {
this.perPageNum = 10;
return;
}
this.perPageNum = perPageNum;
}
public int getPerPageNum() {
return perPageNum;
}
// limit 시작 값 ( 메서드 처리 ) 계산해서 get만 출력(set 없어도됨)
public int getPageStart() {
return (this.page - 1) * this.perPageNum;
}
@Override
public String toString() {
return "Criteria [page=" + page + ", perPageNum=" + perPageNum + "]";
}
}
2) BoardDAO.java
public List<BoardVO> listCriteria(Criteria cri) throws Exception;
3) BoardDAOImpl.java
@Override // criteria 객체 페이징
public List<BoardVO> listCriteria(Criteria cri) throws Exception {
return session.selectList(namespace+".listCriteria", cri);
}
4) boardMapper.xml
<select id="listCriteria" resultType="BoardVO">
<![CDATA[
select * from tbl_board where bno > 0 order by bno desc limit #{pageStart}, #{perPageNum}
]]>
</select>
5) BoardDAOTest.java
@Test
public void testListCriteria() throws Exception {
Criteria cri = new Criteria();
cri.setPage(2); //출력할 페이지
cri.setPerPageNum(2); //출력할 게시물 수
logger.info(cri.toString());
List<BoardVO> list = dao.listCriteria(cri);
for (BoardVO boardVO : list) { // 향상된 for문 형식
logger.info("cri test=="+boardVO.getBno() + ":" + boardVO.getTitle());
}
}
6) BoardService.java
public List<BoardVO> listCriteria(Criteria cri) throws Exception;
7) BoardServiceImpl.java
@Override
public List<BoardVO> listCriteria(Criteria cri) throws Exception {
return dao.listCriteria(cri);
}
8) BoardController.java
@RequestMapping(value = "/listCri", method = RequestMethod.GET)
public void listCri(Criteria cri, Model model) throws Exception {
logger.info("show list Page with Criteria......................");
model.addAttribute("list", service.listCriteria(cri));
}
9) header.jsp
<a href="/board/listCri">[listCri]</a>
10) listCri.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ include file="/WEB-INF/views/include/header.jsp" %>
<script>
var result = "${msg}";
if(result == "register"){ // alert 뜬 후 새로고침하면 없어지므로 다시 뜨진 않음
alert("작성 완료!");
}else if(result == "delete"){
alert("삭제 완료!");
}else if(result == "modify"){
alert("수정 완료!");
}
</script>
<center>
<h3>LIST PAGE</h3>
<table border=1 width=700>
<tr>
<th style="width:10px">BNO</th>
<th>TITLE</th>
<th>WRITER</th>
<th>REGDATE</th>
<th style="width: 40px">VIEWCNT</th>
</tr>
<c:forEach var="boardVO" items="${list}">
<tr>
<td>${boardVO.bno }</td>
<td><a href="/board/read?bno=${boardVO.bno }">${boardVO.title }</a></td>
<td>${boardVO.writer }</td>
<!-- <td>${boardVO.regdate }</td> -->
<td><fmt:formatDate pattern="yyyy-MM-dd HH:mm:ss" value="${boardVO.regdate }"/></td>
<td>${boardVO.viewcnt }</td>
</tr>
</c:forEach>
</table>
<br>
<table border=0 width=700>
<tr>
<td align=right><a href="register">[글쓰기]</a></td>
</tr>
</table>
</center>
<%@ include file="/WEB-INF/views/include/footer.jsp" %>
3. pageMaker --> domain에
ㄴ> 페이징 블럭 담당
1) PageMaker.java
package org.zerock.domain;
import lombok.Data;
@Data
public class PageMaker {
private int totalCount; // 총 게시물 수
private int startPage; // 시작 페이지
private int endPage; // 끝 페이지
private boolean prev; // 이전 링크
private boolean next; // 다음 링크
private int displayPageNum = 5; //블럭 갯수
private Criteria cri; // limit 메소드 이용
private void calcData() {
endPage = (int) (Math.ceil(cri.getPage() / (double) displayPageNum) * displayPageNum);
//endPage = 현재 페이지 번호 / 블럭 개수 * 블럭 개수
// Math.ceil --> 0보다 크다면 올림 함 (0.3이라면 1로)
//현재 페이지가 3 : Math.ceil(3/10) * 10 = 10
//현재 페이지가 1 : Math.ceil(1/10) * 10 = 10
//현재 페이지가 20 : Math.ceil(20/10) * 10 = 20
//현재 페이지가 21 : Math.ceil(21/10) * 10 = 30
startPage = (endPage - displayPageNum) + 1;
//현재 페이지가 21 : startPage = (30 - 10) + 1 = 21
// 마지막 블럭일 경우 계산 처리
int tempEndPage = (int) (Math.ceil(totalCount / (double) cri.getPerPageNum()));
if (endPage > tempEndPage) {
endPage = tempEndPage;
}
prev = startPage == 1 ? false : true; //시작 페이지가 1이 아니라면 true
next = endPage * cri.getPerPageNum() >= totalCount ? false : true;
//endPage = 10 , perPageNum = 10 , totalCount = 101 이라면 next = true 되어야 한다.
}
public void setTotalCount(int totalCount) {
this.totalCount = totalCount;
//위 메소드 호출
calcData();
}
}
2) BoardController.java
@RequestMapping(value = "/listPage", method = RequestMethod.GET)
public void listPage(@ModelAttribute("cri") Criteria cri, Model model) throws Exception {
logger.info(cri.toString());
model.addAttribute("list", service.listCriteria(cri)); //현재 페이지 리스트 출력 내용
PageMaker pageMaker = new PageMaker();
pageMaker.setCri(cri);
pageMaker.setTotalCount(131); //임의로 131개로 데이터 입력 테스트
model.addAttribute("pageMaker", pageMaker); //현재 페이지에 해당하는 페이징 값들
}
3) listPage.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ include file="/WEB-INF/views/include/header.jsp" %>
<script>
var result = "${msg}";
if(result == "register"){ // alert 뜬 후 새로고침하면 없어지므로 다시 뜨진 않음
alert("작성 완료!");
}else if(result == "delete"){
alert("삭제 완료!");
}else if(result == "modify"){
alert("수정 완료!");
}
</script>
<center>
<h3>LIST PAGE</h3>
<table border=1 width=700>
<tr>
<th style="width:10px">BNO</th>
<th>TITLE</th>
<th>WRITER</th>
<th>REGDATE</th>
<th style="width: 40px">VIEWCNT</th>
</tr>
<c:forEach var="boardVO" items="${list}">
<tr>
<td>${boardVO.bno }</td>
<td><a href="/board/readPage?bno=${boardVO.bno }&page=${pageMaker.cri.page}">${boardVO.title }</a></td> <!-- pageMaker.cri.page or cri.page -->
<td>${boardVO.writer }</td>
<!-- <td>${boardVO.regdate }</td> -->
<td><fmt:formatDate pattern="yyyy-MM-dd HH:mm:ss" value="${boardVO.regdate }"/></td>
<td>${boardVO.viewcnt }</td>
</tr>
</c:forEach>
</table>
<br>
<table border=0 width=700>
<tr>
<td align=right><a href="register">[글쓰기]</a></td>
</tr>
</table>
<!-- 페이징 추가 -->
<table border=1 width=200 align=center>
<tr>
<c:if test="${pageMaker.prev}">
<td><a href="listPage?page=${pageMaker.startPage - 1 }">«</a></td>
</c:if>
<c:forEach var="idx" begin="${pageMaker.startPage }" end="${pageMaker.endPage }">
<td>
<c:if test="${pageMaker.cri.page == idx}"><b></c:if>
<a href="listPage?page=${idx}">${idx}</a>
<c:if test="${pageMaker.cri.page == idx}"></b></c:if>
</td>
</c:forEach>
<c:if test="${pageMaker.next && pageMaker.endPage > 0}">
<td><a href="listPage?page=${pageMaker.endPage +1 }">»</a></td>
</c:if>
</tr>
</table>
</center>
<%@ include file="/WEB-INF/views/include/footer.jsp" %>
4) header.jsp
<a href="/board/listPage">[listPage]</a>
perPageNum = 10 , totalCount = 122 , displayPageNum = 10(블럭)
ㄴ> 122개를 10개씩 보여준다 총 13페이지
< 1~10 >
< 11~13 >
. page = 3 일 경우
- startPage = 1 , endPage = 10 , next = true , prev = false // 첫번째 블럭이므로 prev( < )는 false
. page = 10 일 경우
- startPage = 1 , endPage = 10 , next = true , prev = false // 첫번째 블럭이므로 prev( < )는 false
. page = 11 일 경우
- startPage = 11 , endPage = 20 , next = false , prev = true // 두번째 블럭이므로 next( > )는 false
4. 총게시물수
1) BoardDAO.java
public int countPaging(Criteria cri) throws Exception;
2) BoardDAOImpl.java
@Override
public int countPaging(Criteria cri) throws Exception {
return session.selectOne(namespace+".countPaging", cri);
}
3) boardMapper.xml
<select id="countPaging" resultType="int">
<![CDATA[
select count(bno) from tbl_board where bno > 0
]]>
</select>
4) BoardService.java
public int listCountCriteria(Criteria cri) throws Exception;
5) BoardServiceImpl.java
@Override
public int listCountCriteria(Criteria cri) throws Exception {
return dao.countPaging(cri);
}
6) BoardController.java --> value="/listPage" 에 추가
//pageMaker.setTotalCount(131);
pageMaker.setTotalCount(service.listCountCriteria(cri)); //총 게시물 수
7) readPage.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ include file="/WEB-INF/views/include/header.jsp" %>
<center>
<h3>READ PAGE</h3>
<table border=1 width=570>
<tr>
<td width=70>제목</td>
<td width=500>${boardVO.title }</td>
</tr>
<tr>
<td>내용</td>
<td>${boardVO.content }</td>
</tr>
<tr>
<td>작성자</td>
<td>${boardVO.writer }</td>
</tr>
</table>
<br>
<table border=0 width=570>
<tr>
<td width=50%><a href="listPage?&page=${param.page}">[리스트]</a></td>
<td width=50% align="right">
<a href="/board/modifyPage?bno=${boardVO.bno }&page=${param.page}">[수정]</a> <!-- pageMaker.cri.page or 주소창에 이미 불러와있으므로 param.page도 가능 -->
<a href="/board/removePage?bno=${boardVO.bno }">[삭제]</a>
</td>
</tr>
</table>
<!-- ajax 이용 -->
<form role="pkt" name="pkt" method="get">
<input type="hidden" name="bno" value="${boardVO.bno }">
</form>
<button class="btn-modify">수정</button>
<button class="btn-delete">삭제</button>
<button class="btn-list">리스트</button>
</center>
<%@ include file="/WEB-INF/views/include/footer.jsp" %>
8) modifyPage.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ include file="/WEB-INF/views/include/header.jsp" %>
<center>
<h3>MODIFY PAGE</h3>
<form role="pkt" name="pkt" method="post">
<input type="hidden" name="bno" value="${boardVO.bno}">
<input type="hidden" name="page" value="${param.page}">
<table>
<tr>
<td>제목</td>
<td><input name="title" value="${boardVO.title}"></td>
</tr>
<tr>
<td>내용</td>
<td><textarea name="content" rows="3">${boardVO.content}</textarea></td>
</tr>
<tr>
<td>작성자</td>
<td><input name="writer" value="${boardVO.writer}" readonly></td>
</tr>
<tr>
<td></td>
<td><button type="submit">Submit</button></td>
</tr>
</table>
</form>
</center>
<%@ include file="/WEB-INF/views/include/footer.jsp" %>
5. UriComponentsBuilder 이용
함수처리
주소?변수=값&변수=값
대신 메소드 처리
1) BoardDAOTest.java --> 추가
//@Test
public void testURI() throws Exception {
UriComponents uriComponents = UriComponentsBuilder.newInstance()
.path("/board/read") // 경로
.queryParam("bno", 12) //변수전달
.queryParam("perPageNum", 10)
.build();
//logger.info("/board/read?bno=12&perPageNum=10");
//logger.info(uriComponents.toString());
}
// UriComponents 클래스는 path나 query에 해당하는 문자열들을 추가해서 원하는 URI를 생성할 때 사용한다.
// 위 코드의 실행 결과는 아래와 같이 동일하게 보여진다.
// INFO : org.zerock.controller.BoardDAOTest - /board/read?bno=12&perPageNum=10
// 원하는 데이터를 계속 추가해서 처리할 수 있고, 필요한 데이터를 설정한다.
// 위의 코드에서 queryParam()의 경우 나중에 GET방식의 ? 뒤에 붙는 데이터가 되는 것을 볼 수 있다.
@Test
public void testURI2() throws Exception {
UriComponents uriComponents = UriComponentsBuilder.newInstance()
.path("/{module}/{page}")
.queryParam("bno", 12)
.queryParam("perPageNum", 10)
.build()
.expand("board", "read") // path 변수에 들어갈 녀석들
.encode();
logger.info("/board/read?bno=12&perPageNum=10");
logger.info(uriComponents.toString());
}
// 위와 같이 미리 필요한 경로를 지정해 두고 {module}와 같은 경로를 'board'로 {page}를 'read'로 변경할 수 있다.
2) Pagemaker.java --> 추가
// get방식 - url 주소 변수 값 - 처리 용이하게..
public String makeQuery(int page) {
UriComponents uriComponents = UriComponentsBuilder.newInstance()
.queryParam("page", page)
.queryParam("perPageNum", cri.getPerPageNum())
.build();
return uriComponents.toUriString();
}
3) listPage.jsp --> 추가
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ include file="/WEB-INF/views/include/header.jsp" %>
<script>
var result = "${msg}";
if(result == "register"){ // alert 뜬 후 새로고침하면 없어지므로 다시 뜨진 않음
alert("작성 완료!");
}else if(result == "delete"){
alert("삭제 완료!");
}else if(result == "modify"){
alert("수정 완료!");
}
</script>
<center>
<h3>LIST PAGE</h3>
<table border=0 width=700>
<tr>
<td>Total : ${pageMaker.totalCount }</td>
</tr>
</table>
<table border=1 width=700>
<tr>
<th style="width:10px">BNO</th>
<th>TITLE</th>
<th>WRITER</th>
<th>REGDATE</th>
<th style="width: 40px">VIEWCNT</th>
</tr>
<c:forEach var="boardVO" items="${list}">
<tr>
<td>${boardVO.bno }</td>
<td> <!-- pageMaker.cri.page or cri.page -->
<%-- <a href="/board/readPage?bno=${boardVO.bno }&page=${pageMaker.cri.page}">${boardVO.title }</a> --%>
<a href="/board/readPage${pageMaker.makeQuery(pageMaker.cri.page)}&bno=${boardVO.bno }">${boardVO.title }</a> <!-- UriComponentsBuilder 이용한다면 -->
</td>
<td>${boardVO.writer }</td>
<!-- <td>${boardVO.regdate }</td> -->
<td><fmt:formatDate pattern="yyyy-MM-dd HH:mm:ss" value="${boardVO.regdate }"/></td>
<td>${boardVO.viewcnt }</td>
</tr>
</c:forEach>
</table>
<br>
<table border=0 width=700>
<tr>
<td align=right><a href="register">[글쓰기]</a></td>
</tr>
</table>
<!-- 페이징 추가 -->
<table border=1 align=center>
<tr>
<c:if test="${pageMaker.prev}">
<td>
<%-- <a href="listPage?page=${pageMaker.startPage - 1 }">«</a> --%>
<a href="listPage${pageMaker.makeQuery(pageMaker.startPage - 1)}">«</a>
</td>
</c:if>
<c:forEach var="idx" begin="${pageMaker.startPage }" end="${pageMaker.endPage }">
<td>
<c:if test="${pageMaker.cri.page == idx}"><b></c:if>
<a href="listPage${pageMaker.makeQuery(idx)}">${idx}</a> <!-- <a href="listPage?page=${idx}">${idx}</a> -->
<c:if test="${pageMaker.cri.page == idx}"></b></c:if>
</td>
</c:forEach>
<c:if test="${pageMaker.next && pageMaker.endPage > 0}">
<td>
<%-- <a href="listPage?page=${pageMaker.endPage +1 }">»</a> --%>
<a href="listPage${pageMaker.makeQuery(pageMaker.endPage +1)}">»</a>
</td>
</c:if>
</tr>
</table>
</center>
<%@ include file="/WEB-INF/views/include/footer.jsp" %>
4) BoardController.java --> 추가
Criteria cri 로 해도 됨 (cri 로 사용 안할 거라면!! )
ㄴ> readPage.jsp 에서 <a href="/board/modifyPage${pageMaker.makeQuery(cri.page)}&bno=${boardVO.bno }"> 와 같이 pageMaker 없애고 cri.page로 사용하면 됨
@RequestMapping(value = "/readPage", method = RequestMethod.GET) // pageMaker 사용하기 위해 cri 추가
public void readPage(@RequestParam("bno") int bno, @ModelAttribute("cri") Criteria cri, Model model) throws Exception {
logger.info("readPage get ...........");
PageMaker pageMaker = new PageMaker();
pageMaker.setCri(cri);
model.addAttribute("pageMaker", pageMaker); // forward
model.addAttribute(service.read(bno));
}
5) readPage.jsp --> 추가
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ include file="/WEB-INF/views/include/header.jsp" %>
<center>
<h3>READ PAGE</h3>
<table border=1 width=570>
<tr>
<td width=70>제목</td>
<td width=500>${boardVO.title }</td>
</tr>
<tr>
<td>내용</td>
<td>${boardVO.content }</td>
</tr>
<tr>
<td>작성자</td>
<td>${boardVO.writer }</td>
</tr>
</table>
<br>
<table border=0 width=570>
<tr>
<td width=50%>
<%-- <a href="listPage?&page=${param.page}">[리스트]</a> --%>
<a href="listPage${pageMaker.makeQuery(pageMaker.cri.page)}">[리스트]</a>
</td>
<td width=50% align="right">
<%-- <a href="/board/modifyPage?bno=${boardVO.bno }&page=${param.page}">[수정]</a> --%> <!-- pageMaker.cri.page or 주소창에 이미 불러와있으므로 param.page도 가능 -->
<a href="/board/modifyPage${pageMaker.makeQuery(pageMaker.cri.page)}&bno=${boardVO.bno }">수정</a>
<a href="/board/removePage?bno=${boardVO.bno }">[삭제]</a>
</td>
</tr>
</table>
<!-- ajax 이용 -->
<form role="pkt" name="pkt" method="get">
<input type="hidden" name="bno" value="${boardVO.bno }">
</form>
<button class="btn-modify">수정</button>
<button class="btn-delete">삭제</button>
<button class="btn-list">리스트</button>
</center>
<%@ include file="/WEB-INF/views/include/footer.jsp" %>
'JAVA > spring' 카테고리의 다른 글
스프링 member 구현 (0) | 2023.05.03 |
---|---|
스프링 Board 구현_넘버링, 검색 (0) | 2023.05.03 |
스프링 Board 구현 (0) | 2023.04.28 |
스프링 페이지 이동(변수 전달) (0) | 2023.04.28 |
스프링 프로젝트 생성 (0) | 2023.04.27 |