스프링 부트_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>&gt;
			</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

+ Recent posts