고래씌

[JSP] 5-4. 사진게시판(썸네일) 본문

Server/JSP과 Servlet

[JSP] 5-4. 사진게시판(썸네일)

고래씌 2023. 12. 13. 15:53

1. 사진게시판에 썸네일 리스트 만들기

▶ views-board 폴더에 thumbnailListView.jsp 파일 생성

■ thumbnailListView.jsp 

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" import="java.util.ArrayList, com.kh.board.model.vo.Board"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<style>
.list-area{
	width:760px;
	margin: 0 auto;
}
.outer{
	width:1000px;
	height: auto;
}
</style>
</head>
<body>
	<%@ include file="../common/menubar.jsp" %>
	
	<div class="outer">
		<br>
		<h2 align="center">사진게시판</h2>
		<br>
		
		<!-- 로그인한 사용자만 글작성이 보이도록 -->
		<% if(loginUser != null) { %>
			<div align="right" style="width:850px">
				<a href="<%= contextPath %>/insert.th" class="btn btn-secondary">글작성</a>
				<br>
				<br>
			</div>
		<% } %>
		
		<div class='list-area'>
			<%
				ArrayList<Board> list = (ArrayList<Board>) request.getAttribute("list");
			%>
			<%if(list.isEmpty()) { %> 
			<%-- 등록된 게시글이 없다면 --%>
				등록된 게시글이 없습니다.
			<% } else { %>
				<% for(Board b : list) { %>
					<div class="thumbnail" align="center">
						<%-- 썸네일 게시판 상세보기로 들어가면 BoardNo가 필요하기 때문에 hidden으로 게시판 번호를 넘겨줌 --%>
						<input type="hidden" value="<%= b.getBoardNo() %>">
						<img src="<%= contextPath %>/<%= b.getAttachment().getFilePath()
														+b.getAttachment().getChangeName() %>"
														width="200px" height="150px">
						<%-- b.getAttachment().getFilePath()+b.getAttachment().getChangeName() 
						     => 썸네일들의 경로를 가져옴 --%>
						<p>
							No.<%= b.getBoardNo() %> <%= b.getBoardTitle() %> <br>
							조회수 : <%=b.getCount() %>
						</p>
					</div>
				<% } %>
			<% } %>
		</div>
	</div>
</body>
</html>

 

 

▶ menubar.jsp 에 경로 추가

 

 

▶ common.css 파일에 style 속성 추가

 

 

▶ resources 폴더 아래에 thumbnail_upfiles 폴더 생성

- jpg 파일 저장되는 공간

 

 

=> FILE_LEVEL 은 썸네일에서만 사용하는 컬럼인데 파일레벨이 1인 것만 썸네일로 사용하도록 하겠다.

 

 

▶ Board 클래스에 Attachment 변수 추가(Builder 에도 추가)

=> 썸네일 관련 항목을 저장할 목적

package com.kh.board.model.vo;

import java.sql.Date;


public class Board {
//	BOARD_NO	NUMBER
	private int boardNo;

//	BOARD_TYPE	NUMBER
	private int boardType;

//	CATEGORY_NO	NUMBER
	private int categoryNo;

//	BOARD_TITLE	VARCHAR2(100 BYTE)
	private String boardTitle;

//	BOARD_CONTENT	VARCHAR2(4000 BYTE)
	private String boardContent;

//	BOARD_WRITER	NUMBER
	private String boardWriter;
	// 쿼리문으로 join시에는 회원번호를 활용하여 join할 것이고,
	// 조회결과 작성한 사용자의 이름 or id를 저장하기 위한 필드

//	COUNT	NUMBER
	private int count;

//	CREATE_DATE	DATE
	private Date createDate;

//	STATUS	VARCHAR2(1 BYTE)
	private String status;

	private String categoryName; // Board테이블에는 존재하지 않는 칼럼
	// DB에 Category 테이블에도 CATEGORY_NO가 있기 때문에 하나 생성 해둠

	public Attachment attachment;

	
	public Board() {

	}

	public static class Builder {

		private int boardNo;
		private int boardType;
		private int categoryNo;
		private String boardTitle;
		private String boardContent;
		private String boardWriter;
		private int count;
		private Date createDate;
		private String status;
		private String categoryName; // Board테이블에는 존재하지 않는 칼럼
		private Attachment attachment;

		public Board bulid() {
//			빌더에 초기화한 값을 그대로 Builder로 반환시켜줌

			// Board 타입 객체로 모두 옮겨놓음
			Board b = new Board();
			b.boardNo = boardNo;
			b.boardType = boardType;
			b.categoryNo = categoryNo;
			b.boardTitle = boardTitle;
			b.boardContent = boardContent;
			b.boardWriter = boardWriter;
			b.count = count;
			b.createDate = createDate;
			b.status = status;
			b.categoryName = categoryName;
			b.attachment = attachment;
			
			return b;
		}

		public Builder boardNo(int boardNo) {
			this.boardNo = boardNo;

			return this;
		}

		public Builder boardType(int boardType) {
			this.boardType = boardType;

			return this;
		}

		public Builder categoryNo(int categoryNo) {
			this.categoryNo = categoryNo;

			return this;
		}

		public Builder boardTitle(String boardTitle) {
			this.boardTitle = boardTitle;

			return this;
		}

		public Builder boardContent(String boardContent) {
			this.boardContent = boardContent;

			return this;
		}

		public Builder boardWriter(String boardWriter) {
			this.boardWriter = boardWriter;

			return this;
		}

		public Builder count(int count) {
			this.count = count;

			return this;
		}

		public Builder createDate(Date createDate) {
			this.createDate = createDate;

			return this;
		}

		public Builder status(String status) {
			this.status = status;

			return this;
		}

		public Builder categoryName(String categoryName) {
			this.categoryName = categoryName;

			return this;
		}
		
		public Builder attachment(Attachment attachment) {
			this.attachment = attachment;
			
			return this;
		}
	}

//	 똑같이 한 이유는 /...?
	
	
	@Override
	public String toString() {
		return "Board [boardNo=" + boardNo + ", boardType=" + boardType + ", categoryNo=" + categoryNo + ", boardTitle="
				+ boardTitle + ", boardContent=" + boardContent + ", boardWriter=" + boardWriter + ", count=" + count
				+ ", createDate=" + createDate + ", status=" + status + ", categoryName=" + categoryName
				+ ", attachment=" + attachment + "]";
	}
	

	public int getBoardNo() {
		return boardNo;
	}


	public void setBoardNo(int boardNo) {
		this.boardNo = boardNo;
	}

	public int getBoardType() {
		return boardType;
	}

	public void setBoardType(int boardType) {
		this.boardType = boardType;
	}

	public int getCategoryNo() {
		return categoryNo;
	}

	public void setCategoryNo(int categoryNo) {
		this.categoryNo = categoryNo;
	}

	public String getBoardTitle() {
		return boardTitle;
	}

	public void setBoardTitle(String boardTitle) {
		this.boardTitle = boardTitle;
	}

	public String getBoardContent() {
		return boardContent;
	}

	public void setBoardContent(String boardContent) {
		this.boardContent = boardContent;
	}

	public String getBoardWriter() {
		return boardWriter;
	}

	public void setBoardWriter(String boardWriter) {
		this.boardWriter = boardWriter;
	}

	public int getCount() {
		return count;
	}

	public void setCount(int count) {
		this.count = count;
	}

	public Date getCreateDate() {
		return createDate;
	}

	public void setCreateDate(Date createDate) {
		this.createDate = createDate;
	}

	public String getStatus() {
		return status;
	}

	public void setStatus(String status) {
		this.status = status;
	}

	public String getCategoryName() {
		return categoryName;
	}

	public void setCategoryName(String categoryName) {
		this.categoryName = categoryName;
	}
	
	public Attachment getAttachment() {
		return attachment;
	}

	public void setAttachment(Attachment attachment) {
		this.attachment = attachment;
	}

}

 

 

▶ board-mapper.xml 에 사진게시판 썸네일 list를 가져오는 쿼리문 작성

 

 

▶ ThumbnailListController.java

package com.kh.board.controller;

import java.io.IOException;
import java.util.ArrayList;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.kh.board.model.service.BoardService;
import com.kh.board.model.vo.Board;

/**
 * Servlet implementation class ThumbnailListController
 */
@WebServlet("/list.th")
public class ThumbnailListController extends HttpServlet {
	private static final long serialVersionUID = 1L;

	
    public ThumbnailListController() {
        super();
    }


	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// 사진게시판에 리스트에 필요한 데이터 조회
		// 게시판(board)정보와 썸네일(Attachment)정보
		ArrayList<Board> list = new BoardService().selectThumbnailList();
		
		request.setAttribute("list", list);
		
		request.getRequestDispatcher("views/board/thumbnailListView.jsp").forward(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doGet(request, response);
	}

}

 

 

 

▶ BoardService.java

 

 

 

▶ BoardDao.java

 

 


2. 사진게시판 작성하는 폼 만들기

▶ thumbnailEnrollForm.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<style>
#enroll-form>table{border:1px solid white;}
#enroll-form input, #enroll-form textarea{
	width:100%;
	box-sizing:border-box;
}
</style>
<body>
	<%@ include file="../common/menubar.jsp" %>
	
	<div class="outer">
		<br>
		<h2 align="center">사진게시판 작성</h2>
		<br>
		
		<form action="<%=contextPath %>/insert.th" method="post" 
			id="enroll-form" enctype="multipart/form-data">
			
			<!-- 현재 로그인한 사용자의 회원번호 전송 -->
			<input type="hidden" name="userNo" value="<%= loginUser.getUserNo() %>">
			<table align="center">
				<tr>
					<th width="100">제목</th>
					<td colspan="3"><input type="text" name="boardTitle" required></td>
				</tr>
				<tr>
					<th width="100">내용</th>
					<td colspan="3">
					<textarea name="boardContent" style="resize:none;" rows="5" required></textarea>
					</td>
				</tr>
				<tr>
					<!-- 썸네일로 등록될 영역 -->
					<th width="100">대표이미지</th>
					<td colspan="3" align="center">
						<img id="contentImg0" width='250' height='170'>
					</td>
				</tr>
				<tr>
					<!-- 현재이미지를 타고들어갔을 때 상세이미지 -->
					<th width="100">상세이미지</th>
					<td>
						<img id="contentImg1" width='150' height='120'>
					</td>
					<td>
						<img id="contentImg2" width='150' height='120'>
					</td>
					<td>
						<img id="contentImg3" width='150' height='120'>
					</td>
				</tr>
			</table>
			
			<!-- id가 contentImg1 클릭하면 file0인 것 클릭, contentImg2 클릭하면 file1인 것 클릭되도록 설정 -->
			<div id="file-area">
				<input type="file" id="file0" name="file0" required>
				<input type="file" id="file1" name="file1">
				<input type="file" id="file2" name="file2">
				<input type="file" id="file3" name="file3">
			</div>
			
			<script>
				$(function(){
                	// 첨부파일 선택 숨기기
					$("#file-area").hide();
					// $("#contentImg0").click(() => $("#file1").click());
					
					
					/* id가 contentImg로 시작하는 img태그를 모두 가져오겠다 */
					$("img[id^=contentImg]").each(function(index, value) {
						$(value).click(function(){  // contextImg1을 클릭하게되면(value=>contentImg1~3) file0 클릭되도록 반복문 수행
							$("#file"+index).click();  
						});
					});
					
					$("input[type=file]").each(function(index, value) {
						$(value).change(function(){loadImg(value,index)}) ;
						//loadImg(value,index) 하게되면 제대로 호출이 안돼서 익명함수로 묶어줌
					}) 
				})
				
				// 미리보기 이벤트
				function loadImg(file,index){
					// file : 현재 변화가 생긴 input type="file" 요소 객체
					// index : 몇번째 file에 변화가 발생했는지 확인 후 그 영역에 미리보기를 해주기 위한 변수
					console.log(file.files[0]);  // 파일명
					console.dir(file);  // input#file0~4
					
					if(file.files[0]){
						// 선택된 파일이 존재할 경우
						// 존재하지 않는다면 undefind반환
						
						// 파일을 읽어들일 FileReader 객체 생성
						const reader = new FileReader();
						
						// 파일을 읽어들일 수 있는 메소드
						// readAsDataURL(파일) => 파일을 읽어들이는 순간 해당 파일만의
						// 고유한 URL이 부여됨 => 미리보기로 현재 부여된 url을 src속성값으로 추가
						reader.readAsDataURL(file.files[0]);
						
						// 파일 읽기가 완료되었을 때 실행할 함수 정의
						reader.onload = function(e){
							// e == event
							// event.target.result에 각 파일의 고유한 url 값이 담긴다.
							$("#contentImg"+index).attr("src",e.target.result);  // 추가하고자하는 src의 url 값 추가			
						}
					}else {
						// 선택했던 파일이 사라졌을 경우. 파일선택 클릭후 취소버튼 눌렀을 때
						$('#contentImg'+index).removeAttr("src");  // src 속성 제거. url 제거한다.
					}
				}
			</script>
			
			<br>
			<div align="center">
				<button>등록</button>
			</div>
		</form>
	</div>

</body>
</html>

 

 

- readAsDataURL(파일) => 파일을 읽어들이는 순간 해당 파일만의 고유한 URL이 부여된다. 미리보기로 현재 부여된 url을 src 속성값으로 추가

 

 

- 파일선택을 클릭하여 파일을 추가하게되면(바뀌게 되면) fuction loadImg 함수 실행

$("input[type=file]").each(function(index, value) {
$(value).change(function(){loadImg(value,index)}) ;
      //loadImg(value,index) 하게되면 제대로 호출이 안돼서 익명함수로 묶어줌
}) 

 

 

- file.files[0]  => list에 index가 하나라도 추가되면(첨부된 파일이 있다면) 그 값을 가져온다.(파일첨부에는 각각 하나의 파일밖에 못가져오니까 files[0] 임

 

 

 

▶ ThumbnailInsertController.java

package com.kh.board.controller;

import java.io.IOException;
import java.util.ArrayList;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.tomcat.util.http.fileupload.servlet.ServletFileUpload;

import com.kh.board.model.service.BoardService;
import com.kh.board.model.vo.Attachment;
import com.kh.board.model.vo.Board;
import com.kh.common.MyFileRenamePolicy;
import com.oreilly.servlet.MultipartRequest;

/**
 * Servlet implementation class ThumbnailInsertController
 */
@WebServlet("/insert.th")
public class ThumbnailInsertController extends HttpServlet {
	private static final long serialVersionUID = 1L;
       

    public ThumbnailInsertController() {
        super();
    }


	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
		request.getRequestDispatcher("views/board/thumbnailEnrollForm.jsp").forward(request, response);
	}

	// 등록기능이 들어갈 예정
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		request.setCharacterEncoding("UTF-8");
		
		if(ServletFileUpload.isMultipartContent(request)) {
			
			int maxSize = 20 * 1024 * 1024;   // 20mbyte
			
			// 사진 저장할 파일의 물리적인 경로
			String savePath = request.getSession().getServletContext().getRealPath("/resources/thumbnail_upfiles/");
						// 절대경로를 얻어옴
			
			MultipartRequest multi = new MultipartRequest(request, savePath, maxSize, "UTF-8", new MyFileRenamePolicy());
		
			// DB에 전달할 데이터 추출
			// BOARD - 게시글 작성자, 제목, 내용
			Board b = new Board.Builder()
					  .boardWriter(multi.getParameter("userNo"))
					  .boardTitle(multi.getParameter("boardTitle"))
					  .boardContent(multi.getParameter("boardContent"))
					  .bulid();
			
			// ATTACHMENT 테이블에 여러번 insert할 데이터 뽑기(최소 1번 이상)
			ArrayList<Attachment> list = new ArrayList();
			
			for(int i=0; i<4; i++) { // 4회 반복
				// file0, file1, file2, file3  => name 속성값
				String key = "file"+i;
				
				if(multi.getOriginalFileName(key) != null) {
					// 첨부파일이 있는 케이스
					// Attachment 객체 생성 + 원본명, 수정명, 저장경로, 파일레벨 담아줄 예정
					Attachment at = new Attachment();
					at.setOriginName(multi.getOriginalFileName(key));
					
					at.setChangeName(multi.getFilesystemName(key));
					// file0으로 넘어온 데이터가 실제 웹사이트에 저장된 이름을 반환해줌
					
					at.setFilePath("resources/thumbnail_upfiles/");
					
					if(i == 0) {
						at.setFileLevel(1);  // 썸네일
					}else {
						at.setFileLevel(2);  // 대표이미지로 설정 X
					}
					
					list.add(at);
				}
			}
			
			int result = new BoardService().insertThumbnailBoard(b,list);
			
			if(result > 0) {
				// 성공시에는 list.th 재요청
				request.getSession().setAttribute("alertMsg", "업로드 완료");
				response.sendRedirect("list.th");  // 상대경로
			}else {
				request.setAttribute("errorMsg", "업로드 실패");
				request.getRequestDispatcher("views/common/errorPage.jsp").forward(request, response);
			}
		}
	}

}

 

 

 

▶ BoardService.java

 

 

▶ board-mapper.xml

 

 

 

▶ BoardDao.java

 

 

 

 

 


3. 사진게시판 상세보기

■ thumbnailDetailView.java

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" import="com.kh.board.model.vo.*, java.util.ArrayList"%>
<%
	Board b = (Board) request.getAttribute("b");
	ArrayList<Attachment> list = (ArrayList<Attachment>) request.getAttribute("list");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<%@ include file="../common/menubar.jsp" %>
	
	<div class="outer">
		<br>
		<h2 align="center">사진게시판 상세보기</h2>
		<br>
		
		<table class="detail-area" align="center">
			<tr>
				<td width="70">제목</td>
				<td colspan="3" width="600"><%= b.getBoardTitle() %></td>
			</tr>
			<tr>
				<td>작성자</td>
				<td><%= b.getBoardWriter() %></td>
				<td>작성일</td>
				<td><%= b.getCreateDate() %></td>
			</tr>
			<tr>
				<td>내용</td>
				<td colspan="3">
					<p style="height:50px;"><%= b.getBoardContent() %></p>
				</td>
			</tr>
			<tr>
				<td>대표사진</td>
				<td colspan="3">
					<div>
						<img src="<%= contextPath %>/<%= list.get(0).getFilePath() + list.get(0).getChangeName() %>"
						width="500" height="300">
						<!-- list.get(0)  => 대표사진 -->
					</div>
				</td>
			</tr>
			<tr>
				<td>상세사진</td>
				<td colspan="3">
				<% for(int i=1; i<list.size(); i++) { %>
					<img src="<%= contextPath %>/<%= list.get(i).getFilePath() + list.get(i).getChangeName() %>"
						width="200" height="150">
				<% } %>
				<!-- 등록한 상세이미지 만큼만 반복적으로 사진 추가됨 -->
				</td>
			</tr>
		</table>
	</div>

</body>
</html>

 

 

 

■ thumbnailListView.java

		<script>
			$(function(){
				$(".thumbnail").click(function(){
					// 자식 요소들 중 하나를 가져옴
					location.href = "<%= contextPath%>/detail.th?bno="+$(this).children().eq(0).val();
				})
			}
		</script>

 

 

 

▶ 우리는 5-1. 게시판 만들기에서 사용하였던 SQL "selectAttachment"와 "selectBoard"를 이용하겠다.

 

 

▶ ThumbnailDetailController.java

package com.kh.board.controller;

import java.io.IOException;
import java.util.ArrayList;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.kh.board.model.service.BoardService;
import com.kh.board.model.vo.Attachment;
import com.kh.board.model.vo.Board;

/**
 * Servlet implementation class ThumbnailDetailController
 */
@WebServlet("/detail.th")
public class ThumbnailDetailController extends HttpServlet {
	private static final long serialVersionUID = 1L;
       

    public ThumbnailDetailController() {
        super();
    }


	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		int boardNo = Integer.parseInt(request.getParameter("bno"));
		
		int result = new BoardService().increaseCount(boardNo); 
		// 이미 만들었던 조회수 증가서비스 이용
		
		String url = "";
		
		if(result > 0) {
			// 게시판 번호 조회
			Board b = new BoardService().selectBoard(boardNo);
			
			// 이미지 정보 가져옴
			ArrayList<Attachment> list = new BoardService().selectAttachmentList(boardNo);
			
			request.setAttribute("b", b);
			request.setAttribute("list", list);
			
			System.out.println(b);
			System.out.println(list);
			
			url = "views/board/thumbnailDetailView.jsp";
			
		}else {
			request.setAttribute("errorMsg", "사진 게시글 조회 실패");
			url = "views/common/errorPage.jsp";
		}
		
		request.getRequestDispatcher(url).forward(request, response);
	}


	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doGet(request, response);
	}

}

 

▶ BoardService.java

 

 

▶ BoardDao.java