스프링 부트_MyBatis 사용해서_ 게시판 ( 답변, 페이징 )
DTO
package com.study.springboot.mvjsp.model;
import java.util.Date;
import lombok.Builder;
import lombok.ToString;
@Builder
@ToString
public class Article {
private int id;
private int groupId;
private String sequenceNumber;
private Date postingDate;
private int readCount;
private String writerName;
private String password;
private String title;
private String content;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getGroupId() {
return groupId;
}
public void setGroupId(int groupId) {
this.groupId = groupId;
}
public String getSequenceNumber() {
return sequenceNumber;
}
public void setSequenceNumber(String sequenceNumber) {
this.sequenceNumber = sequenceNumber;
}
public Date getPostingDate() {
return postingDate;
}
public void setPostingDate(Date postingDate) {
this.postingDate = postingDate;
}
public int getReadCount() {
return readCount;
}
public void setReadCount(int readCount) {
this.readCount = readCount;
}
public String getWriterName() {
return writerName;
}
public void setWriterName(String writerName) {
this.writerName = writerName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
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 int getLevel() {
if (sequenceNumber == null) {
return -1;
}
if (sequenceNumber.length() != 16) {
return -1;
}
if (sequenceNumber.endsWith("999999")) {
return 0;
}
if (sequenceNumber.endsWith("9999")) {
return 1;
}
if (sequenceNumber.endsWith("99")) {
return 2;
}
return 3;
}
}
페이징 커맨드객체
package com.study.springboot.mvjsp.model;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class ArticleListModel {
private List<Article> articleList;
private int requestPage;
private int totalPageCount;
private int startRow;
private int endRow;
public ArticleListModel() {
this(Collections.<Article>emptyList(), 0, 0, 0, 0);
}
public ArticleListModel(List<Article> articleList, int requestPageNumber,
int totalPageCount, int startRow, int endRow) {
this.articleList = articleList;
this.requestPage = requestPageNumber;
this.totalPageCount = totalPageCount;
this.startRow = startRow;
this.endRow = endRow;
}
public List<Article> getArticleList() {
return articleList;
}
public boolean isHasArticle() {
return ! articleList.isEmpty();
}
public int getRequestPage() {
return requestPage;
}
public int getTotalPageCount() {
return totalPageCount;
}
public int getStartRow() {
return startRow;
}
public int getEndRow() {
return endRow;
}
}
DAO( 인터페이스 )
package com.study.springboot.mvjsp.dao;
import java.util.List;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Options;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import com.study.springboot.mvjsp.model.Article;
@Mapper
public interface ArticleDao {
@Select("select count(*) from article")
int selectCount();
@Select("select article_id, group_id, sequence_no, posting_date, "
+ "read_count, writer_name, password, title, content from article "
+ "order by sequence_no desc limit ${firstRow-1}, ${endRow - firstRow + 1}")
@Results(id="myResultId", value = {
@Result(property = "id", column = "article_id"),
@Result(property = "groupId", column = "group_id"),
@Result(property = "sequenceNumber", column = "sequence_no"),
@Result(property = "postingDate", column = "posting_date"),
@Result(property = "readCount", column = "read_count"),
@Result(property = "writerName", column = "writer_name")
}) //필드명과 컬럼명이 같으면 @Results 는 필요없다.
List<Article> select(@Param("firstRow") int firstRow, @Param("endRow") int endRow);
@Insert("insert into article "
+ "(group_id, sequence_no, posting_date, read_count, "
+ "writer_name, password, title, content) "
+ "values (#{article.groupId}, #{article.sequenceNumber},"
+ " now(), 0, #{article.writerName}, #{article.password},"
+ " #{article.title}, #{article.content})")
@Options(useGeneratedKeys = true, keyProperty = "id", keyColumn="article_id")
int insert(@Param("article") Article article);
@Select("select * from article where article_id = #{param1}")
Article selectById(int articleId);
@Update("update article set read_count = read_count + 1 where article_id = #{arg0}")
void increaseReadCount(int articleId);
@Select("select min(sequence_no) from article where sequence_no < #{param1} and sequence_no >= #{param2}")
String selectLastSequenceNumber(String searchMaxSeqNum, String searchMinSeqNum);
@Update("update article set title = #{article.title}, content = #{article.content} where article_id = #{article.id}")
int update(@Param("article") Article article);
@Delete("delete from article where article_id = #{param1}")
void delete(int articleId);
}
Controller ( DAO만들고 테스트 해보기 )
package com.study.springboot.mvjsp.controller;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import com.study.springboot.mvjsp.model.Article;
import com.study.springboot.mvjsp.model.ArticleListModel;
import com.study.springboot.mvjsp.service.ArticleNotFoundException;
import com.study.springboot.mvjsp.service.ListArticleService;
import com.study.springboot.mvjsp.service.ReadArticleService;
@Controller
public class MvController {
@Autowired
ListArticleService listSerivce;
@Autowired
ReadArticleService readArticleService;
@GetMapping("/list")
public String list(HttpServletRequest request, Model model) {
String pageNumberString = request.getParameter("p");
int pageNumber = 1;
if (pageNumberString != null && pageNumberString.length() > 0) {
pageNumber = Integer.parseInt(pageNumberString);
}
ArticleListModel articleListModel = listSerivce.getArticleList(pageNumber);
request.setAttribute("listModel", articleListModel);
if (articleListModel.getTotalPageCount() > 0) {
int beginPageNumber =
(articleListModel.getRequestPage() - 1) / 10 * 10 + 1;
int endPageNumber = beginPageNumber + 9;
if (endPageNumber > articleListModel.getTotalPageCount()) {
endPageNumber = articleListModel.getTotalPageCount();
}
model.addAttribute("beginPage", beginPageNumber);
model.addAttribute("endPage", endPageNumber);
}
return "/list_view";
}
@GetMapping("/read")
public String read(HttpServletRequest request, Model model) {
int articleId = Integer.parseInt(request.getParameter("articleId"));
String viewPage = null;
try {
Article article = readArticleService.readArticle(articleId);
request.setAttribute("article", article);
viewPage = "/read_view";
} catch(ArticleNotFoundException ex) {
viewPage = "/article_not_found";
}
return viewPage;
}
}
Service
package com.study.springboot.mvjsp.service;
import java.sql.Connection;
import java.sql.SQLException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.study.springboot.mvjsp.dao.ArticleDao;
import com.study.springboot.mvjsp.model.Article;
@Service
public class ArticleCheckHelper {
@Autowired
ArticleDao articleDao;
public Article checkExistsAndPassword(int articleId, String password)
throws ArticleNotFoundException, InvalidPasswordException{
Article article = articleDao.selectById(articleId);
if (article == null) {
throw new ArticleNotFoundException(
"게시 글이 존재하지 않음: " + articleId);
}
if (!checkPassword(article.getPassword(), password)) {
throw new InvalidPasswordException("패스워드 오류");
}
return article;
}
private boolean checkPassword(String realPassword, String userInputPassword) {
if (realPassword == null) {
return false;
}
if (realPassword.length() == 0) {
return false;
}
return realPassword.equals(userInputPassword);
}
}
package com.study.springboot.mvjsp.service;
public class ArticleNotFoundException extends Exception {
public ArticleNotFoundException(String msg) {
super(msg);
}
}
package com.study.springboot.mvjsp.service;
public class CannotReplyArticleException extends Exception {
public CannotReplyArticleException(String message) {
super(message);
}
}
package com.study.springboot.mvjsp.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.study.springboot.mvjsp.dao.ArticleDao;
@Service
public class DeleteArticleService {
@Autowired
ArticleDao articleDao;
public void deleteArticle(DeleteRequest deleteRequest)
throws ArticleNotFoundException, InvalidPasswordException {
ArticleCheckHelper checkHelper = new ArticleCheckHelper();
checkHelper.checkExistsAndPassword(deleteRequest.getArticleId(),
deleteRequest.getPassword());
articleDao.delete(deleteRequest.getArticleId());
}
}
package com.study.springboot.mvjsp.service;
public class DeleteRequest {
private int articleId;
private String password;
public int getArticleId() {
return articleId;
}
public void setArticleId(int articleId) {
this.articleId = articleId;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
package com.study.springboot.mvjsp.service;
public class IdGenerationFailedException extends Exception {
public IdGenerationFailedException(Throwable cause) {
super(cause);
}
}
package com.study.springboot.mvjsp.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class IdGenerator {
@Autowired
JdbcTemplate jdbcTemplate;
@Transactional
public int generateNextId(String sequenceName) {
String sql = "select next_value from id_sequence " +
"where sequence_name = ? for update";
int id = this.jdbcTemplate.queryForObject(sql,
(rs, n)-> rs.getInt(1), sequenceName);
id++;
sql = "update id_sequence set next_value = ? " +
"where sequence_name = ?";
this.jdbcTemplate.update(sql, id, sequenceName);
return id;
}
}
package com.study.springboot.mvjsp.service;
public class InvalidPasswordException extends Exception {
public InvalidPasswordException(String message) {
super(message);
}
}
package com.study.springboot.mvjsp.service;
public class LastChildAleadyExistsException extends Exception {
public LastChildAleadyExistsException(String message) {
super(message);
}
}
package com.study.springboot.mvjsp.service;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.study.springboot.mvjsp.dao.ArticleDao;
import com.study.springboot.mvjsp.model.Article;
import com.study.springboot.mvjsp.model.ArticleListModel;
@Service
public class ListArticleService {
@Autowired
ArticleDao articleDao;
public static final int COUNT_PER_PAGE = 10;
public ArticleListModel getArticleList(int requestPageNumber) {
if (requestPageNumber < 0) {
throw new IllegalArgumentException("page number < 0 : " + requestPageNumber);
}
int totalArticleCount = articleDao.selectCount();
if (totalArticleCount == 0) {
return new ArticleListModel();
}
int totalPageCount = calculateTotalPageCount(totalArticleCount);
int firstRow = (requestPageNumber - 1) * COUNT_PER_PAGE + 1;
int endRow = firstRow + COUNT_PER_PAGE - 1;
if (endRow > totalArticleCount) {
endRow = totalArticleCount;
}
List<Article> articleList = articleDao.select(firstRow, endRow);
ArticleListModel articleListView = new ArticleListModel(articleList, requestPageNumber, totalPageCount,
firstRow, endRow);
return articleListView;
}
private int calculateTotalPageCount(int totalArticleCount) {
if (totalArticleCount == 0) {
return 0;
}
int pageCount = totalArticleCount / COUNT_PER_PAGE;
if (totalArticleCount % COUNT_PER_PAGE > 0) {
pageCount++;
}
return pageCount;
}
}
package com.study.springboot.mvjsp.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.study.springboot.mvjsp.dao.ArticleDao;
import com.study.springboot.mvjsp.model.Article;
@Service
public class ReadArticleService {
@Autowired
ArticleDao articleDao;
public Article readArticle(int articleId) throws ArticleNotFoundException {
return selectArticle(articleId, true);
}
private Article selectArticle(int articleId, boolean increaseCount) throws ArticleNotFoundException {
Article article = articleDao.selectById(articleId);
if (article == null) {
throw new ArticleNotFoundException(
"게시글이 없음: " + articleId);
}
if (increaseCount) {
articleDao.increaseReadCount( articleId);
article.setReadCount(article.getReadCount() + 1);
}
return article;
}
public Article getArticle(int articleId) throws ArticleNotFoundException {
return selectArticle(articleId, false);
}
}
JSPList
<%@ page contentType="text/html; charset=euc-kr" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%
response.setHeader("Pragma", "No-cache");
response.setHeader("Cache-Control", "no-cache");
response.addHeader("Cache-Control", "no-store");
response.setDateHeader("Expires", 1L);
%>
<html>
<head><title>게시글 목록</title></head>
<body>
<table border="1">
<c:if test="${listModel.totalPageCount > 0}">
<tr>
<td colspan="5">
${listModel.startRow}-${listModel.endRow}
[${listModel.requestPage}/${listModel.totalPageCount}]
</td>
</tr>
</c:if>
<tr>
<td>글 번호</td>
<td>제목</td>
<td>작성자</td>
<td>작성일</td>
<td>조회수</td>
</tr>
<c:choose>
<c:when test="${listModel.hasArticle == false}">
<tr>
<td colspan="5">
게시글이 없습니다.
</td>
</tr>
</c:when>
<c:otherwise>
<c:forEach var="article" items="${listModel.articleList}">
<tr>
<td>${article.id}</td>
<td>
<c:if test="${article.level > 0}">
<c:forEach begin="1" end="${article.level}">-</c:forEach>>
</c:if>
<c:set var="query"
value="articleId=${article.id}&p=${listModel.requestPage}"/>
<a href="<c:url value="/read?${query}"/>">
${article.title}
</a>
</td>
<td>${article.writerName}</td>
<td>${article.postingDate}</td>
<td>${article.readCount}</td>
</tr>
</c:forEach>
<tr>
<td colspan="5">
<c:if test="${beginPage > 10}">
<a href="<c:url value="/list?p=${beginPage-1}"/>">이전</a>
</c:if>
<c:forEach var="pno" begin="${beginPage}" end="${endPage}">
<a href="<c:url value="/list?p=${pno}" />">[${pno}]</a>
</c:forEach>
<c:if test="${endPage < listModel.totalPageCount}">
<a href="<c:url value="/list?p=${endPage + 1}"/>">다음</a>
</c:if>
</td>
</tr>
</c:otherwise>
</c:choose>
<tr>
<td colspan="5">
<a href="writeForm.jsp">글쓰기</a>
</td>
</tr>
</table>
</body>
</html>
read_view
<%@ page contentType="text/html; charset=euc-kr" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%
response.setHeader("Pragma", "No-cache");
response.setHeader("Cache-Control", "no-cache");
response.addHeader("Cache-Control", "no-store");
response.setDateHeader("Expires", 1L);
%>
<html>
<head><title>글 읽기</title></head>
<body>
<table>
<tr>
<td>제목</td>
<td>${article.title}</td>
</tr>
<tr>
<td>작성자</td>
<td>${article.writerName}</td>
</tr>
<tr>
<td>작성일</td>
<td><fmt:formatDate value="${article.postingDate}"
pattern="yyyy-MM-dd" /></td>
</tr>
<tr>
<td>내용</td>
<td>
<pre><c:out value="${article.content}" /></pre>
</td>
</tr>
<tr>
<td colspan="2">
<a href="list?p=${param.p}">목록보기</a>
<a href="reply_form.jsp?parentId=${article.id}&p=${param.p}">답변쓰기</a>
<a href="update_form.jsp?articleId=${article.id}&p=${param.p}">수정하기</a>
<a href="delete_form.jsp?articleId=${article.id}">삭제하기</a>
</td>
</tr>
</table>
</body>
</html>
결과
'프로젝트 기반 자바(JAVA) 응용 SW개발자 취업과정' 카테고리의 다른 글
2023-09-12 81일차 (0) | 2023.09.12 |
---|---|
2023-09-11 80일차 (0) | 2023.09.11 |
2023-09-07 78일차 (0) | 2023.09.07 |
2023-09-06 77일차 (0) | 2023.09.06 |
2023-09-05 76일차 (0) | 2023.09.05 |