고래씌

[JSP] 5-2. 게시판 상세 페이지 만들기(+첨부파일 업로드) 본문

Server/JSP과 Servlet

[JSP] 5-2. 게시판 상세 페이지 만들기(+첨부파일 업로드)

고래씌 2023. 12. 11. 16:16

1. 게시글 클릭시 상세보기 페이지로 넘어가는 기능 추가

① boardListVIew.jsp 파일에 게시글 클릭하면 상세보기 페이지로 넘어가는 기능 추가

 

=> 로그인한 회원만 글작성 버튼이 보이도록 설정

 

 

 

② 게시글 상세페이지 디자인

 

 

■ boardDetailView

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" import="com.kh.board.model.vo.*"%>
<%
	Board b = (Board)request.getAttribute("b");

	Attachment at = (Attachment) request.getAttribute("at");
%>    

<!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 id="detail-area" align="center" border="1">
			<tr>
				<th width="70">카테고리</th>
				<td width="70"><%= b.getCategoryName() %></td>
				<th width="70">제목</th>
				<td width="350"><%= b.getBoardTitle() %></td>
			</tr>
			<tr>
				<th>작성자</th>
				<td><%= b.getBoardWriter() %></td>
				<th>작성일</th>
				<td><%= b.getCreateDate() %></td>
			</tr>
			<tr>
				<th>내용</th>
				<td colspan="3">  <!--열병합3칸-->
					<p style="height:200px;">
						<%= b.getBoardContent() %>
					</p>
				</td>
			</tr>
			<tr>
				<th>첨부파일</th>
				<td colspan="3">
					<% if(at == null) { %>
						첨부파일이 없습니다.
					<% } else { %>
						<!-- 첨부파일이 있을경우 해당파일 다운로드 -->
						<a download="<%= at.getOriginName() %>" 
						href="<%= contextPath %>/<%= at.getFilePath()+at.getChangName()%>">
						<!-- 다운로드 파일을 받을 경로 -->
						<%= at.getOriginName() %>
						</a>
						<!--  at.getFilePath()+at.getChangName() => +를 이용해 하나로 표현해줌 -->
					<% } %>
				</td>
			</tr>
		</table>
		
		<br>
		
		<div align="center">
			<a href="<%=contextPath%>/list.bo?currentPage=1" class="btn btn-secondary btn-sm">목록</a>
			
			<!-- 로그인한 사용자와 현재 게시글을 작성한 작성자가 맞는지 검사 -->
			<% if(loginUser != null && loginUser.getUserId().equals(b.getBoardWriter())) { %>
				<!-- 로그인한 사용자만 게시글 수정/삭제버튼이 보여야함 -->
				<a href="<%=contextPath %>" class="btn btn-warning btn-sm">수정</a>
				<a href="<%=contextPath %>" class="btn btn-danger btn-sm">삭제</a>
			<% } %>
		</div>
			
	
	
		<br>
		<div id="reply-area">
			<table border="1" align="center">
				<thead>
					<tr>
						<th>댓글작성</th>
						<td>
							<textarea rows="3" cols="50" style="resize:none" readonly>로그인후 이용가능한 서비스입니다</textarea>
						</td>
						<td><button disabled>댓글등록</button></td>
					</tr>
				</thead>
				<tbody>
					
				</tbody>
			</table>
		</div>
	</div>
</body>
</html>

 

▶ 첨부파일이 있는 경우 및 없는 경우 if 문 처리

<th>첨부파일</th>
   <td colspan="3">
   <% if(at == null) { %>
     첨부파일이 없습니다.
   <% } else { %>
   <!-- 첨부파일이 있을경우 해당파일 다운로드 -->
      <a download="<%= at.getOriginName() %>" 
             href="<%= contextPath %>/<%= at.getFilePath()+at.getChangName()%>">
              <!-- 다운로드 파일을 받을 경로 -->
             <%= at.getOriginName() %>
      </a>
<!--  at.getFilePath()+at.getChangName() => +를 이용해 하나로 표현해줌 -->
<% } %>
</td>

 

 

▶ 로그인한 사용자만 사용할 수 있도록 하고, 로그인한 사용자와 현재 게시글을 작성한 작성자가 맞는지 검사

<div align="center">
    <a href="<%=contextPath%>/list.bo?currentPage=1" class="btn btn-secondary btn-sm">목록</a>

    <!-- 로그인한 사용자와 현재 게시글을 작성한 작성자가 맞는지 검사 -->
    <% if(loginUser != null && loginUser.getUserId().equals(b.getBoardWriter())) { %>
        <!-- 로그인한 사용자만 게시글 수정/삭제버튼이 보여야함 -->
        <a href="<%=contextPath %>" class="btn btn-warning btn-sm">수정</a>
        <a href="<%=contextPath %>" class="btn btn-danger btn-sm">삭제</a>
    <% } %>
</div>

 

③ 게시글 상세피지와 첨부파일, 조회수증가하는 SQL쿼리문 작성하기

 

■ board-mapper.xml

▶ 각 게시글을 작성한 작성자, 카테고리, 작성날짜등의 데이터 등을 가져오기

 

=> 각 게시판의 제목, 카테고리 이름, userid등 가져오기 위해 select 쿼리문 작성

 

 

▶ 첨부파일 가져오기

 

=> 첨부파일은 Attachment 테이블에 REF_BNO을 이용해 가져옴

 

 

▶ 게시글 상세보기 페이지로 이동하면 해당 게시글의 조회수 증가되도록 SQL 쿼리문 작성

 

 

④ 서버 전송하는 Servlet 작성

■ BoardDetailController.java

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;

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

/**
 * Servlet implementation class BoardDetailController
 */
@WebServlet("/detail.bo")
public class BoardDetailController extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public BoardDetailController() {
        super();
    }

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
		// 사용자가 bno라는 이름으로 전달한 boardNo값 추출
		int boardNo = Integer.parseInt(request.getParameter("bno"));
		
		BoardService bService = new BoardService();
		
		// 조회수 증가 서비스 => ()
		int result = bService.increaseCount(boardNo);
		
		if(result>0) { // 성공적으로 조회수가 증가했다면
			// 게시글 정보 조회
			Board b = bService.selectBoard(boardNo);
			
			// Attachment 정보 조회
			Attachment at = bService.selectAttachment(boardNo);
			
			System.out.println(b);
			System.out.println(at);
			
			request.setAttribute("b", b);
			request.setAttribute("at", at);
			request.getRequestDispatcher("views/board/boardDetailView.jsp").forward(request, response);
			
		} else { // 에러페이지로 이동
			
			request.setAttribute("errorMsg", "게시글 상세조회 실패");
			request.getRequestDispatcher("views/common/errorPage.jsp").forward(request, response);
			
		}
	}

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

}

 

 

⑤ BoardService.java에서 Connection 객체 생성

▶ 조회수 증가 관련 메소드

 

 

▶ 게시글 불러오기(상세페이지) 메소드

 

 

▶ 첨부파일 메소드

 

 

 

⑥ BoardDao.java에서 SQL 쿼리문 실행 

▶ 조회수 증가 관련 메소드

 

 

▶ 게시글 불러오기(상세페이지) 메소드

 

 

▶ 첨부파일 메소드

 

 

 

▶ 결과화면


2. 게시글 작성 만들고 업로드 파일 저장

 

 

board_upfiles => 사용자가 업로드한 파일들이 저장되는 폴더

 

 

① 글작성 클릭 후 이동하는 페이지 만들기

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" import="java.util.ArrayList, com.kh.board.model.vo.Category"%>
<%
	ArrayList<Category> list = (ArrayList<Category>) request.getAttribute("list");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<style>
#enroll-form>table{border:1px solid white;}
#enroll-form input, #enroll-form textarea{
	width:100%;
	box-sizing:border-box;
}
</style>
</head>
<body>
	<%@ include file="../common/menubar.jsp" %>
	
	<div class="outer">
		<br>
		<h2 align="center">일반게시판 작성</h2>
		
		<form action="<%= contextPath %>/insert.bo" id="enroll-form" method="post"
		enctype="multipart/form-data">
			<!-- 만약 내가 보내야하는 파일에 첨부파일이 있는 경우 enctype="multipart/form-data"로 전달해야함
				그래야 정상적으로 파일이 전송되어진다!
			 -->
			
			<!-- 카테고리, 제목, 내용, 첨부파일 넘겨주어야 함(사용자가 선택하거나 입력해야하는 것) -->
			<!-- 회원번호 → input type hidden으로 넘길예정 (사용자가 자기 회원번호를 입력하는 것은 이상하니까) -->
			<input type="hidden" name="userNo" value="<%= loginUser.getUserNo() %>">
			<table align="center">
				<tr>
					<th width="100">카테고리</th>
					<td width="500">
						<select name="category">
<!-- 							<option value="10">공통</option> -->
<!-- 							<option value="20">운동</option> -->
<!-- 							<option value="30">등산</option> -->
<!-- 							<option value="40">게임</option> -->
<!-- 							<option value="50">낚시</option> -->
<!-- 							<option value="60">요리</option> -->
<!-- 							<option value="70">기타</option> -->
							<!-- DB에 저장되어있는 category_no는 value에 저장 -->
								<% for(Category c : list) { %>
								<option value="<%= c.getCategoryNo() %>"><%= c.getCategoryName() %></option>
								<% } %>
						</select>
					</td>
				</tr>
				<tr>
					<th>제목</th>
					<td><input type="text" name="title" required></td>
				</tr>
				<tr>
					<th>내용</th>
					<td>
						<textarea name="content" rows="10" required></textarea>
					</td>
				</tr>
				<tr>
					<th>첨부파일</th>
					<td>
						<input type="file" name="upfile">
					</td>
				</tr>
			</table>
			
			<br>
			
			<div align="center">
				<button type="submit">작성</button>
			</div>
			
		</form>
	</div>

</body>
</html>

 

▶ 내가 보내야하는 파일에 첨부파일이 있는 경우

=> enctype="multipart/form-data"로 전달해야한다. 그래야 정상적으로 파일이 전송되어진다!

 

 

② DB에 저장되어 있는 카테고리 리스트들을 가져오기 위해 SQL 문 작성

▶ board-mapper.xml

 

 

③ Servlet 작성하여 서버 연결

▶ BoardInsertController.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.Category;
import com.kh.common.MyFileRenamePolicy;
import com.oreilly.servlet.MultipartRequest;

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

    public BoardInsertController() {
        super();
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
		ArrayList<Category> list = new BoardService().selectCategoryList();
		
		request.setAttribute("list", list);
		request.getRequestDispatcher("views/board/boardEnrollForm.jsp").forward(request, response);
		
	}

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

		}
	}

}

 

 

 

④ 게시글 작성하는 Connection 객체 생성 

▶ BoardService.java

 

 

⑤ SQL 쿼리문 실행

▶ BoardDao.java

 

 

 


3. 게시글 작성할 때 첨부파일이 있을 경우 전송

☞ form태그의 전송방법을 multipart/form-data로 전송하는 경우 request로 부터 값을 뽑는게 불가능하다!

☞ multipart로 값을 이관시킨 후 다뤄줘야 한다.

 

=> 우리는 앞서 첨부파일을 전송할 때 multipart을 이용하여 전송하는 방법으로 하였었다.

 

boardEnrollForm.jsp

 

 

(메이븐 레파지토리)

https://mvnrepository.com/artifact/com.jfinal/cos

=> 2022.02 들어가 jar 파일 다운. 

 

다운 후, lib 파일에 복사한다.

 

 

① 게시판 추가 와 게시판 추가할 때 첨부파일이 있을 경우 SQL 쿼리문 생성

▶ board-mapper.xml 

 

 

② if문을 이용해 enctype이 multipart/form-data로 전송되었는지 확인

▶ BoardInsertController.java

package com.kh.board.controller;

import java.io.File;
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.board.model.vo.Category;
import com.kh.common.MyFileRenamePolicy;
import com.oreilly.servlet.MultipartRequest;

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

    public BoardInsertController() {
        super();
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
		ArrayList<Category> list = new BoardService().selectCategoryList();
		
		request.setAttribute("list", list);
		request.getRequestDispatcher("views/board/boardEnrollForm.jsp").forward(request, response);
		
	}

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

		request.setCharacterEncoding("UTF-8");
		
		/*
		 * form태그의 전송방법을 multipart/form-data로 전송하는 경우
		 * request로 부터 값을 뽑는게 불가능하다!
		 * 
		 * multipart로 값을 이관시킨 후 다뤄줘야 한다.
		 */
		// enctype이 multipart/form-data로 전송되었는지 확인
		if(ServletFileUpload.isMultipartContent(request)) {
			// Servlet으로 multipart 파일 형식으로 파일을 업로드했냐 안했냐
			// System.out.println("실행중");
			
			// 파일 업로드를 위한 라이브러리 : cos.jar
			
			// 1. 전송되는 파일을 처리할 작업내용(전송되는 파일의 용량제한, 전달된 파일을 저장할 폴더경로 제시)
			// 1_1. 전송파일 용량제한(byte단위로 제시)
			/*
			 * 1kbyte == 1024byte
			 * 1mbyte == 1024kbyte == 1024*1024(2의 20승)
			 */
			int maxSize = 10 * 1024 * 1024; // 10Mbyte;
			
			// 1_2. 전달된 파일을 저장할 서버의 폴더 경로 알아내기
			// 어플리케이션 객체에서 제공하는 getRealPath메소드를 통해 알아내기
			// 매개변수로 board_upfiles폴더까지의 경로를 제시해줘야한다.
			String savePath = request.getSession().getServletContext().getRealPath("/resources/board_upfiles/");
			// System.out.println(savePath);
			// "/" => WebContent 의미
			
			/*
			 * 2. 전달된 파일명 수정 및 서버에 업로드
			 *   - HttpServeltRequest request => MultipartRequest multiRequest로 변환
			 *   
			 *   매개변수 생성자로 MultpartRequest객체를 생성(cos.jar에서 제공하는 객체)
			 *   MultipartRequest multiRequest = new MultipartRequest(request 객체,
			 *     저장할 폴더경로, 용량제한, 인코딩값, 파일명을 수정시켜주는 객체);
			 *     
			 *   위 구문 한줄 실행만으로 넘어온 첨부파일들이 해당 폴더에 업로드됨.
			 *   그리고 사용자가 올린 파일명은 그대로 해당 폴더에 업로드하지 않는다.(같은 파일명이 있을 경우
			 *   덮어씌워질 수도 있고, 서버에 따라 문제가 발생할 수도 있다.)
			 *   
			 *   cos.jar에서 제공하는 파일명 수정작업을 해주는 객체
			 *   - DefaultFileRenamePolicy 객체
			 *   - 내부적으로 rename()이라는 메소드가 실행이 되면서 파일명 수정이 진행됨
			 *   - 작동방식은 동일한 파일명이 존재할 경우 카운팅된 숫자를 붙여서 파일명을 수정해줌
			 *   ex) aaa.jpb, aaa1.jpb, aaa2.jpg
			 *   
			 *   - 우리 입맛대로 파일명이 겹치지 않게끔 rename 메소드를 오버라이딩 해줄 예정
			 */
			
			MultipartRequest multiRequest = new MultipartRequest(request, savePath,
					maxSize, "UTF-8", new MyFileRenamePolicy());
			
			// 3. DB에 기록할 데이터들을 뽑기
			// - Board 테이블에 추가할 데이터(카테고리 번호, 제목, 내용, 작성자 회원번호)
			// - Attachment테이블에 추가할 데이터(원본명, 수정명, 저장경로)
			String category = multiRequest.getParameter("category");
			String boardTitle = multiRequest.getParameter("title");
			String boardContent = multiRequest.getParameter("content");
			String boardWriter = multiRequest.getParameter("userNo");
			
			Board b = new Board.Builder().categoryNo(Integer.parseInt(category))
										 .boardTitle(boardTitle)
										 .boardContent(boardContent)
										 .boardWriter(boardWriter)
										 .bulid();
			
			// 첨부파일은 필수가 아니기 때문에 우선 null로 초기화,
			// 등록한 첨부파일이 있을 경우 객체 생성
			Attachment at = null;
			// multiRequest.getOriginlFileName("키")
			// 첨부파일이 있었을 경우 원본 파일명, 없었을 경우 null 값이 반환
			if(multiRequest.getOriginalFileName("upfile") != null) {
				at = new Attachment();
				at.setOriginName(multiRequest.getOriginalFileName("upfile")); // 원본명
				at.setChangeName(multiRequest.getFilesystemName("upfile")); // 수정명(실제 서버에 올라간 파일명)
				at.setFilePath("resources/board_upfiles/");
			}
			
			// 4. 서비스 요청(DML)
			int result = new BoardService().insertBoard(b, at);
			
			// 5. 응답화면 지정
			if(result > 0) {  // 성공 => list.bo
				request.getSession().setAttribute("alertMsg", "게시글 작성에 성공했습니다.");
				response.sendRedirect("list.bo?currentPage=1");
			}else {
				// 실패시 => 첨부파일이 있었을 경우 이미 업로드된 첨부파일을 서버에서 삭제후, 에러페이지로 포워딩
				if(at != null) {
					// 삭제시키고자하는 파일객체 생성후 delete 메소드 호출
					new File(savePath+at.getChangeName()).delete();
				}
				request.setAttribute("errorMsg", "게시글 작성 실패!");
				request.getRequestDispatcher("views/common/errorPage.jsp").forward(request, response); // 에러페이지로 포워딩
			}
		}
	}

}

 

 

1. 전송되는 파일을 처리할 작업내용(전송되는 파일의 용량제한, 전달된 파일을 저장할 폴더경로 제시

1_1.  전송파일 용량제한(byte단위로 제시)

 

* 1kbyte == 1024byte
 * 1mbyte == 1024kbyte == 1024*1024(2의 20승)

 

int maxSize = 10 * 1024 * 1024   // 10Mbyte;

=> 용량제한 걸어둠

 

 

 

1_2. 전달된 파일을 저장할 서버의 폴더 경로 알아내기

=> 어플리케이션 객체에서 제공하는 getRealPath메소드를 통해 알아내기

=> 매개변수로 board_upfiles폴더까지의 경로를 제시해줘야한다.(board_upfiles => 업로드된 파일이 저장된 폴더)

 

String savePath = request.getSession().getServletContext().getRealPath("/resources/board_upfiles/");

 

"/"  => WebContent 의미

 

 

2. 전달된 파일명 수정 및 서버에 업로드

- HttpServeltRequest request => MultipartRequest multiRequest로 변환
   매개변수 생성자로 MultpartRequest객체를 생성(cos.jar에서 제공하는 객체)
   MultipartRequest multiRequest = new MultipartRequest(request 객체, 저장할 폴더경로, 용량제한, 인코딩값, 파일명을 수정시켜주는 객체);
   
=> 위 구문 한줄 실행만으로 넘어온 첨부파일들이 해당 폴더에 업로드됨.
=> 그리고 사용자가 올린 파일명은 그대로 해당 폴더에 업로드하지 않는다.(같은 파일명이 있을 경우 덮어씌워질 수도 있고, 서버에 따라 문제가 발생할 수도 있다.)

cos.jar에서 제공하는 파일명 수정작업을 해주는 객체
- DefaultFileRenamePolicy 객체
- 내부적으로 rename()이라는 메소드가 실행이 되면서 파일명 수정이 진행됨
- 작동방식은 동일한 파일명이 존재할 경우 카운팅된 숫자를 붙여서 파일명을 수정해줌
 ex) aaa.jpb, aaa1.jpb, aaa2.jpg
- 우리 입맛대로 파일명이 겹치지 않게끔 rename 메소드를 오버라이딩 해줄 예정

 

MultipartRequest multiRequest = new MultipartRequest(request, savePath,
maxSize, "UTF-8", new MyFileRenamePolicy());

 

 

3. DB에 기록할 데이터들을 뽑기

- Board 테이블에 추가할 데이터(카테고리 번호, 제목, 내용, 작성자 회원번호)
- Attachment테이블에 추가할 데이터(원본명, 수정명, 저장경로)

 

 

 

4. 서비스 요청(DML)

int result = new BoardService().insertBoard(b, at);

 

 

5. 응답화면 지정

 

 

③ 사용자가 파일을 업로드할 때 board_upfiles 폴더에 저장되는데 같은 폴더명이 존재하면 덮어씌우기 되니까 날짜,시간을 합한 파일명으로 자동으로 생성되도록 설정

▶ MyFileFenamePolicy.java

package com.kh.common;

import java.io.File;

import com.oreilly.servlet.multipart.FileRenamePolicy;

public class MyFileRenamePolicy implements FileRenamePolicy {
	
	public File rename(File originFile) {
		// 기존의 파일을 매개변수로 전달받아서(originFile) 파일명 수정작업 후에 수정된 파일을 반환해주는 메소드
		
		// 원본파일명("aaa.jpg")
		String originName = originFile.getName();
		
		// 수정파일명 : 파일업로드시간(년월일시분초)+5자리 랜덤값 => 최대한 안겹치게 함
		// 확장자 : 원본파일의 확장자 그대로 사용
		
		// aaa.jpg ------> 202312114374512345.jpg
		// 1. 파일 업로드된 시간(년월일시분초)
		String currentTime = new java.text.SimpleDateFormat("yyyyMMddHHmmss").format(new java.util.Date());
		
		// 2. 5자리 랜덤값 => int ranNum;
		int ranNum = (int)((Math.random() * 90000) + 10000); // 10000~99999
		
		// 3. 원본파일 확장자(String ext)
		String ext = originName.substring(originName.lastIndexOf(".")); // jpg
		
		String changeName = currentTime + ranNum + ext;
		
		// 원본파일을 수정된 파일명으로 적용시켜서 파일객체로 반환
		return new File(originFile.getParent(), changeName);
	}

}

 

 

④ 게시글 작성과 첨부파일 있을시 업로드 할 때 메소드 생성

▶ BoardService.java

 

 

⑤ 게시판 작성 후 추가와 첨부파일 있을 경우 추가에 관한 SQL 쿼리문 실행한 메소드 생성

▶ BoardDao.java

 

 

 

▶ 결과화면

 

=> 첨부파일을 클릭하면 다운로드까지 되는 것을 확인할 수 있다.