today_is
[ jsp 프로젝트 ] 게시판 기능 (검색 / script 를 이용한 무한스크롤) 본문
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 도구를 잘 다루는 것도 하나의 방법일 듯 하다 ㅠㅠ
인간은 도구 없이는 살 수 없 다 (합리화 아님 ^^)
- 진행사항
다음은 페이징을 이용한 게시글 작성에 돌입하겠다 !!
'project' 카테고리의 다른 글
[ jsp 프로젝트 ] 프로젝트 회고 (0) | 2023.12.22 |
---|---|
[ jsp 프로젝트 ] 게시글 저장 기능 (+ 대댓글) (0) | 2023.12.21 |
[ jsp 프로젝트 ] 게시글 작성 (+ FileUtil 을 이용한 이미지 업로드 / 페이징) (0) | 2023.12.21 |
[ jsp 프로젝트 ] 회원기능 (0) | 2023.12.18 |
[ jsp 프로젝트 ] 여행 커뮤니티 사이트 만들기 (0) | 2023.12.17 |