프로그래밍/Java

[Spring] 스프링 삽질일지 6일차 - 내용 부족 시 경고창 팝업, 페이징 기능 구현(데모)

Be개발자 2021. 5. 12. 03:25

오늘은 경고창 팝업과 페이징 기능을 구현해보고자 한다.

STS를 3.9.16에서 3.9.7로 바꿔서 프로젝트를 열어보니 이게 웬걸....

실행해보니 무언가 이상하다. 

그래서 처음부터 하나하나 다시 만들었는데 문제는 바로 Java 버전이랑 JUnit 라이브러리 추가를 안한거 때문이었다니.. 그래도 2시간이면 싸게 먹힌 거 같다 ㅎㅎ

 

그리고 블로그 업뎃이 엄청 오랜만인데... 시험기간이었다...

새하얗게 불태웠다. 흑흑

 


1. 게시판 작성 중 내용 미입력 시 경고 메시지 팝업

 

게시판 작성 부분에서 하나라도 공백으로 적을 시 경고창을 띄우는 기능을 추가하고자 한다. 

writeView.jsp로 가 head 태그 부분에 jquery가 있는지 확인해준다. 

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>

없으면 추가해주고 그 다음에 head 태그와 body 태그 사이에 다음 코드를 추가해준다. 이는 게시글 작성 후 "등록" 버튼을 누를 때 미입력 부분이 있으면 해당 부분을 입력하라고 경고창을 띄워준다.

fn_valiChk 함수가 공백이 있는지 체크해주는 함수이다.

	<script type="text/javascript">
		$(document).ready(function(){
			var formObj = $("form[name='writeForm']");
			$(".write_btn").on("click", function(){
				if(fn_valiChk()){
					return false;
				}
				formObj.attr("action", "/board/write");
				formObj.attr("method", "post");
				formObj.submit();
			});
		})
		function fn_valiChk(){
			var regForm = $("form[name='writeForm'] .chk").length;
			for(var i = 0; i<regForm; i++){
				if($(".chk").eq(i).val() == "" || $(".chk").eq(i).val() == null){
					alert($(".chk").eq(i).attr("title"));
					return true;
				}
			}
		}
	</script>

 

form의 name을 "writeForm"으로 설정해주고 

기존의 태그들 안에 class="chk" title="팝업경고창에서 띄울 메시지" 를 추가로 적어준다.

그 후, 등록 버튼에다가 class="write_btn"을 추가해준다.

writeView.jsp에 한 것을 동일하게 updateView.jsp에도 적용시켜준다.

updateView.jsp에도 

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>

있는지 확인하고 

head 태그와 body 태그 사이에 다음 코드를 추가한다.

<script type="text/javascript">
		$(document).ready(function(){
			
			$(".cancel_btn").on("click", function(){
				event.preventDefault();
				location.href = "/board/list";
			})
		})
	</script>
	
		<script type="text/javascript">
		$(document).ready(function(){
			var formObj = $("form[name='updateForm']");
			$(".update_btn").on("click", function(){
				if(fn_valiChk()){
					return false;
				}
				formObj.attr("action", "/board/write");
				formObj.attr("method", "post");
				formObj.submit();
			});
		})
		function fn_valiChk(){
			var regForm = $("form[name='updateForm'] .chk").length;
			for(var i = 0; i<regForm; i++){
				if($(".chk").eq(i).val() == "" || $(".chk").eq(i).val() == null){
					alert($(".chk").eq(i).attr("title"));
					return true;
				}
			}
		}
	</script>

그 후, 마찬가지로 각 항목마다 class="chk"와 title="경고메시지"를 추가해준다.

테스트 결과 writeView에서 비밀번호를 치지 않은 상태에서 "등록" 버튼을 누르니 경고창이 제대로 떴다.

 

또한 updateView에서도 마찬가지로 "상품설명" 부분을 공란으로 둔채 "게시물 수정" 버튼을 누르니 내용을 입력하라는 경고창이 뜨는 것을 확인할 수 있다.

 

2. 페이징 기능 구현

 

페이징이란 게시판의 글 개수를 제한하는 기능을 말한다. 그리하여 한 페이지에 3개의 게시물이 보이도록 작업하고자 한다. 또한 페이지의 경우 +2, -2 페이지까지 보이도록 페이지 버튼을 만들고자 한다. 예를 들면 3페이지일때 1~5페이지까지 이동 가능하도록 말이다.

 

일단 데이터베이스에 더미 데이터(dummy data)를 쌓아서 게시글의 개수를 대폭 증가시켜보자.

아래 코드는 500개의 더미데이터를 생성하는 loopInsert PROCEDURE이다.

DROP PROCEDURE IF EXISTS loopInsert$$
 
CREATE PROCEDURE loopInsert()
BEGIN
    DECLARE i INT DEFAULT 1;
        
    WHILE i <= 500 DO
        INSERT INTO board_table(writer , userpass, category, content, cost , image, click_cnt, create_date , state)
          VALUES(concat('작성자',i), concat('비밀번호',i),  concat('카테고리',i), concat('상품설명',i),  i,  
			 concat('이미지',i),  i , now(),  concat('상태',i));
        SET i = i + 1;
    END WHILE;
END$$
DELIMITER $$

 

loopInsert .실행한다.

CALL loopInsert;

 

기존에 테스트용으로 존재하던 데이터들까지 합쳐서 대략 500개의 데이터가 만들어졌다. 

 

 

껄껄껄 근데 만들고나니 망한걸 느꼈다... 내 프로젝트는 정렬 기준이 상품상태(STATE)와 등록시간(Create_date)이기 때문에 더미데이터를 위와 같이 만들면 정렬이 어렵다... 결국 하나하나 넣었다...^_^ 다른 분들은 정렬 기준이 게시판의 고유번호라면 위 방식을 써도 된다... 참고하실 분들만 하십쇼 ㅎㅎ

 

결국 나는 하나하나 내가 데이터를 넣어서 만들었다... ^_^ 대략 18~20개 정도 넣은 거 같다. 그러고 정렬 기준에 맞추어 3개의 값만 읽어오는 쿼리를 작성하여 실행해보니 제대로 앞의 3개의 것을 읽어오는 것을 확인할 수 있다.

 

 

쿼리 코드는 다음과 같다!

 

SELECT *
FROM (
        SELECT *,
        ROW_NUMBER() over(ORDER BY FIELD(STATE,"판매완료") ASC, CREATE_DATE ASC) AS rNum
        FROM board_table
			)A
WHERE rNum BETWEEN 1 AND 3;

 

만든 쿼리문을 boardMapper.xml에 추가해준다. 이때 카테고리 상관없이 모든 카테고리의 게시글 개수를 구하는 listCount와 인자로 카테고리가 들어오면 해당 카테고리의 게시글 개수를 세주는 listCount2를 추가한다.

<select id="listCount" resultType="int" >
		<![CDATA[
		SELECT COUNT(ID)
		FROM board_table
		WHERE ID > 0
		]]>
	</select>
	
		<select id="listCount2" resultType="int" parameterType="String">
		<![CDATA[
		SELECT COUNT(ID)
		FROM board_table
		WHERE CATEGORY = #{value} AND ID > 0	
		]]>

	</select>

 

이때 꽤나 삽질을 했던 것이 mybatis의 경우 String을 넘길 때 getter가 없기 때문에 String값을 인자로 넘길 때 변수명을 그대로 사용하면 에러가 났었다. 그렇기에 실제로 넘어오는 parameter 변수명이 category더라도 우리는 value라는 변수를 써서 받아야만 정상적으로 인자 값이 넘어간다. ㅜㅜ

 

 

이제 com.board.domain 패키지에 Criteria.java를 생성한 뒤 다음과 같이 코드를 작성해준다.

 

package com.board.domain;

public class Criteria {
	
	private int page;
	private int perPageNum;
	private int rowStart;
	private int rowEnd;
	
	public Criteria() {
		this.page = 1;
		this.perPageNum = 3;
	}
	
	public void setPage(int page) {
		if (page <= 0) {
			this.page = 1;
			return;
		}
		this.page = page;
	}
	
	public void setPerPageNum(int perPageNum) {
		if (perPageNum <= 0 || perPageNum > 100) {
			this.perPageNum = 3;
			return;
		}
		this.perPageNum = perPageNum;
	}
	
	public int getPage() {
		return page;
	}
	
	public int getPageStart() {
		return (this.page - 1) * perPageNum;
	}
	
	public int getPerPageNum() {
		return this.perPageNum;
	}
	
	public int getRowStart() {
		rowStart = ((page - 1) * perPageNum) + 1;
		return rowStart;
	}
	
	public int getRowEnd() {
		rowEnd = rowStart + perPageNum - 1;
		return rowEnd;
	}

	@Override
	public String toString() {
		return "Criteria [page=" + page + ", perPageNum=" + perPageNum + ", rowStart=" + rowStart + ", rowEnd=" + rowEnd
				+ "]";
	}

}

 

 

 

BoardDAO.java 코드 중 list 함수들의 인자에 Criteria를 추가해주고, 게시글의 총 개수를 구하는 listCount를 추가로 선언해준다.

 

// Post list lookup
	public List<BoardVO> list(Criteria cri) throws Exception;
	
	// Post list_Toys lookup
	public List<BoardVO> list_Toys(Criteria cri) throws Exception;
	
	// Post list_Clothes lookup
	public List<BoardVO> list_Clothes(Criteria cri) throws Exception;
	
	// Post list_Fruits lookup
	public List<BoardVO> list_Fruits(Criteria cri) throws Exception;
	
	// Post list_Electronics lookup
	public List<BoardVO> list_Electronics(Criteria cri) throws Exception;
	
	// Count Total number of bulletin boards
	public int listCount() throws Exception;
	
	// Count number of posts in the category
	public int listCount2(String category) throws Exception;

 

BoardDAOImpl.java에서 다음과 같이 구현해준다.

 

 

// Post list lookup
	@Override
	public List<BoardVO> list(Criteria cri) throws Exception{
		
		return sqlSession.selectList("boardMapper.listPage", cri);
	}
	
	// Post list_Toys lookup
	@Override
	public List<BoardVO> list_Toys(Criteria cri) throws Exception{
		return sqlSession.selectList("boardMapper.listPage_Toys", cri);
	}
		
	// Post list_Clothes lookup
	@Override
	public List<BoardVO> list_Clothes(Criteria cri) throws Exception{
		return sqlSession.selectList("boardMapper.listPage_Clothes", cri);
	}
	
	
	// Post list_Fruits lookup
	@Override
	public List<BoardVO> list_Fruits(Criteria cri) throws Exception{
		return sqlSession.selectList("boardMapper.listPage_Fruits", cri);
	}
		
	// Post list_Electronics lookup
	@Override
	public List<BoardVO> list_Electronics(Criteria cri) throws Exception{
		return sqlSession.selectList("boardMapper.listPage_Electronics", cri);
	}
	
	// Count Total number of bulletin boards
	public int listCount() throws Exception{
		return sqlSession.selectOne("boardMapper.listCount");
	}
	
	// Count Total number of bulletin boards
	public int listCount2(String category) throws Exception{
		return sqlSession.selectOne("boardMapper.listCount2", category);
	}

 

BoardService와 BoardServiceImpl에도 똑같이 구현해준다.

 

 

BoardService.java
BoardServiceImpl.java

 

 

 

이제 com.board.domain에 PageMaker.java 파일을 만들어주자.

 

package com.board.domain;

import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;

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;
	
	public void setCri(Criteria cri) {
		this.cri = cri;
	}
	
	public void setTotalCount(int totalCount) {
		this.totalCount = totalCount;
		calcData();
	}
	
	public int getTotalCount() {
		return totalCount;
	}
	
	public int getStartPage() {
		return startPage;
	}
	
	public int getEndPage() {
		return endPage;
	}
	
	public boolean isPrev() {
		return prev;
	}
	
	public boolean isNext() {
		return next;
	}
	
	public int getDisplayPageNum() {
		return displayPageNum;
	}
	
	public Criteria getCri() {
		return cri;
	}
	 
	private void calcData() {
		endPage = (int) (Math.ceil(cri.getPage() / (double)displayPageNum) * displayPageNum);
		startPage = (endPage - displayPageNum) + 1;
	  
		int tempEndPage = (int) (Math.ceil(totalCount / (double)cri.getPerPageNum()));
		if (endPage > tempEndPage) {
			endPage = tempEndPage;
		}
		prev = startPage == 1 ? false : true;
		next = endPage * cri.getPerPageNum() >= totalCount ? false : true;
	}
	
	public String makeQuery(int page) {
		UriComponents uriComponents =
		UriComponentsBuilder.newInstance()
						    .queryParam("page", page)
							.queryParam("perPageNum", cri.getPerPageNum())
							.build();
		   
		return uriComponents.toUriString();
	}

}

 

 

이제 BoardController로 이동하여 기존에 작성한 list 함수들의 인자에 Criteria를 추가해준다. 또한 pageMaker 객체도 생성하여 setCri함수와 setTotalCount 함수를 호출하여 page를 만들어준다.

 

// Bulletin board list inquiry
	@RequestMapping(value = "/list", method = RequestMethod.GET)
	public String list(Model model, Criteria cri) throws Exception{
		logger.info("list");
		
		model.addAttribute("list",service.list(cri));
		
		PageMaker pageMaker = new PageMaker();
		pageMaker.setCri(cri);
		pageMaker.setTotalCount(service.listCount());
		
		model.addAttribute("pageMaker", pageMaker);
		
		return "board/list";
	}
		
	// Post list_Toys lookup
	@RequestMapping(value = "/list_Toys", method = RequestMethod.GET)
	public String list_Toys(Model model, Criteria cri) throws Exception{
		logger.info("list_Toys");
		
		model.addAttribute("list_Toys",service.list_Toys(cri));
		
		PageMaker pageMaker = new PageMaker();
		pageMaker.setCri(cri);
		String category = "Toys";
		pageMaker.setTotalCount(service.listCount2("Toys"));
		
		model.addAttribute("pageMaker", pageMaker);
		
		return "board/list_Toys";
	}
		
	// Post list_Clothes lookup
	@RequestMapping(value = "/list_Clothes", method = RequestMethod.GET)
	public String list_Clothes(Model model, Criteria cri) throws Exception{
		logger.info("list_Clothes");
		
		model.addAttribute("list_Clothes",service.list_Clothes(cri));
		
		PageMaker pageMaker = new PageMaker();
		pageMaker.setCri(cri);
		pageMaker.setTotalCount(service.listCount2("Clothes"));
		
		model.addAttribute("pageMaker", pageMaker);
		
		return "board/list_Clothes";
	}
	
	// Post list_Fruits lookup
	@RequestMapping(value = "/list_Fruits", method = RequestMethod.GET)
	public String list_Fruits( Model model, Criteria cri) throws Exception{
		logger.info("list_Fruits");
		
		model.addAttribute("list_Fruits",service.list_Fruits(cri));
		
		PageMaker pageMaker = new PageMaker();
		pageMaker.setCri(cri);
		pageMaker.setTotalCount(service.listCount2("Fruits"));
		
		model.addAttribute("pageMaker", pageMaker);
		
		return "board/list_Fruits";
	}
	
	// Post list_Electronics lookup
	@RequestMapping(value = "/list_Electronics", method = RequestMethod.GET)
	public String list_Electronics( Model model, Criteria cri) throws Exception{
		logger.info("list_Electronics");
		
		model.addAttribute("list_Electronics",service.list_Electronics(cri));
		
		PageMaker pageMaker = new PageMaker();
		pageMaker.setCri(cri);
		
		pageMaker.setTotalCount(service.listCount2("Electronics"));
		
		model.addAttribute("pageMaker", pageMaker);
		
		return "board/list_Electronics";
	}

 

 

이제 list.jsp로 가 글쓰기 버튼 위에 다음 코드를 추가해준다.

<div>
	          
		          	

				  <ul class="page">
				    <c:if test="${pageMaker.prev}">
				    	<li><a href="list${pageMaker.makeQuery(pageMaker.startPage - 1)}">"<<"</a></li>
				    </c:if> 
				
				    <c:forEach begin="${pageMaker.startPage}" end="${pageMaker.endPage}" var="idx">
				    	<li><a href="list${pageMaker.makeQuery(idx)}">${idx}</a></li>
				    </c:forEach>
				
				    <c:if test="${pageMaker.next && pageMaker.endPage > 0}">
				    	<li><a href="list${pageMaker.makeQuery(pageMaker.endPage + 1)}">">>"</a></li>
				    </c:if> 
				  </ul>
				</div>
				
				<div class = "write_btn">
					<a href ="http://localhost:8080/board/writeView"><input type='button', value='글쓰기'/></a>
				</div>

 

 

 

 

내가 만들고자 했던 페이징 기능은 구글링을 해도 잘 나오지 않는다 ㅜㅜ

일단 다른 것들부터 먼저 만들고 목적에 맞게 수정해야겠다...

 

 


 

devlogofchris.tistory.com/30 (더미 데이터 만들기)

melonpeach.tistory.com/26?category=806570 (경고 팝업 기능)

melonpeach.tistory.com/27?category=806570 (페이징 기능 구현)