더보기
Servlet/JSP의 사진 게시판(Board)를 만들어 보자
사진 게시판
✔️ 게시글 작성, 게시판 전체 조회, 게시판 상세 조회, 수정, 삭제
*게시글 등록
menubar.jsp
👉🏻 페이징 처리는 일반 게시판 참고하세요!
<div class="nav-area" align="center">
<!-- (div.menu>a)*4 + Enter -->
<div class="menu"><a href="<%= contextPath %>">HOME</a></div>
<div class="menu"><a href="<%= contextPath %>/list.no">공지사항</a></div>
<div class="menu"><a href="<%= contextPath %>/list.bo?currentPage=1">일반게시판</a></div>
<div class="menu"><a href="<%= contextPath %>/list.th">사진게시판</a></div>
</div>
thumbnailListView.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>
<style>
.outer {
background-color: black;
color : white;
width : 1000px;
height : 1000px;
margin : auto;
margin-top : 50px;
}
.list-area {
width : 760px;
margin : auto;
}
.thumbnail {
border : 1px solid white;
width : 220px;
display : inline-block; /* 가로로 배치, 그냥 inline은 속성 안 먹힘 */
margin : 14px;
}
.thumbnail:hover {
cursor : pointer;
opacity : 0.7; /* 투명도 조절해서 마우스 올렸을 때 살짝 흐려지게 보이도록 */
}
</style>
</head>
<body>
<%@ include file="../common/menubar.jsp" %>
<div class="outer">
<br>
<h2 align="center">사진 게시판</h2>
<br>
<% if(loginUser != null) { %>
<!--
로그인한 회원만 보이는 버튼
a href 태그 뒤에 절대경로로 <%= contextPath %>/enrollForm.th 기재해도 무방!
-->
<div style="width:850px" align="right">
<a href="enrollForm.th" class="btn btn-secondary">글작성</a>
</div>
<% } %>
<br><br>
<div class="list-area">
<div class="thumbnail" align="center">
<img src="" width="200px" height="150px">
<p>
No.123 제목입니다. <br>
조회수: 230
</p>
</div>
<div class="thumbnail" align="center">
<img src="" width="200px" height="150px">
<p>
No.123 제목입니다. <br>
조회수: 230
</p>
</div>
<div class="thumbnail" align="center">
<img src="" width="200px" height="150px">
<p>
No.123 제목입니다. <br>
조회수: 230
</p>
</div>
<div class="thumbnail" align="center">
<img src="" width="200px" height="150px">
<p>
No.123 제목입니다. <br>
조회수: 230
</p>
</div>
<div class="thumbnail" align="center">
<img src="" width="200px" height="150px">
<p>
No.123 제목입니다. <br>
조회수: 230
</p>
</div>
<div class="thumbnail" align="center">
<img src="" width="200px" height="150px">
<p>
No.123 제목입니다. <br>
조회수: 230
</p>
</div>
<div class="thumbnail" align="center">
<img src="" width="200px" height="150px">
<p>
No.123 제목입니다. <br>
조회수: 230
</p>
</div>
</div>
</div>
</body>
</html>
ThumbnailListController 서블릿 생성
👉🏻 url mapping: /list.th
package com.kh.board.controller;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class ThumbnailListController
*/
@WebServlet("/list.th")
public class ThumbnailListController extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public ThumbnailListController() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.getRequestDispatcher("views/board/thumbnailListView.jsp").forward(request, response);
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
사진 게시판 폼 만들고 서블릿으로 포워딩까지 함!
ThumbnailEnrollFormController 서블릿 생성
👉🏻 url mapping: /enrollForm.th
package com.kh.board.controller;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class ThumbnailEnrollFormController
*/
@WebServlet("/enrollForm.th")
public class ThumbnailEnrollFormController extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public ThumbnailEnrollFormController() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.getRequestDispatcher("views/board/thumbnailEnrollForm.jsp").forward(request, response);
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
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>
<style>
.outer {
background-color: black;
color : white;
width : 1000px;
height : 700px;
margin : auto;
margin-top : 50px;
}
#enroll-form>table {border : 1px solid white; }
#enroll-form input, #enroll-form textarea {
width : 100%;
box-sizing : border-box; /* 내가 지정한 길이는 border 포함 길이임을 알려 줌 */
}
</style>
</head>
<body>
<%@ include file="../common/menubar.jsp" %>
<div class="outer">
<br>
<h2 align="center">사진 게시판 작성하기</h2>
<br>
<!--
길이가 얼마나 될지 모르는 게시판은 post 형식이 좋음
사진 게시판에는 적어도 1개 이상의 첨부파일이 꼭 들어가야 함! enctype 속성 넣어 주기
-->
<form id="enroll-form" action="<%= contextPath %>/insert.th" method="post" enctype="multipart/form-data">
<!-- 작성자의 회원번호도 같이 넘기기 -->
<input type="hidden" name="userNo" value="<%= loginUser.getUserNo() %>">
<table align="center">
<!--
(tr>th+td+td+td)*4 + Enter
name 속성은 추후 키값이 됨!
테이블 확인 후 not null이라면 required 속성 걸어 주기
-->
<tr>
<th width="100"> 제목</th>
<td colspan="3"><input type="text" name="title" required></td>
</tr>
<tr>
<th>내용</th>
<td colspan="3"><textarea name="content" rows="5" style="resize:none;" required></textarea></td>
</tr>
<!-- 첨부파일 이미지 미리 보기 폼 -->
<tr>
<th>대표 이미지</th> <!-- 필수 -->
<td colspan="3">
<img id="titleImg" width="250" height="170">
</td>
</tr>
<tr>
<th>상세이미지</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>
<!--
img는 단순히 사진을 보여 주는 용도
원하는 사진 파일을 서버로 보내려면 input type="file"이 필요함 (form 내부에)
-->
<div id="file-area">
<!-- (input[type=file id=file$ name=file$])*4 -->
<input type="file" id="file1" name="file1" onchange="loadImg(this, 1);" required> <!-- 대표 이미지 업로드용(대표이미지인 썸네일은 필수) -->
<input type="file" id="file2" name="file2" onchange="loadImg(this, 2);"> <!-- 상세 이미지 업로드용 -->
<input type="file" id="file3" name="file3" onchange="loadImg(this, 3);">
<input type="file" id="file4" name="file4" onchange="loadImg(this, 4);">
<!-- onchange 메소드: input 태그의 내용물이 변경될 시 발생하는 이벤트 속성(change 이벤트) -->
<!-- loadImg() : 내가 직접 만든 선언적 함수, 매개변수 this: 이벤트 당한 요소, 1: input 태그의 위치값 (구분 용도)-->
</div>
<br><br>
<script>
$(function() {
$("#file-area").hide();
$("#titleImg").click(function () {
$("#file1").click();
});
$("#contentImg1").click(function () {
$("#file2").click();
});
$("#contentImg2").click(function () {
$("#file3").click();
});
$("#contentImg3").click(function () {
$("#file4").click();
});
});
function loadImg(inputFile, num) {
// inputfile: 현재 변화가 생긴 input type="file"요소 객체
// num : 몇 번째 input 요소인지 확인 후 해당 그 영역에 미리보기 하기 위한 변수
// input type="file" 요소 객체는 내부적으로 files라는 속성을 가지고 있음
// => 현재 이 input 태그로 선택된 파일들의 정보를 배열 형식으로 가지고 있음
console.log(inputFile.files.length);
// 파일 선택 시 1, 파일 취소 시 0이 출력됨
// => 즉, 파일의 존재 유무를 알 수 있음
if(inputFile.files.length == 1) { // 선택된 파일이 있을 경우
// 선택된 파일을 읽어들여서 그 영역에 맞는 곳에 미리보기 기능 추가
// 파일을 읽어들일 FileReader 객체 생성
var reader = new FileReader();
// 파일을 읽어들이는 메소드 속성을 호출
// => 어느 파일을 읽어들일 건지 그 파일의 정보 자체를 매개변수로 제시해야 함
// => inputFile.files라는 배열의 0번째 인덱스에 파일 정보가 담겨 있음
reader.readAsDataURL(inputFile.files[0]);
// => 해당 파일을 읽어들이는 순간 그 파일만의 고유한 url 주소가 하나 부여됨(FileReader 객체의 result 속성에)
// == 해당 이미지의 고유 url 주소(이미지 주소 복사할 때 뜨는 url)가 하나 만들어지는 꼴임
// => 이 고유한 url 주소를 각 img 태그의 src 속성으로 부여
// 파일 읽기가 완료되었을 때 실행할 함수를 정의
reader.onload = function(e) {
// e: 현재 발생한 이벤트의 정보(이벤트 객체)
// e.target: 현재 이벤트가 발생된 요소(이벤트를 당한 요소객체)
// e.target == reader == this
// $("#titleImg").attr("src", e.target.result);
// 각 영역에 맞춰서 이미지 미리보기
switch(num) {
case 1 : $("#titleImg").attr("src", e.target.result); break;
case 2 : $("#contentImg1").attr("src", e.target.result); break;
case 3 : $("#contentImg2").attr("src", e.target.result); break;
case 4 : $("#contentImg3").attr("src", e.target.result); break;
}
};
} else { // 선택된 파일이 사라졌을 경우
// 미리보기 이미지를 사라지게 하기 => src 속성에 null 대입
switch(num) {
case 1 : $("#titleImg").attr("src", null); break;
case 2 : $("#contentImg1").attr("src", null); break;
case 3 : $("#contentImg2").attr("src", null); break;
case 4 : $("#contentImg3").attr("src", null); break;
}
}
}
</script>
<div align="center">
<button type="submit">등록하기</button>
</div>
</form>
</div>
</body>
</html>
ThumbnailInsertController 서블릿 생성
👉🏻 url mapping: /insert.th
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;
/**
* @see HttpServlet#HttpServlet()
*/
public ThumbnailInsertController() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 인코딩 설정
request.setCharacterEncoding("UTF-8");
// 이 요청이 multipart/form-data 형식인지 먼저 검사
if(ServletFileUpload.isMultipartContent(request)) {
// 1. 전달된 파일에 대한 정보 먼저 지정 (전송파일 용량 제한, 지정할 파일의 물리적인 경로)
// 1_1. 용량 제한
int maxSize = 10 * 1024 * 1024;
// 1_2. 저장할 파일의 물리적인 경로
String savePath = request.getSession().getServletContext().getRealPath("/resources/thumbnail_upfiles/");
// 2. 전달된 파일명 수정 작업 후 서버에 업로드 + MultipartRequest 타입으로 변환
MultipartRequest multiRequest = new MultipartRequest(request, savePath, maxSize, "UTF-8", new MyFileRenamePolicy());
// MultipartRequest로 바꿀 request 넣어 주고, 사진 저장할 경로 savePath 넣어 주고, 최대 용량 넣어 주고, 인코딩, 파일명 수정작업
// 3. DB에 전달할 값 뽑기
// Board에 Insert => userNo, title, content
Board b = new Board();
b.setBoardWriter(multiRequest.getParameter("userNo"));
b.setBoardTitle(multiRequest.getParameter("title"));
b.setBoardContent(multiRequest.getParameter("content"));
// Attachment에 Insert
// 단, 여러 개의 첨부파일이 있을 예정!
// => ArrayList<Attachment>에 담기 (최소 1개~ 최대 4개)
ArrayList<Attachment> list = new ArrayList<>();
for(int i = 1; i <= 4; i++) { // i: 1, 2, 3, 4
// 키값 먼저 세팅
String key = "file" + i; // key: "file1", "file2", "file3", "file4"
// 해당 키값에 대한 첨부파일이 있다면 처리!
if(multiRequest.getOriginalFileName(key) != null) { // 첨부파일이 존재할 경우
// Attachment 객체 생성
// 원본명, 수정명, 폴더경로, 파일레벨
Attachment at = new Attachment();
at.setOriginName(multiRequest.getOriginalFileName(key));
at.setChangeName(multiRequest.getFilesystemName(key));
at.setFilePath("resources/thumbnail_upfiles/");
if(i == 1) { // 대표 이미지일 경우 => 1
at.setFileLevel(1);
} else { // 상세 이미지일 경우 => 2
at.setFileLevel(2);
}
list.add(at);
}
}
// 현재 list에는 첨부파일이 차곡차곡 담긴 상태임
// Service 단으로 요청 후 결과 받기
int result = new BoardService().insertThumbnailBoard(b, list);
// 결과에 따른 응답 페이지 지정
if(result > 0) { // 성공 => 사진 게시판 리스트 url(list.th)로 재요청
request.getSession().setAttribute("alertMsg", "성공적으로 사진 게시글이 업로드되었습니다");
response.sendRedirect(request.getContextPath() + "/list.th");
} else { // 실패 => 에러 문구 담아서 에러페이지 포워딩
request.setAttribute("errorMsg", "사진 게시판 업로드 실패");
request.getRequestDispatcher("views/common/errorPage.jsp").forward(request, response);
}
}
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
thumbnail_upfiles 폴더 생성
👉🏻 사진게시판에 사람들이 올리는 파일들만 저장할 수 있게끔
BoardService
public int insertThumbnailBoard(Board b, ArrayList<Attachment> list) {
Connection conn = getConnection();
// 각각 b와 list를 insert 할 수 있는 요청 보내기
// list는 bno을 참조해야 하기 때문에 "b부터 진행"해야 함!!
int result1 = new BoardDao().insertThumbnailBoard(conn, b);
int result2 = new BoardDao().insertAttachmentList(conn, list);
if(result1 > 0 && result2 > 0) {
commit(conn);
} else {
rollback(conn);
}
close(conn);
return result1 * result2;
}
BoardDao
public int insertThumbnailBoard(Connection conn, Board b) {
// INSERT문 => int (처리된 행의 개수)
int result = 0;
PreparedStatement pstmt = null;
String sql = prop.getProperty("insertThumbnailBoard");
try {
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, b.getBoardTitle());
pstmt.setString(2, b.getBoardContent());
pstmt.setInt(3, Integer.parseInt(b.getBoardWriter()));
result = pstmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
close(pstmt);
}
return result;
}
public int insertAttachmentList(Connection conn, ArrayList<Attachment> list) {
// INSERT문 여러 번 => int (처리된 행의 개수)
int result = 1;
PreparedStatement pstmt = null;
String sql = prop.getProperty("insertAttachmentList");
try {
// DAO 메소드 하나로 동일한 쿼리문을 여러 번 실행해야 함
// => 쿼리문을 실행할 때마다 pstmt를 생성해야 함
// => list에 담긴 Attachment의 개수만큼 반복 돌리기
// list에서 하나씩 뽑아서 at에 담겠다
for(Attachment at : list) {
pstmt = conn.prepareStatement(sql);
// 쿼리문 완성시키기
pstmt.setString(1, at.getOriginName());
pstmt.setString(2, at.getChangeName());
pstmt.setString(3, at.getFilePath());
pstmt.setInt(4, at.getFileLevel());
// 쿼리문 실행 후 결과 받기(결과를 누적곱으로 => 하나라도 실패하면 0, 시작(초기화)값은 1이 되어야 함!)
result *= pstmt.executeUpdate();
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
close(pstmt);
}
return result;
}
board-mapper.xml
<entry key="insertThumbnailBoard">
INSERT INTO BOARD (BOARD_NO
, BOARD_TYPE
, BOARD_TITLE
, BOARD_CONTENT
, BOARD_WRITER)
VALUES (SEQ_BNO.NEXTVAL
, 2
, ?
, ?
, ?)
</entry>
<entry key="insertAttachmentList">
INSERT INTO ATTACHMENT (FILE_NO
, REF_BNO
, ORIGIN_NAME
, CHANGE_NAME
, FILE_PATH
, FILE_LEVEL)
VALUES (SEQ_FNO.NEXTVAL
, SEQ_BNO.CURRVAL
, ?
, ?
, ?
, ?)
</entry>
*게시판 전체 조회
Board
👉🏻 titleimg 필드, getter/setter 메소드 추가
// 필드부
private String titleImg;
// 메소드부
public String getTitleImg() {
return titleImg;
}
public void setTitleImg(String titleImg) {
this.titleImg = titleImg;
}
ThumbnailListController
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 사진 게시판 리스트페이지에 필요한 데이터를 먼저 조회해 와야 함
ArrayList<Board> list = new BoardService().selectThumbnailList();
request.setAttribute("list", list);
request.getRequestDispatcher("views/board/thumbnailListView.jsp").forward(request, response);
}
BoardService
public ArrayList<Board> selectThumbnailList() {
Connection conn = getConnection();
ArrayList<Board> list = new BoardDao().selectThumbnailList(conn);
close(conn);
return list;
}
BoardDao
public ArrayList<Board> selectThumbnailList(Connection conn) {
// SELECT문 => ResultSet 타입의 객체로 리턴 (여러 행 조회)
ArrayList<Board> list = new ArrayList<>();
PreparedStatement pstmt = null;
ResultSet rset = null;
String sql = prop.getProperty("selectThumbnailList");
try {
pstmt = conn.prepareStatement(sql);
rset = pstmt.executeQuery();
while(rset.next()) {
Board b = new Board();
b.setBoardNo(rset.getInt("BOARD_NO"));
b.setBoardTitle(rset.getString("BOARD_TITLE"));
b.setCount(rset.getInt("COUNT"));
b.setTitleImg(rset.getString("TitleImg"));
list.add(b);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
close(rset);
close(pstmt);
}
return list;
}
board-mapper.xml
<entry key="selectThumbnailList">
SELECT BOARD_NO
, BOARD_TITLE
, COUNT
, FILE_PATH || CHANGE_NAME "TITLEIMG"
FROM BOARD B
JOIN ATTACHMENT ON (BOARD_NO = REF_BNO)
WHERE BOARD_TYPE = 2
AND B.STATUS = 'Y'
AND FILE_LEVEL = 1
ORDER BY BOARD_NO DESC
</entry>
thumbnailListView
👉🏻 상단 부분 Board 타입 ArrayList 선언, import
👉🏻 list-area 부분 정적 코딩을 동적 코딩으로 바꿔 줌 (반복문 돌리기)
// 페이지 정보 (상단)
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" import="java.util.ArrayList, com.kh.board.model.vo.Board" %>
<%
ArrayList<Board> list = (ArrayList<Board>)request.getAttribute("list");
%>
// list-area 부분 정적 코딩을 동적 코딩으로 바꿔 줌
<div class="outer">
<br>
<h2 align="center">사진 게시판</h2>
<br>
<% if(loginUser != null) { %>
<!--
로그인한 회원만 보이는 버튼
a href 태그 뒤에 절대경로로 <%= contextPath %>/enrollForm.th 기재해도 무방!
-->
<div style="width:850px" align="right">
<a href="enrollForm.th" class="btn btn-secondary">글작성</a>
</div>
<% } %>
<br><br>
<div class="list-area">
<!--
<div class="thumbnail" align="center">
<img src="" width="200px" height="150px">
<p>
No.123 제목입니다. <br>
조회수: 230
</p>
</div>
<div class="thumbnail" align="center">
<img src="" width="200px" height="150px">
<p>
No.123 제목입니다. <br>
조회수: 230
</p>
</div>
<div class="thumbnail" align="center">
<img src="" width="200px" height="150px">
<p>
No.123 제목입니다. <br>
조회수: 230
</p>
</div>
<div class="thumbnail" align="center">
<img src="" width="200px" height="150px">
<p>
No.123 제목입니다. <br>
조회수: 230
</p>
</div>
<div class="thumbnail" align="center">
<img src="" width="200px" height="150px">
<p>
No.123 제목입니다. <br>
조회수: 230
</p>
</div>
<div class="thumbnail" align="center">
<img src="" width="200px" height="150px">
<p>
No.123 제목입니다. <br>
조회수: 230
</p>
</div>
<div class="thumbnail" align="center">
<img src="" width="200px" height="150px">
<p>
No.123 제목입니다. <br>
조회수: 230
</p>
</div>
-->
<% if(!list.isEmpty()) { %>
<% for(Board b : list) { %>
<div class="thumbnail" align="center">
<input type="hidden" value="<%= b.getBoardNo() %>">
<img src="<%= contextPath %>/<%= b.getTitleImg() %>" width="200px" height="150px">
<p>
No.<%= b.getBoardNo() %> <%= b.getBoardTitle() %> <br>
조회수 : <%= b.getCount() %>
</p>
</div>
<% } %>
<% } else { %>
등록된 게시글이 없습니다
<% } %>
</div>
<script>
$(function() {
$(".thumbnail").click(function() {
location.href = "<%= contextPath %>/detail.th?bno=" + $(this).children().eq(0).val();
/*
p 태그 안에 있던 No. 뒤 글 번호를 span 태그로 감싼 뒤 탐색 메소드 활용하여 불러와도 되고,
div에 input type="hidden"으로 글 번호를 따로 한 번 더 만들어서 숨겨 줘도 됨
이번은 input type="hiddne"을 사용함!
"class값 thumbnail인 div 클릭 시, 해당 영역 자식 중 첫 번째의 값의 value(== b.getBoardNo())을 가지고 와라"
=> 이 방법으로 글 번호를 구할 수 있음!
*/
});
});
</script>
</div>
*게시글 상세 조회
thumbnailDetailView.jsp 생성
👉🏻 경로: WebContent\views\board\thumbnailDetailView.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" import="java.util.ArrayList, com.kh.board.model.vo.*"%>
<%
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>
<style>
.outer {
background-color : black;
color : white;
width : 1000px;
height : 800px;
margin : auto;
margin-top : 50px;
}
.detail-area td {
border : 1px solid white;
text-align : center;
}
</style>
</head>
<body>
<%@ include file="../common/menubar.jsp" %>
<div class="outer">
<br>
<h2 align="center">사진게시판 상세보기</h2>
<br>
<table class="detail-area" align="center">
<!-- (tr>td*4)*5 + Enter -->
<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">
</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>
ThumbnailDetailController 서블릿 생성
👉🏻 url mapping : /detail.th
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;
/**
* @see HttpServlet#HttpServlet()
*/
public ThumbnailDetailController() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
int boardNo = Integer.parseInt(request.getParameter("bno"));
// 조회 수 증가용 서비스 요청 후 성공 시 상세 조회 요청 => increaseCount 메소드 재활용
int result = new BoardService().increaseCount(boardNo);
if(result > 0) { // 성공 => 게시글 정보, 첨부파일들 정보 조회
// Board 테이블로부터 해당 게시글 정보만 뽑아오기
// 일반 게시판용 selectBoard 쿼리 활용 => 기본 내부 조인에서 left outer 조인으로 변경
// 내부 조인인 경우 일치하는 컬럼만을 가져오는 구조였는데,
// 사진 게시판의 경우 카테고리가 null이기 때문에 일치하는 것이 없어 반환되는 것이 없었던 것!
// 카테고리 컬럼을 기준으로 일치하는 컬럼, 일치하지 않는 컬럼도 가지고 오려면 outer join(외부조인) 해 줘야 함!
// 어찌되었든 간에 Board 테이블의 내용물을 조회하고 싶기 때문에 Board 테이블을 기준으로 left outer 조인으로 변경
Board b = new BoardService().selectBoard(boardNo);
// Attachment 테이블로부터 해당 게시글에 딸린 첨부파일들을 모두 조회
ArrayList<Attachment> list = new BoardService().selectAttachmentList(boardNo);
// 수화물 싣기
request.setAttribute("b", b);
request.setAttribute("list", list);
request.getRequestDispatcher("views/board/thumbnailDetailView.jsp").forward(request, response);
} else { // 실패 => 에러 문구 담아서 에러 페이지로 포워딩
request.setAttribute("errorMsg", "사진 게시글 조회 실패");
request.getRequestDispatcher("views/common/errorPage.jsp").forward(request, response);
}
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
BoardService
public ArrayList<Attachment> selectAttachmentList(int boardNo) {
Connection conn = getConnection();
ArrayList<Attachment> list = new BoardDao().selectAttachmentList(conn, boardNo);
close(conn);
return list;
}
BoardDao
public ArrayList<Attachment> selectAttachmentList(Connection conn, int boardNo) {
// SELECT문 => ResultSet 객체 (여러 행 조회)
ArrayList<Attachment> list = new ArrayList<>();
PreparedStatement pstmt = null;
ResultSet rset = null;
// 일반 게시판 상세조회 시 썼던 쿼리문 재활용
String sql = prop.getProperty("selectAttachment");
try {
pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, boardNo);
rset = pstmt.executeQuery();
while(rset.next()) {
Attachment at = new Attachment();
at.setFileNo(rset.getInt("FILE_NO"));
at.setOriginName(rset.getString("ORIGIN_NAME"));
at.setChangeName(rset.getString("CHANGE_NAME"));
at.setFilePath(rset.getString("FILE_PATH"));
list.add(at);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
close(rset);
close(pstmt);
}
return list;
}
}
board-mapper.xml
👉🏻 selectAttachment 재활용!
<entry key="selectAttachment">
SELECT FILE_NO
, ORIGIN_NAME
, CHANGE_NAME
, FILE_PATH
FROM ATTACHMENT
WHERE REF_BNO = ?
AND STATUS = 'Y'
</entry>
*게시글 수정 (숙제)
화면
👉🏻
더보기
ㅇ
화면
👉🏻
더보기
ㅇ
화면
👉🏻
더보기
ㅇ
화면
👉🏻
더보기
ㅇ
화면
👉🏻
더보기
ㅇ
화면
👉🏻
더보기
ㅇ
화면
👉🏻
더보기
ㅇ
화면
👉🏻
더보기
ㅇ
화면
👉🏻
더보기
ㅇ
*게시글 삭제(숙제)
화면
👉🏻
더보기
ㅇ
화면
👉🏻
더보기
ㅇ
화면
👉🏻
더보기
ㅇ
화면
👉🏻
더보기
ㅇ
화면
👉🏻
더보기
ㅇ
화면
👉🏻
더보기
ㅇ
화면
👉🏻
더보기
ㅇ
화면
👉🏻
더보기
ㅇ
화면
👉🏻
더보기
ㅇ