1. 글 목록 보기, 새로운 글쓰기, 페이징, 글 검색 기능 구현.
2.소스코드
board.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thyleaf.org">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>main page</title>
<link href="../css/main.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<style>
table{
width:100%;
height:70%;
border: 1px solid;
border-collapse: collapse;
text-align: center;
}
tr, td{
border: 1px solid;
border-collapse: collapse;
padding: 3px 3px;
}
button {
left: 85%;
background-color: #fff;
border: 1px solid #d5d9d9;
border-radius: 8px;
box-shadow: rgba(213, 217, 217, .5) 0 2px 5px 0;
box-sizing: border-box;
color: #0f1111;
cursor: pointer;
display: inline-block;
font-family: "Amazon Ember",sans-serif;
font-size: 13px;
line-height: 29px;
padding: 0 10px 0 11px;
position: relative;
text-align: center;
text-decoration: none;
user-select: none;
-webkit-user-select: none;
touch-action: manipulation;
vertical-align: middle;
width: 80px;
}
button:hover {
background-color: #f7fafa;
}
button:focus {
border-color: #008296;
box-shadow: rgba(213, 217, 217, .5) 0 2px 5px 0;
outline: 0;
}
.pagination {
display: inline-block;
}
.pagination a {
color: black;
float: left;
padding: 8px 16px;
text-decoration: none;
border: 1px solid #ddd;
}
.pagination a.active {
background-color: #4CAF50;
color: white;
border: 1px solid #4CAF50;
}
.pagination a:hover:not(.active) {background-color: #ddd;}
.pagination a:first-child {
border-top-left-radius: 5px;
border-bottom-left-radius: 5px;
}
.pagination a:last-child {
border-top-right-radius: 5px;
border-bottom-right-radius: 5px;
}
</style>
<div class="header">
<h1>Spring 취약점 테스트</h1>
</div>
<div class="topnav">
<a href="../login">로그인</a>
<a href="board">게시판</a>
<a href="#">SSTI 취약점</a>
<a href="#">LFI, RFI</a>
<a href="#">추가 예정</a>
</div>
<div class="row">
<div class="column side">
<h2>환경 구성</h2>
<p>Spring boot 2.7.3 <br> Gradle <br> Thymeleaf <br> MySQL <br> Mybatis</p>
</div>
<div class="column middle">
<h2>게시판</h2>
검색어: <p th:text="${search}"></p>
<head>
<meta charset="UTF-8">
</head>
<body>
<div class="container">
<table>
<thead>
<td>번호</td>
<td>제목</td>
<td>작성자</td>
</thead>
<tbody>
<tr th:each="board: ${boardlist}">
<td th:text="${board.id}"></td>
<td th:text="${board.title}"></td>
<td th:text="${board.writer}"></td>
</tr>
</tbody>
</table>
<button onclick="location.href='newpost'" style="margin-top:3px;=">글쓰기</button>
<!-- pagination{s} -->
<div id="paginationBox">
<ul class="pagination">
<!-- <th:if test="${pagination.prev}">-->
<li class="page-item" th:if="${pagination.prev}">
<!-- <a class="page-link" href="#" onClick="fn_prev('${pagination.page}', '${pagination.range}', '${pagination.rangeSize}')">Previous</a>-->
<a class="page-link" href="#"
th:attr="onclick=|fn_prev('${pagination.page}', '${pagination.range}', '${pagination.rangeSize}')|">Previous</a>
</li>
<!-- </th:if>-->
<!-- <th:forEach begin="${pagination.startPage}" end="${pagination.endPage}" var="idx">-->
<!--<!– <li class="page-item <th:out value=\"${pagination.page== idx ? 'active' : ''}\"/> ">–>-->
<!-- <li class="page-item">-->
<!-- <a class="page-link" href="#" onClick="fn_pagination('${idx}', '${pagination.range}', '${pagination.rangeSize}')">-->
<!-- ${idx}-->
<!-- </a>-->
<!-- </li>-->
<!-- </th:forEach>-->
<th:block th:each="idx : ${#numbers.sequence(pagination.startPage, pagination.endPage+1)}">
<!-- <a th:text="${idx}" class="page-link" href="#" onClick="fn_pagination('${idx}', '${pagination.range}', '${pagination.rangeSize}')"></a>-->
<a th:text="${idx}" class="page-link" href="#"
th:attr="onclick=|fn_pagination('${idx}', '${pagination.range}', '${pagination.rangeSize}')|"></a>
</th:block>
<!-- <th:if test="${pagination.next}">-->
<li class="page-item" th:if="${pagination.next}">
<!-- <a class="page-link" href="#" onClick="fn_next('${pagination.range}', '${pagination.range}', '${pagination.rangeSize}')">Next</a>-->
<a class="page-link" href="#"
th:attr="onclick=|fn_next('${pagination.page}', '${pagination.range}', '${pagination.rangeSize}')|">Previous</a>
</li>
<!-- </th:if>-->
</ul>
</div>
<!-- pagination{e} -->
<div id="search_box" style="text-align: center;">
<form action="search_result" mothod="get">
<select name="gubun">
<option value="title">제목</option>
<option value="writer">글쓴이</option>
<option value="content">내용</option>
</select>
<input type="text" name="search" size="40" required="required">
<button class="btn" style="position:relative; left:3px;">검색</button>
</form>
</div>
</div>
</body>
</div>
<div class="column side">
<h2>Side</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit..</p>
</div>
</div>
<div class="footer">
<p>Footer</p>
</div>
</body>
</html>
<script>
//이전 버튼 이벤트
function fn_prev(page, range, rangeSize) {
var page = ((range - 2) * rangeSize) + 1;
var range = range - 1;
var url = "/Board/boardpage";
url = url + "?page=" + page;
url = url + "&range=" + range;
location.href = url;
}
//페이지 번호 클릭
function fn_pagination(page, range, rangeSize, searchType, keyword) {
var url = "/Board/boardpage";
url = url + "?page=" + page;
url = url + "&range=" + range;
location.href = url;
}
//다음 버튼 이벤트
function fn_next(page, range, rangeSize) {
var page = parseInt((range * rangeSize)) + 1;
var range = parseInt(range) + 1;
var url = "/Board/boardpage";
url = url + "?page=" + page;
url = url + "&range=" + range;
location.href = url;
}
</script>
css
* {
box-sizing: border-box;
}
body {
margin: 0;
}
/* Style the header */
.header {
background-color: #f1f1f1;
padding: 20px;
text-align: center;
}
/* Style the top navigation bar */
.topnav {
overflow: hidden;
background-color: #333;
}
/* Style the topnav links */
.topnav a {
float: left;
display: block;
color: #f2f2f2;
text-align: center;
padding: 14px 16px;
text-decoration: none;
}
/* Change color on hover */
.topnav a:hover {
background-color: #ddd;
color: black;
}
/* Create three unequal columns that floats next to each other */
.column {
float: left;
padding: 10px;
}
/* Left and right column */
.column.side {
width: 25%;
}
/* Middle column */
.column.middle {
width: 50%;
}
/* Clear floats after the columns */
.row:after {
content: "";
display: table;
clear: both;
}
/* Responsive layout - makes the three columns stack on top of each other instead of next to each other */
@media screen and (max-width: 600px) {
.column.side, .column.middle {
width: 100%;
}
}
/* Style the footer */
.footer {
background-color: #f1f1f1;
padding: 10px;
text-align: center;
}
Controller
BoardController
package hello.hellospring.Controller;
import hello.hellospring.domain.Board;
import hello.hellospring.domain.Pagination;
import hello.hellospring.mapper.BoardMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import static java.lang.System.out;
@Controller
@Slf4j
public class BoardController {
private final BoardMapper boardMapper;
public BoardController(BoardMapper boardMapper) {
this.boardMapper = boardMapper;
}
@GetMapping("Board/board")
public String getBoardList(@ModelAttribute Board board, Model model){
Pagination pagination = new Pagination();
int totalCount = boardMapper.getBoardTotal(board);
int page = 1;
pagination.pageInfo(page, 1, totalCount);
board.setStartRownum(pagination.getStartList());
board.setEndRownum(pagination.getEndList());
List<Board> boardList = boardMapper.getBoardPage(board);
model.addAttribute("boardlist", boardList);
model.addAttribute("pagination", pagination);
return "Board/board";
}
@GetMapping("Board/boardpage")
public String getBoardListPage(@ModelAttribute Board board, Model model){
// pageInfo(int page, int range, int listCnt);
Pagination pagination = new Pagination();
int totalCount = boardMapper.getBoardTotal(board);
int page = 1;
if ( board.getPage() > 1 ) page = board.getPage();
pagination.pageInfo(page, 1, totalCount);
out.println("------------------------");
out.println(page);
out.println(pagination.getStartList());
out.println(pagination.getEndList());
out.println("------------------------");
board.setStartRownum(pagination.getStartList());
board.setEndRownum(pagination.getEndList());
List<Board> boardList = boardMapper.getBoardPage(board);
model.addAttribute("boardlist", boardList);
model.addAttribute("pagination", pagination);
return "Board/board";
}
@GetMapping("Board/search_result")
public String board_search(@ModelAttribute Board board ,Model model, HttpServletRequest request){
Pagination pagination = new Pagination();
int totalCount = boardMapper.getBoardTotal(board);
int page = 1;
pagination.pageInfo(page, 1, totalCount);
board.setStartRownum(pagination.getStartList());
board.setEndRownum(pagination.getEndList());
String search1 = board.getSearch();
List<Board> boardList = boardMapper.resultBoard(board);
String search = request.getParameter("search");
// model.addAttribute("search",search);
model.addAttribute("search",search1);
model.addAttribute("boardlist", boardList);
model.addAttribute("pagination", pagination);
return "Board/board";
}
@GetMapping("Board/newpost")
public String board_new(@ModelAttribute Board board , Model model){
return "Board/newpost";
}
@PostMapping("Board/newpost_ok")
public String board_newpost(@ModelAttribute Board board , Model model){
boardMapper.setBoard(board);
model.addAttribute("board", board);
out.println("====================" + board.getTitle());
out.println("====================" + board.getContent());
return "redirect:/Board/board";
}
}
Domain
Board.java
package hello.hellospring.domain;
public class Board {
private String title;
private String content;
private String writer;
private Long id;
private String gubun;
private String search;
// paging
private int startRownum;
private int endRownum;
private int page;
public int getStartRownum() {
return startRownum;
}
public void setStartRownum(int startRownum) {
this.startRownum = startRownum;
}
public int getEndRownum() {
return endRownum;
}
public void setEndRownum(int endRownum) {
this.endRownum = endRownum;
}
public int getPage() {
return page;
}
public void setPage(int page) {
this.page = page;
}
public Board(Long id, String title, String content, String writer) {
this.id = id;
this.title = title;
this.content = content;
this.writer = writer;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getWriter() {
return writer;
}
public void setWriter(String writer) {
this.writer = writer;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getGubun() {
return gubun;
}
public void setGubun(String gubun) {
this.gubun = gubun;
}
public String getSearch() {
return search;
}
public void setSearch(String search) {
this.search = search;
}
}
Pagination(페이징)
package hello.hellospring.domain;
public class Pagination {
private int listSize = 7; // ** //초기값으로 목록개수를 10으로 셋팅
private int rangeSize = 10; //초기값으로 페이지범위를 10으로 셋팅
private int page; // *** current page
private int range; // 각 페이지 범위 시작 번호
private int listCnt; // ** total count
private int pageCnt;
private int startPage;
private int startList;
private int endList;
private int endPage;
private boolean prev;
private boolean next;
public int getRangeSize() {
return rangeSize;
}
public int getPage() {
return page;
}
public void setPage(int page) {
this.page = page;
}
public int getRange() {
return range;
}
public void setRange(int range) {
this.range = range;
}
public int getStartPage() {
return startPage;
}
public void setStartPage(int startPage) {
this.startPage = startPage;
}
public int getEndPage() {
return endPage;
}
public void setEndPage(int endPage) {
this.endPage = endPage;
}
public boolean isPrev() {
return prev;
}
public void setPrev(boolean prev) {
this.prev = prev;
}
public boolean isNext() {
return next;
}
public void setNext(boolean next) {
this.next = next;
}
public int getListSize() {
return listSize;
}
public void setListSize(int listSize) {
this.listSize = listSize;
}
public int getListCnt() {
return listCnt;
}
public void setListCnt(int listCnt) {
this.listCnt = listCnt;
}
public int getStartList() {
return startList;
}
public int getEndList() {
return endList;
}
public void pageInfo(int page, int range, int listCnt) {
this.page = page;
this.range = range;
this.listCnt = listCnt;
//전체 페이지수
this.pageCnt = (int) Math.ceil(listCnt/listSize);
//시작 페이지
this.startPage = (range - 1) * rangeSize + 1 ;
//끝 페이지
this.endPage = range * rangeSize;
//게시판 시작번호
this.startList = (page - 1) * listSize;
this.endList = (page - 1) * listSize + listSize -1;
//이전 버튼 상태
this.prev = range == 1 ? false : true;
//다음 버튼 상태
this.next = endPage > pageCnt ? false : true;
if (this.endPage > this.pageCnt) {
this.endPage = this.pageCnt;
this.next = false;
}
}
}
interface
BoardMapper
package hello.hellospring.mapper;
import hello.hellospring.domain.Board;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
@Mapper
public interface BoardMapper {
List<Board> getBoard(Board board);
List<Board> getBoardPage(Board board);
int getBoardTotal(Board board);
List<Board> resultBoard(Board board);
int setBoard(Board board);
void deleteBoard(Board board);
}
board-mapper.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="hello.hellospring.mapper.BoardMapper">
<resultMap type="board" id="selectMap">
<result column="id" property="id"/>
<result column="title" property="title"/>
<result column="content" property="content"/>
<result column="writer" property="writer"/>
</resultMap>
<select id="getBoard" resultMap="selectMap">
select * from board
</select>
<select id="getBoardPage" parameterType="Board" resultMap="selectMap">
<![CDATA[
select *
from
(
select @rownum := @rownum +1 AS ROWNUM
, b.* from board b, (SELECT @ROWNUM:=0) R
) t
where ROWNUM >= #{startRownum,jdbcType=NUMERIC}
and ROWNUM <= #{endRownum,jdbcType=NUMERIC}
]]>
</select>
<select id="getBoardTotal" parameterType="Board" resultType="int">
select count(*) as totalCnt from board
</select>
<!-- 리턴값이 존재하지않음! int 값으로 반환 -->
<insert id="setBoard" parameterType="Board">
INSERT INTO board (title, content,writer) VALUES (#{title,jdbcType=VARCHAR}, #{content,jdbcType=VARCHAR}, #{writer,jdbcType=VARCHAR});
</insert>
<delete id="deleteBoard" parameterType="Board">
delete from board where id = #{id,jdbcType=NUMERIC}
</delete>
<select id="resultBoard" parameterType="Board" resultMap="selectMap">
select * from board
where 1 = 1
<choose>
<when test='gubun == "title"'>
<!-- AND title like #{search,jdbcType=VARCHAR}-->
AND title like "${search}"
</when>
<when test='gubun == "content"'>
AND content like #{search,jdbcType=VARCHAR}
</when>
<when test='gubun == "writer"'>
AND writer like #{search,jdbcType=VARCHAR}
</when>
</choose>
</select>
</mapper>
'개발 > Java' 카테고리의 다른 글
[Spring] 스프링 입문 4 - 로그인 페이지 제작하기 (0) | 2022.12.25 |
---|---|
[Spring] Infearn 스프링 입문3 - (응용)MySQL & Mybatis 사용 (1) | 2022.12.15 |
[Android 개발] Unresolved class 'Activity', xml에서 클래스를 못찾을 때 해결 (0) | 2022.12.07 |
[Spring] Infearn 스프링 입문 필기 2 - 실습, 회원 등록, 회원 조회 기능 만들기 (0) | 2022.12.06 |
[Spring] Infearn 스프링 입문 필기 1 - 개념 학습 (1) | 2022.12.06 |