블로그에선 프로젝트 파일 트리 위쪽에서 아래쪽 순서로 기록함(프로그램 작성순서 아님)

- sql
- 게시판 테이블
DROP TABLE BOARD_PAGING;
CREATE TABLE BOARD_PAGING (
BNO NUMBER(10),
TITLE VARCHAR2(500) NOT NULL,
CONTENT VARCHAR2(4000) NOT NULL,
WRITER VARCHAR2(100) NOT NULL,
WRITEDATE DATE DEFAULT SYSDATE,
CONSTRAINT PK_BOARD PRIMARY KEY(BNO)
);
DROP SEQUENCE BNO_PAGING_SEQ;
CREATE SEQUENCE BNO_PAGING_SEQ;
COMMIT;
SELECT * FROM BOARD_PAGING;
- 게시판 데이터 삽입 sql
DECLARE
I INT;
BEGIN
FOR I IN 1 .. 412
LOOP
INSERT INTO BOARD_PAGING(BNO, TITLE, CONTENT, WRITER)
VALUES(BNO_PAGING_SEQ.NEXTVAL, '제목임.'||I, '내용임.'||I, '관리자');
END LOOP;
END;
- pom.xml
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.22.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.22.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.2.22.RELEASE</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jdbc</artifactId>
<version>10.1.4</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc6</artifactId>
<version>11.2.0.4</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>
- src/main/java
- com.jafa.config 패키지 RootConfig, ServletConfig, WebConfig 클래스 생성
- RootConfig
package com.jafa.config;
import org.apache.tomcat.jdbc.pool.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RootConfig {
@Bean
public DataSource dataSource() {
DataSource dataSource = new DataSource();
dataSource.setDriverClassName("oracle.jdbc.driver.OracleDriver");
dataSource.setUrl("jdbc:oracle:thin:@localhost:1521:XE");
dataSource.setUsername("springdb");
dataSource.setPassword("1234");
return dataSource;
}
}
- ServletConfig
package com.jafa.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
@EnableWebMvc
@ComponentScan("com.jafa")
public class ServletConfig implements WebMvcConfigurer {
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.jsp("/WEB-INF/views/", ".jsp");
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**")
.addResourceLocations("/resources/");
}
}
- WebConfig
package com.jafa.config;
import javax.servlet.Filter;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class WebConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] {RootConfig.class};
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] {ServletConfig.class};
}
@Override
protected String[] getServletMappings() {
return new String[] {"/"};
}
@Override
protected Filter[] getServletFilters() {
CharacterEncodingFilter filter = new CharacterEncodingFilter();
filter.setEncoding("utf-8");
filter.setForceEncoding(true);
return new Filter[] {filter};
}
}
- com.jafa.domain 패키지 BoardVO, Criteria, Pagination 클래스 생성
- BoardVO
package com.jafa.domain;
import java.sql.Date;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class BoardVO {
private Long bno;
private String title;
private String content;
private String writer;
private Date writeDate;
}
- Criteria
package com.jafa.domain;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class Criteria {
private int pageNum; // 현재 페이지
private int amount = 10; // 한페이지에 나타낼 게시물수(10)
public Criteria() {
this(1, 10); // 1페이지 10개씩 페이징
}
}
- Pagination
package com.jafa.domain;
import lombok.Getter;
@Getter
public class Pagination {
Criteria criteria;
private int startPage; // 시작 페이지 버튼 번호
private int endPage; // 마지막 페이지 버튼 번호
private int tempEndPage; // 실제 마지막 페이지 버튼 번호
private int totalCount; // 총 게시물 수
private int displayPageNum = 10; // 화면에 보여질 페이지 버튼 수
private boolean prev; // 이전페이지 활성화여부
private boolean next; // 다음페이지 활성화여부
public Pagination(Criteria criteria, int totalCount) {
this.criteria = criteria;
this.totalCount = totalCount;
int pageNum = criteria.getPageNum();
// 올림(pageNum / displayPageNum) * displayPageNum
endPage = (int) Math.ceil(pageNum / (double)displayPageNum) * displayPageNum;
startPage = endPage - displayPageNum + 1;
tempEndPage = (int) Math.ceil(totalCount / (double)criteria.getAmount());
System.out.println("끝 페이지 : " + endPage);
System.out.println("마지막 페이지 : " + tempEndPage);
prev = startPage != 1;
next = endPage < tempEndPage;
if(endPage > tempEndPage) endPage = tempEndPage;
}
/*
displayPageNum = 10
1~10 : [1][2]...[9][10]
endPage = 10
startPage = 10 - 10 + 1
11~20 : [11][12]...[19][20]
endPage = 20
startPage = 20 - 10 + 1
21~30 : [21][22]...[29][30]
endPage = 30
startPage = 30(endPage) - 10(displayPageNum) + 1
올림(페이지번호/버튼수) * 10
*/
}
/*
displayPageNum = 10 // 화면에 보여질 페이지 버튼 수
totalCount = 412 // 총 게시물 수
1~10 페이지 :
[1][2][3][4][5]....[9][10][다음페이지]
startPage = [1]
endPage = [10]
prev = false
next = true
11~20 페이지 :
[이전페이지][11][12][13][14][15]....[19][20][다음페이지]
startPage = [11]
endPage = [20]
prev = true
next = true
41~50 페이지 :
[이전페이지][41][42][43][44][415]....[49][50][다음페이지]
startPage = [41]
endPage = [50]
prev = true
next = true
게시물 수 : 412
페이징 처리 수 : 10
실제 보여질 페이지
[이전페이지][41][42]
startPage = [41]
endPage = 올림(총게시물수/페이징처리수)
prev = true
next = false
*/
- com.jafa.controller 패키지 BoardController, HomeController 클래스 생성
- BoardController
package com.jafa.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import com.jafa.dao.BoardDao;
import com.jafa.domain.BoardVO;
import com.jafa.domain.Criteria;
import com.jafa.domain.Pagination;
@Controller
@RequestMapping("/board")
public class BoardController {
@Autowired
BoardDao dao;
@GetMapping("/list")
public String list(Criteria criteria, Model model) {
List<BoardVO> list = dao.list(criteria);
Pagination pagination = new Pagination(criteria, dao.totalCount());
model.addAttribute("list", list);
model.addAttribute("p", pagination);
return "/board/list";
}
@GetMapping("/detail")
public String detail(@RequestParam("bnumber") Long bno, Model model) {
try {
BoardVO detail = dao.detail(bno);
System.out.println(detail);
model.addAttribute("board", detail);
} catch (EmptyResultDataAccessException e) {
System.out.println("장난no");
return "/error/notFoundArticle";
}
return "/board/detail";
}
}
- HomeController
package com.jafa.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class HomeController {
@GetMapping("/")
public String home() {
return "index";
}
}
- com.jafa.dao 패키지 BoardDao 클래스 생성
- BoardDao
package com.jafa.dao;
import java.util.List;
import org.apache.tomcat.jdbc.pool.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;
import com.jafa.domain.BoardVO;
import com.jafa.domain.Criteria;
@Repository
public class BoardDao {
JdbcTemplate jdbcTemplate;
@Autowired
public BoardDao(DataSource dataSource) {
jdbcTemplate = new JdbcTemplate(dataSource);
}
RowMapper<BoardVO> rowMapper =
(rs, rowNum) ->
BoardVO.builder()
.bno(rs.getLong("bno"))
.title(rs.getString("title"))
.content(rs.getString("content"))
.writer(rs.getString("writer"))
.writeDate(rs.getDate("writeDate")).build();
public List<BoardVO> list(Criteria criteria) {
String sql = "SELECT ROWNUM, BNO, TITLE, CONTENT, WRITER, WRITEDATE";
sql += " FROM (SELECT /*+INDEX_DESC(BOARD_PAGING PK_BOARD)*/ ";
sql += " ROWNUM AS RN, BNO, TITLE, CONTENT, WRITER, WRITEDATE ";
sql += " FROM BOARD_PAGING WHERE ROWNUM <= ?) WHERE RN > ? ";
int maxRow = criteria.getPageNum() * criteria.getAmount();
int minRow = (criteria.getPageNum() - 1) * criteria.getAmount();
return jdbcTemplate.query(sql, rowMapper, maxRow, minRow);
}
public int totalCount() {
return jdbcTemplate.queryForObject("select count(*) from board_paging", Integer.class);
}
public BoardVO detail(Long bno) {
String sql = "select * from board_paging where bno=?";
return jdbcTemplate.queryForObject(sql, rowMapper, bno);
}
}
- src/main/webapp/WEB-INF/views/ index.jsp 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ include file="layout/header.jsp" %>
<div class="container">
<h1>메인페이지</h1>
</div>
<%@ include file="layout/footer.jsp" %>
- src/main/webapp/WEB-INF/views/ layout, board, error 폴더 생성
- layout/header.jsp, footer.jsp
- header.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:set var="contextPath" value="${pageContext.request.contextPath}" />
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.3/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/js/bootstrap.bundle.min.js"></script>
<link rel="stylesheet" href="${contextPath}/resources/css/style.css">
<script src="${contextPath}/resources/js/main.js"></script>
</head>
<body>
- footer.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<footer>footer</footer>
</body>
</html>
- board/list.jsp, detail.jsp
- list.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ include file="../layout/header.jsp" %>
<div class="jumbotron bg-warning my-3 text-center">
<h1>페이징 처리 연습</h1>
</div>
<div class="container">
<table class="table">
<tr>
<th>번호</th>
<th>제목</th>
<th>작성자</th>
<th>작성일</th>
</tr>
<c:forEach items="${list}" var="b">
<tr>
<td>${b.bno}</td>
<td>
<a href="${contextPath}/board/detail?bnumber=${b.bno}">${b.title}</a>
</td>
<td>${b.writer}</td>
<td>${b.writeDate}</td>
</tr>
</c:forEach>
</table>
<ul class="pagination d-flex justify-content-center">
<c:if test="${p.prev}">
<li class="page-item"><a class="page-link" href="?pageNum=${p.startPage-p.displayPageNum}">이전페이지</a></li>
</c:if>
<c:forEach begin="${p.startPage}" end="${p.endPage}" var="pageBtn">
<li class="page-item ${pageBtn==param.pageNum ? 'active' : ''}">
<a class="page-link" href="?pageNum=${pageBtn}">${pageBtn}</a>
</li>
</c:forEach>
<c:if test="${p.next}">
<li class="page-item">
<a class="page-link" href="?pageNum=${p.endPage+1}">다음페이지</a>
</li>
</c:if>
</ul>
</div>
</body>
</html>
- detail.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ include file="../layout/header.jsp" %>
<div class="container">
<table class="table">
<tr>
<th>제목</th>
<td colspan="3">${board.title}</td>
</tr>
<tr>
<th>내용</th>
<td colspan="3">${board.content}</td>
</tr>
<tr>
<th>작성자</th>
<td>${board.writer}</td>
<th>작성일</th>
<td>${board.writeDate}</td>
</tr>
<tr>
<td colspan="4">
<button class="btn btn-primary">수정</button>
<button class="btn btn-danger">삭제</button>
<button class="btn btn-dark">목록</button>
</td>
</tr>
</table>
</div>
</body>
</html>
- error/notFoundArticle.jsp
<%@ 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>
<h1>잘못된 요청입니다.</h1>
</body>
</html>
프로젝트 시작하고 http://localhost:8090/board_paging/board/list 주소창에 요청
첫페이지에는 이전페이지 버튼이 없고
마지막 페이지는 게시물의 수에따라 페이지 수가 표시되고 다음페이지 버튼 없음


detail(상세) 페이지

주소창 뒤에 쿼리스트링을 없는 요청을 보내보자

bnumber=에 4130000000번째 글은 없다.
요청해보면
notFoundArticle.jsp 쪽으로 가서 에러 페이지를 띄워준다.
'학습 > SPRING' 카테고리의 다른 글
14. 스프링 - mybatis 기본 설정 (0) | 2023.01.05 |
---|---|
07. 스프링 - 의존 자동 주입 (0) | 2022.12.22 |
06. 스프링 - 두 개 이상의 설정 파일 사용하기 (0) | 2022.12.21 |
04. 스프링 DI : 생성자 방식 (0) | 2022.12.21 |
03. 스프링 DI - 애노테이션 방식, XML 방식 (0) | 2022.12.19 |
댓글