today_is

[ jsp 프로젝트 ] 게시판 기능 (검색 / script 를 이용한 무한스크롤) 본문

project

[ jsp 프로젝트 ] 게시판 기능 (검색 / script 를 이용한 무한스크롤)

ye_rang 2023. 12. 20. 09:22

내가 맡은 파트

 

 

BoardDTO

: deleted 컬럼은 check 제약조건을 이용하여 0 또는 1만 가능함

 

게시글을 삭제했을때, delete 가 아니라

update 를 통해서 deleted 컬럼의 값을 바꿀 것임

 

 

 

deleted = 0

: 기본값, 삭제되지 않은 게시물

 

deleted = 1

: 삭제한 게시물, 마이페이지에서 삭제한 본인 게시물을 볼 수 있도록 함

IDX NOT NULL NUMBER primary key
TITLE NOT NULL VARCHAR2(1000)  
IMAGE    VARCHAR2(3000)  
CATEGORY NOT NULL VARCHAR2(100)  
WRITER NOT NULL VARCHAR2(100) member 의 userid 참조
CONTENT NOT NULL VARCHAR2(4000)  
DELETED NOT NULL NUMBER default 0
WRITEDATE    DATE  

 

 

 

BoardDAO

package board;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;


public class BoardDAO {
   
   private Context init;
   private DataSource ds;
   
   private Connection conn;
   private PreparedStatement pstmt;
   private ResultSet rs;
   
   private static BoardDAO instance = new BoardDAO();
   
   public static BoardDAO getInstance() {
      return instance;
   }
   
   
   private BoardDAO() {
      try {
         init = new InitialContext();
         ds = (DataSource) init.lookup("java:comp/env/jdbc/oracle");
      } catch (NamingException e) {
         e.printStackTrace();
      }
   }
   
   private void close() {
      try {
         if(rs != null) rs.close();
         if(pstmt != null) pstmt.close();
         if(conn != null) conn.close();
      } catch (SQLException e) {}
   }
  
   private BoardDTO mapping(ResultSet rs) throws SQLException {
      BoardDTO dto = new BoardDTO();
      
      dto.setIdx(rs.getInt("idx"));
      dto.setTitle(rs.getString("title"));
      dto.setImage(rs.getString("image"));
      dto.setCategory(rs.getString("category"));
      dto.setWriter(rs.getString("writer"));
      dto.setContent(rs.getString("content"));
      dto.setWriteDate(rs.getDate("writeDate"));
      dto.setDeleted(rs.getInt("deleted"));
      return dto;
   }
   
  
   
   // 게시글 목록 불러오기
   public List<BoardDTO> selectList() {
      ArrayList<BoardDTO> list = new ArrayList<>();
      String sql = "select * from board "
            + " where "
            + " deleted = 0"
            + " order by idx desc";
      try {
         conn = ds.getConnection();
         pstmt = conn.prepareStatement(sql);
         rs = pstmt.executeQuery();
         while (rs.next()) {
            list.add(mapping(rs));
         }
      } catch (Exception e) {
         e.printStackTrace();
      }finally {close();}
      return list;
   }
   
   
   // 검색 목록 리스트
   public List<BoardDTO> selectSearchList(String search) {
      ArrayList<BoardDTO> list = new ArrayList<>();
      String sql = "select * from board "
            + " where "
            + " deleted = 0 and "
            + " (title like '%' || ? || '%' or "
            + " writer like '%' || ? || '%' or "
            + "   content like '%' || ? || '%') "
            + " order by idx desc";

      try {
         conn = ds.getConnection();
         pstmt = conn.prepareStatement(sql);
         pstmt.setString(1, search);
         pstmt.setString(2, search);
         pstmt.setString(3, search);
         rs = pstmt.executeQuery();
         while (rs.next()) {
            list.add(mapping(rs));
         }
      } catch (Exception e) {
         e.printStackTrace();
      }finally {close();}
      return list;
   }
   
   
//   INSERT INTO board (title, writer, content, image, category) VALUES (
//           '한라산 백록담', 'jeju4', '제주 한라산 백록담 /
//   제주에 간다면 꼭 가보기를 추천하는 백록담 1년 중 운해가 없는 날이 손에 꼽기 때문에 3대가 덕을 쌓아야 볼 수 있다는 말이 있다 살면서 한번쯤 가본다면 자연의 경치에 매료될 수 있는 장소이다', '백록담.jpg','관광');
//   
   // 게시글 작성하기
   public int insert(BoardDTO dto) {
      int row = 0;
      String sql = "insert into board (title, writer, content, image, category)"
            + "values (?, ?, ?, ?, ?)";
      
      try {
         conn = ds.getConnection();
         pstmt = conn.prepareStatement(sql);
         pstmt.setString(1, dto.getTitle());
         pstmt.setString(2, dto.getWriter());
         pstmt.setString(3, dto.getContent());
         pstmt.setString(4, dto.getImage());
         pstmt.setString(5, dto.getCategory());
         
         row = pstmt.executeUpdate();
      } catch (SQLException e) {
         e.printStackTrace();
      }finally {close();}
      return row;
   }
   
   
   
   // 단일 게시글 보기 (view) / 게시글 읽기
   public BoardDTO selectOne(int idx) {
      BoardDTO dto = null;
      String sql = "select * from board where idx = ?";
      
      try {
         conn = ds.getConnection();
         pstmt = conn.prepareStatement(sql);
         pstmt.setInt(1, idx);
         rs = pstmt.executeQuery();
         while (rs.next()) {
            dto = mapping(rs);
         }
      } catch (SQLException e) {
         e.printStackTrace();
      }finally {close();}
      return dto;
   }
   
   // 카테고리별로 게시글 불러오기
   public List<BoardDTO> selectListByCategory(String category){
      ArrayList<BoardDTO> list = new ArrayList<>();
      String sql = "select * from board where category = ?";
      
      try {
         conn = ds.getConnection();
         pstmt = conn.prepareStatement(sql);
         pstmt.setString(1, category);
         rs = pstmt.executeQuery();
         while (rs.next()) {
            list.add(mapping(rs));
         }
      } catch (Exception e) {
         e.printStackTrace();
      }finally {close();}
      return list;
   }
   
   

   // 게시글 수정하기
   public int update(BoardDTO dto) {
	   System.out.println(dto.getIdx());
	   System.out.println(dto.getWriter());
      int row = 0;
      String sql ="update board set title = ?, content = ? , image = ? , category = ?"
              + " where idx = ? and writer = ?";
      System.out.println(dto.getIdx());      
   
      try {
         conn = ds.getConnection();
         pstmt = conn.prepareStatement(sql);
         pstmt.setString(1, dto.getTitle());
         pstmt.setString(2, dto.getContent());
         pstmt.setString(3, dto.getImage());
         pstmt.setString(4, dto.getCategory());
         pstmt.setInt(5, dto.getIdx());
         pstmt.setString(6, dto.getWriter());
         row = pstmt.executeUpdate();
      } catch (SQLException e) {
         e.printStackTrace();
      }finally {close();}
      return row;
   }
   
   
    // 삭제 : update 쿼리문 사용하기 
    public int delete(int idx) {
         int row = 0;
    
         String sql = "update board set "
          + "   deleted = 1 - deleted "
          + "   where idx = ?";
    
         try {
            conn = ds.getConnection();
            pstmt = conn.prepareStatement(sql);
            pstmt.setInt(1, idx);
            row = pstmt.executeUpdate();
         } catch (Exception e) {
            e.printStackTrace();
         }
         finally {
            close();
         }
         return row;
      }
   
      
   // 내가 쓴 게시글
   public List<BoardDTO> selectListByWriter(String userid, Paging paging){
      ArrayList<BoardDTO> list = new ArrayList<>();
      String sql = "select * from board "
            + " where writer = ? "
            + "   order by idx desc "
            + "   offset ? rows "
            + "   fetch next ? rows only";
      try {
         conn = ds.getConnection();
         pstmt = conn.prepareStatement(sql);
         pstmt.setString(1, userid);
         pstmt.setInt(2, paging.getOffset());
         pstmt.setInt(3, paging.getFetch());
         rs = pstmt.executeQuery();
         while (rs.next()) {
            list.add(mapping(rs));
         }
      } catch (SQLException e) {
         e.printStackTrace();
      }finally {close();}
      return list;
   }
   
   
   // 게시글 개수 불러오는 함수
   public int selectCount(String userid) {
      int count = 0;
      String sql = "select count(*) from board "
            + " where writer = ? "
            + "   order by idx desc ";

      try {
         conn = ds.getConnection();
         pstmt = conn.prepareStatement(sql);
         pstmt.setString(1, userid);
         rs = pstmt.executeQuery();
         while (rs.next()) {
            count = rs.getInt(1);
         }
      } catch (SQLException e) {
         e.printStackTrace();
      }finally {close();}
      return count;
   }
   
   // 검색어에 따라 카운트 되는 카운트 함수
   public int selectSearchCount(String search) {
      int count = 0;
      String sql = "select count(*) from board "
            + " where "
            + "       deleted = 0 and"
            + "       (title like '%' || ? || '%' or "
            + "       writer like '%' || ? || '%' or "
            + "       content like '%' || ? || '%')   "
            + "   order by idx desc";


      try {
         conn = ds.getConnection();
         pstmt = conn.prepareStatement(sql);
         pstmt.setString(1, search);
         pstmt.setString(2, search);
         pstmt.setString(3, search);
         rs = pstmt.executeQuery();
         while (rs.next()) {
            count = rs.getInt(1);
         }
      } catch (SQLException e) {
         e.printStackTrace();
      }finally {close();}
      return count;
   }

}

 

 

대문페이지 - index.jsp

script 를 이용해서 무한 스크롤로 전체 게시물을 보여줌

: 무한스크롤은 5개씩 보여준다

 

 

 

검색기능

: form에 검색어를 입력하면, search 라는 변수명으로 저장

-> 검색기능을 처리하는 함수의 매개변수로 이용함

 

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ include file="header.jsp" %>


<div class="frame" id="root">
   
   <form action="search-action.jsp">
      <div class="sb">
         <p><input class="searchForm" type="search" placeholder="검색어를 입력하시오" name="search" value="${param.search }"></p>
         <p><input type="submit" value="검색"></p>
      </div>
   </form>
      
   <c:set var="searchCount" value="${boardDAO.selectSearchCount(param.search) }"></c:set>
   <c:set var="list" value="${boardDAO.selectList()}" />
   <c:forEach var="dto" items="${list }" varStatus="loop">
     
      <div class="flex root item hidden">
         <div class="imagebox">
           
            <a href="${cpath }/view.jsp?idx=${dto.idx}">
               <img src="${cpath }/reviewImage${dto.image}">
            </a>
         </div>
         <a style="display: block;" href="${cpath }/view.jsp?idx=${dto.idx}">
            <div class="imageboard">
               <p class="title">${dto.title }</p>
               <p class="content">${dto.content }</p>   
            </div>
         </a>
      </div>
   </c:forEach>
   
</div>

<script type="text/javascript">
    const root = document.getElementById('root');
    // #root 내부의 모든 item 클래스를 가진 요소들을 선택한다
    const items = document.querySelectorAll('#root .item');
    // 시작 인덱스를 초기화한다
    let start = 0;

    // hidden 걸린 item을 보여주는 함수
    function showHiddenItems() {
    	// 시작 인덱스부터 5개씩 숨겨진 아이템을 보여준다
        for (let i = start; i < items.length && i < start + 5; i++) {
            // hidden 클래스를 제거하여 해당 아이템을 보이게 만든다
            items[i].classList.remove('hidden')
        }
    	// 그 후 시작 인덱스를 업데이트 한다
        start += 5;
    }

    function scrollHandler() {
    	
    	// 스크롤 관련 정보를 ob에 저장한다
        const ob = {
            scrollTop: window.scrollY,			// 스크롤된 세로의 위치
            clientHeight: window.innerHeight,		// 브라우저에 보여지는 창의 높이
            scrollHeight: document.body.scrollHeight	// 문서 전체의 높이
        };
    	
		console.log(ob) // 스크롤 정보를 콘솔에 출력
// const currentSize = ob.scrollTop + ob.clientHeight;
// const flag = ob.scrollHeight + 1.2 <= currentSize && currentSize <= ob.scrollHeight * 1.5;
	
    		// 현재 화면에 맨 아래 도달했는지 체크 하는 조건 
		const flag = ob.scrollTop + ob.clientHeight > ob.scrollHeight
       		
            	// 만약 도달 했다면 추가로 불러오기 함수를 수행하도록 showHiddenItems를 호출
		if (flag) {
            console.log('추가 불러오기');
            showHiddenItems();
        }
    }
   // body의 스크롤 이벤트에 scrollHandler 함수를 연결
    document.body.onscroll = scrollHandler;
		
    showHiddenItems(); // 초기 로딩 시 한 번 숨겨진 아이템들을 풀어주도록 설정
</script>

</body>
</html>

 

 

검색기능 함수

: 검색 기능 sql 문

 

제목, 작성자, 글 내용에 [검색어가 포함] 되면 모두 출력됨

대신, 삭제되지 않은 게시물만 보여준다 ! (deleted = 0)

 

// 검색 목록 리스트
   public List<BoardDTO> selectSearchList(String search) {
      ArrayList<BoardDTO> list = new ArrayList<>();
      String sql = "select * from board "
            + " where "
            + " deleted = 0 and "
            + " (title like '%' || ? || '%' or "
            + " writer like '%' || ? || '%' or "
            + "   content like '%' || ? || '%') "
            + " order by idx desc";

      try {
         conn = ds.getConnection();
         pstmt = conn.prepareStatement(sql);
         pstmt.setString(1, search);
         pstmt.setString(2, search);
         pstmt.setString(3, search);
         rs = pstmt.executeQuery();
         while (rs.next()) {
            list.add(mapping(rs));
         }
      } catch (Exception e) {
         e.printStackTrace();
      }finally {close();}
      return list;
   }

 

 

 

카테고리별 게시글 목록  -  board.jsp

: 카테고리 별로 게시물을 보여줌

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ include file="header.jsp" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	
<section class="frame">
	<div>
		<jsp:useBean id="dto" class="board.BoardDTO"></jsp:useBean>
		<jsp:setProperty property="*" name="dto"/>
		<c:set var="list" value="${boardDAO.selectListByCategory(dto.category) }"></c:set>
		
		<c:forEach var="dto" items="${list }">
		
			<div class="flex">
				<div class="imagebox">	
					<a href="${cpath }/view.jsp?idx=${dto.idx}">
						<img src="${cpath }/reviewImage${dto.image}">
					</a>
				</div>
				<a style="display: block;" href="${cpath }/view.jsp?idx=${dto.idx}">
					<div class="imageboard">					
						<p class="title">${dto.title }</p>
						<p class="content">${dto.content }</p>
					</div>
            			</a>
			</div>
		</c:forEach>
	</div>
</section>
	
	

</body>
</html>

 

 

카테고리별 게시글 목록 함수

 // 카테고리별로 게시글 불러오기
   public List<BoardDTO> selectListByCategory(String category){
      ArrayList<BoardDTO> list = new ArrayList<>();
      String sql = "select * from board where category = ?";
      
      try {
         conn = ds.getConnection();
         pstmt = conn.prepareStatement(sql);
         pstmt.setString(1, category);
         rs = pstmt.executeQuery();
         while (rs.next()) {
            list.add(mapping(rs));
         }
      } catch (Exception e) {
         e.printStackTrace();
      }finally {close();}
      return list;
   }

 

 

 


review

 

- 어려웠던 부분 

 

아직 script 를 제대로 다룰줄 몰라서

무한 스크롤 코드를 작성할때 어려움을 겪었다

 

일부분은 chatGPT 의 도움을 받고 구현에 성공했다 ㅋㅋㅋㅋ

 

지피티 같은 ai 도구를 잘 다루는 것도 하나의 방법일 듯 하다 ㅠㅠ

 

인간은 도구 없이는 살 수 없 다 (합리화 아님 ^^)

 

 

 

- 진행사항

다음은 페이징을 이용한 게시글 작성에 돌입하겠다 !!