ㅁ 첨부파일 업로드
ㅁ 일반게시글 목록페이지
- 로그인 상태면 '등록하기' 버튼이 보인다.
'등록하기' 버튼을 누르면 일반게시글 작성페이지로 간다.
ㅁ 일반게시글작성 페이지를 토대로 boardWrite.jsp를 만든다.
<%@ page import="java.util.List" %>
<%@ page import="com.br.web.board.model.vo.Category" %>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
List<Category> list = (List<Category>)request.getAttribute("list");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<div class="container p-3">
<!-- Header, Nav start -->
<%@ include file="/views/common/header.jsp" %>
<!-- Header, Nav end -->
<!-- Section start -->
<section class="row m-3" style="min-height: 500px;">
<div class="container border m-4 p-5 rounded">
<h2 class="m-4">일반게시글 작성</h2>
<form action="<%= contextPath %>/insert.bo" method="post" enctype="multipart/form-data" class="m-4">
<table class="table">
<tr>
<th width="100">카테고리</th>
<td>
<select name="category" class="form-control">
<% for(Category c : list) { %>
<option value="<%=c.getCategoryNo()%>"><%=c.getCategoryName()%></option>
<% } %>
</select>
</td>
</tr>
<tr>
<th>제목</th>
<td><input type="text" class="form-control" name="title" required></td>
</tr>
<tr>
<th>내용</th>
<td><textarea rows="10" class="form-control" name="content" style="resize:none;" required></textarea></td>
</tr>
<tr>
<th>첨부파일</th>
<td><input type="file" name="upfile"></td>
</tr>
<tr>
<td colspan="2" align="center">
<button type="submit" class="btn btn-outline-secondary btn-sm">등록하기</button>
<button type="reset" class="btn btn-outline-danger btn-sm">초기화</button>
<button type="button" class="btn btn-outline-warning btn-sm" onclick="history.back();">뒤로가기</button>
</td>
</tr>
</table>
</form>
</div>
</section>
<!-- Section end -->
<!-- Footer start -->
<%@ include file="/views/common/footer.jsp" %>
<!-- Footer end -->
</div>
</body>
</html>
- '등록하기' 버튼을 눌러서 submit하면 /insert.bo라는 서블릿을 호출한다.
- 일반게시글 작성은 첨부파일 하나를 첨부할 수 있게 한다. 필수는 아니다.
나중에 사진게시글 작성은 첨부파일을 여러개 첨부한다.
- 첨부파일은 파일 자체를 넘긴다. 파일 자체를 넘겨서 서버에 보관(저장)을 시켜야 다른 사용자가 이 게시글을 봤을 때 다운로드 같은 기능을 할 수 있다.
- form에 새로운 속성을 사용한다. form submit시 파일 그 자체를 넘기고자 한다면 추가적으로 이 속성을 줘야 한다.
이 속성을 주지 않으면 파일 자체가 넘어가지 않고 파일명만 텍스트로 넘어간다.
- enctype이라는 속성의 값으로 "multipart/form-data"를 써줘야 form submit시 파일이 넘어간다.
그리고 무조건 post방식이어야 한다.
ㅁ BoardInsertController
package com.br.web.board.controller;
import java.io.File;
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 javax.servlet.http.HttpSession;
import com.br.web.board.model.service.BoardService;
import com.br.web.board.model.vo.Attachment;
import com.br.web.board.model.vo.Board;
import com.br.web.common.utils.MyFileRenamePolicy;
import com.br.web.member.model.vo.Member;
import com.oreilly.servlet.MultipartRequest;
/**
* Servlet implementation class BoardInsertController
*/
@WebServlet("/insert.bo")
public class BoardInsertController extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public BoardInsertController() {
super();
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
// multipart/form-data로 전송할 경우
// request로부터 파라미터를 바로 뽑을 수 없음!
// 1. 전달된 파일 업로드(서버에 저장)
/*
* * 파일 업로드 처리를 위한 라이브러리 : cos.jar
*
* HttpServletRequest => MultipartRequest 변환
* MulpartRequest multiRequest
* = new MultipartRequest(request, 저장시킬폴더의물리적인경로, 용량제한값, "UTF-8", 파일명수정해주는FileRenamePolicy객체);
*
*/
// 1_1) 저장시킬 폴더의 물리적인 경로 (String savePath)
String savePath = request.getServletContext().getRealPath("/resources/board_upfiles/");
// 1_2) 파일 용량 제한값 : 10mbyte (int maxSize는 byte단위다.)
// byte => kbyte => mbyte => gbyte => tbyte => ... (1024배)
int maxSize = 10 * 1024 * 1024;
/*
* 1_3) 파일명 수정처리해주는 FileRenamePolicy 객체 세팅
*
* * 파일명을 수정해서 저장해야되는 이유
* (1) 중복된 파일명이 존재할 수 있음
* (2) 원본명에 한글/특수문자/공백 이 포함되어있을 수 있음 => 서버에 문제 생김
*
* * 기본적으로 파일명 수정해주는 DefaultFileRenamePolicy 객체 제공
* => rename 작업 내용
* ㄴ 기존에 동일한 파일명이 존재할 경우
* 파일명 뒤에 카운팅된 숫자를 붙여주기만 함 (특문, 한글, 공백 그대로임)
* ex) aaa.jpg, aaa1.jpg, aaa2.jpg
*
* * 나만의 com.br.web.common.utils.MyFileRenamePolicy 객체 만들기 (일반 클래스에 implements)
* => rename 작업 내용
* ㄴ 전달된 파일명을 "업로드된시간_랜덤숫자5자리.기존확장자"
*/
MultipartRequest multiRequest
= new MultipartRequest(request, savePath, maxSize, "UTF-8", new MyFileRenamePolicy());
// 2. DB에 데이터 기록
// 카테고리번호,제목,내용,작성자회원번호 => Board에 Insert
// 첨부파일원본명,수정명(실제업로드된파일명),저장폴더경로 => Attachment에 Insert (넘어온 첨부파일이 있었을 경우)
// 게시글 데이터 => Board 에 담기
String boardTitle = multiRequest.getParameter("title");
String boardContent = multiRequest.getParameter("content");
String category = multiRequest.getParameter("category"); // "20"
HttpSession session = request.getSession();
int userNo = ((Member)session.getAttribute("loginUser")).getUserNo();
Board b = new Board();
b.setBoardTitle(boardTitle);
b.setBoardContent(boardContent);
b.setCategory(category);
b.setBoardWriter(String.valueOf(userNo));
// 첨부파일 데이터 => Attachment 담기
Attachment at = null; // 넘어온 첨부파일이 있을 경우 => 생성
// * multiRequest.getOriginalFileName("키") : 첨부파일이 있었을 경우 "원본명" | 없을 경우 null
if(multiRequest.getOriginalFileName("upfile") != null) {
at = new Attachment();
at.setOriginName(multiRequest.getOriginalFileName("upfile"));
at.setChangeName(multiRequest.getFilesystemName("upfile"));
at.setFilePath("/resources/board_upfiles/");
}
// 서비스 요청
int result = new BoardService().insertBoard(b, at);
// 3. 응답
if(result > 0) { // 성공 => 다시목록페이지 => alert메세지
session.setAttribute("alertMsg", "성공적으로 게시글이 등록되었습니다.");
response.sendRedirect(request.getContextPath() + "/list.bo");
}else { // 실패 => 에러페이지 => 에러메세지
// 첨부파일이 있었을 경우
// 이미 업로드된 파일 => 더이상 쓸모없음 => 파일제거
if(at != null) {
new File(savePath + at.getChangeName()).delete();
}
request.setAttribute("msg", "게시글 등록 실패");
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 {
doGet(request, response);
}
}
- url mapping값은 /insert.bo다.
- 파일이 넘어올 수도 있고 넘어오지 않을 수도 있다.
- 넘어온 데이터를 db에 기록하기 전에 파일을 먼저 서버에 저장(업로드)시켜야 한다.
- (1) 전달된 파일 업로드(서버에 저장) => (2) DB에 데이터 기록 => (3) 응답
- 전달된 파일을 어떤 폴더에 저장시킬건지 폴더를 먼저 만들어 놓는다.
- webapp폴더에 assets라는 폴더도 있지만 assets는 사이트에 필요한 정적 자원들을 보관시킬거고, 사용자가 저장시킨 파일들은 resources라는 일반 폴더를 만들어서 저장해본다.
- src/main/webapp/resources/board_upfiles 라는 폴더를 만들고 여기에 저장한다.
- 이클립스에서는 외부 기능에 의해서 파일이 추가된 경우 실시간으로 안보여진다. 반드시 f5를 해야 저장된 파일을 볼 수 있다.
- 파일 업로드를 톰캣으로 할 수도 있지만 너무 복잡하다.
파일 업로드를 수월하게 해주는 외부 라이브러리들이 굉장히 많다.
※ 파일 업로드 처리를 위한 라이브러리 : cos.jar
- 파일 업로드 관련한 클래스들이 잔뜩 모여있다.
- 이걸 다운받을 수 있는 사이트가 지금은 사라졌다.
- HttpServletRequest 타입의 객체를 MultipartRequest 변환한다. (cos 라이브러리에서 제공하는 클래스로)
멀티파트 리퀘스트 객체 생성 구문 한 줄로 파일이 업로드된다.
MulpartRequest multiRequest = new MultipartRequest(request, 저장시킬폴더의물리적인경로, 용량제한값, "UTF-8", 파일명수정해주는FileRenamePolicy객체);
- 요청시 전달값들은 request에 담겨있다. 파일이 있었다면 파일 데이터도 담겨있다.
그러나 multipart/form-data로 전송한 경우에는 request로부터 파라미터를 바로 뽑을 수 없다.
- request에 담겨있는 파라미터들이 multiRequest 변수로 이동한다. 파일이 있었다면 이 과정에서 파일 업로드가 진행된다.
- 대신 이 파일을 어떤 폴더에 저장시킬건지, 용량 제한은 몇인지 등을 다 써줘야 한다.
- 마지막으로 "FileRenamePolicy객체"를 제시하면 이 객체가 내부적으로 작동되면서 파일명을 수정해준다.
- MultipartRequest는 cos.jar 라이브러리가 제공하는 클래스다.
- javax는 톰캣이 제공하는 클래스다.
- java는 순수 자바에서 제공하는 클래스다.
(1-1) 저장시킬 폴더의 물리적인 경로 (String savePath)
String savePath = request.getServletContext().getRealPath("/resources/board_upfiles/");
- 서블릿 컨텍스트 객체가 먼저 필요하다.
왜냐면 서블릿 컨텍스트 객체가 물리적인 경로를 알아내는 getRealPath라는 메소드를 제공하기 때문이다.
- 여기서의 슬래시는 루트(최상위 폴더)를 의미한다. 배포되는 폴더인 webapp폴더를 가리킨다.
- 중요한건 뒤에 슬래시까지 있어야한다. 이 폴더 안에 저장을 시킬것이기 때문에!!
(1-2) 파일 용량 제한값
- 파일 용량 제한값은 byte 단위로 환산해서 넣어줘야 한다.
(1-3) 파일명을 수정해주는 FileRenamePolicy 객체 세팅
- cos 라이브러리에서 기본적으로 파일명을 수정해주는 객체가 있다. 그걸 제시해도 된다. 근데 안쓴다.
DefaultFileRenamePolicy는 파일명 뒤에 숫자를 붙여주기만 해서 특수문자나 공백, 한글이 있는 경우 그대로 남아서 적절치 않다.
- 언더바는 허용되는 특수문자다.
* * 파일명을 수정해서 저장해야되는 이유
* (1) 중복된 파일명이 존재할 수 있음
* (2) 원본명에 한글/특수문자/공백 이 포함되어있을 수 있음 => 서버에 문제 생김
*
* * 기본적으로 파일명 수정해주는 DefaultFileRenamePolicy 객체 제공
* => rename 작업 내용
* ㄴ 기존에 동일한 파일명이 존재할 경우
* 파일명 뒤에 카운팅된 숫자를 붙여주기만 함
* ex) aaa.jpg, aaa1.jpg, aaa2.jpg
*
* * 나만의 com.br.web.common.utils.MyFileRenamePolicy 객체 만들기
* => rename 작업 내용
* ㄴ 전달된 파일명을 "업로드된시간_랜덤숫자5자리.기존확장자"
- com.br.web.common.utils 패키지를 만든다.
파일명을 수정해주는 도구여서 이런 것들은 utils 패키지를 만든다.
다른 게시판에서도 파일명 수정작업을 할 수 있기 때문에 common 패키지에 둔다.
- 저 패키지에 일반 클래스로 만든다.
package com.br.web.common.utils;
import java.io.File;
import com.oreilly.servlet.multipart.FileRenamePolicy;
public class MyFileRenamePolicy implements FileRenamePolicy {
@Override
public File rename(File originFile) { // 내부적으로 해당 rename 메소드 호출시 원본파일 객체가 전달됨
// 원본파일명("aaa.jpg") => 수정파일명("1702938174_12371.jpg")
// 업로드시간(밀리세컨)_랜덤숫자5자리.확장자
String originalFilename = originFile.getName(); // 원본파일명("aaa.jpg")
// 파일명 수정 작업
// 1. 파일업로드한 시간 (long currentTime)
long currentTime = System.currentTimeMillis(); // 1970/01/01 부터 현재시간까지 경과한 시간을 밀리세컨초로 반환
// 2. 랜덤숫자 5자리 (10000~99999) (int ranNum)
int ranNum = (int)(Math.random() * 90000 + 10000);
// 3. 원본파일의 확장자 (String ext)
String ext = originalFilename.substring(originalFilename.lastIndexOf("."));
String filesystemName = currentTime + "_" + ranNum + ext;
return new File(originFile.getParent(), filesystemName);
}
}
- 그냥 일반 클래스가 아니라, cos에서 제공하는 FileRenamePolicy라는 인터페이스를 구현하는 구현 클래스여야 MultipartRequest 객체 생성 구문의 마지막 인자값으로 제시할 수 있다.
- 인터페이스여서 추상메소드가 존재한다.
빨간줄에 마우스를 갖다대서 'Add unimplemented methods'를 누르면 내가 완성시켜야 하는 rename 메소드가 오버라이드 된다.
- MultipartRequest 객체 생성 구문 실행시 내부적으로 이 메소드가 자동으로 호출된다.
이 메소드 안에서 파일명을 수정해주는 코드를 작성하면 된다.
- rename 메소드에 매개변수로 원본 파일이 전달된다. 이해하기 쉽게 매개변수명을 originFile로 바꿨다.
원본 파일로부터 원본명, 파일 사이즈 등을 알아낼 수 있다.
- 중복되지 않게끔 업로드한 시간을 밀리세컨 단위로 한다. 현재 시스템 시간이다.
밀리세컨초 단위는 숫자가 커서 long형에 담아야 한다.
- Java에서 숫자는 0으로 시작할 수 없기 때문에, 랜덤 숫자를 5자리로 만들고, 만약 자릿수가 모자라면 0을 앞에 붙여주는 작업을 추가로 해야 합니다.
- 보통 서버에 저장되는 파일명은 filesystemName이라고 한다.
- new File의 첫번째 인자값으로는 원본 파일의 상위 폴더를 제시한다.
두번째 인자값으로는 어떤 이름으로 바꿀건지 제시한다.
- 마지막으로 db에 데이터를 기록하기 전에 업로드가 우선 잘 되는지부터 확인한다.
서버 재시작하고 브라우저 새로고침, 로그인, 일반게시글을 첨부파일을 첨부해서 작성한다.
- 이클립스에서 src/main/webapp/resources/board_upfiles를 새로고침하면 방금 첨부한 파일이 rename한 파일명으로 보인다.
(2) DB에 데이터 기록
// 2. DB에 데이터 기록
// 카테고리번호,제목,내용,작성자회원번호 => Board에 Insert
// 첨부파일원본명,수정명(실제업로드된파일명),저장폴더경로 => Attachment에 Insert (넘어온 첨부파일이 있었을 경우)
// 게시글 데이터 => Board 에 담기
String boardTitle = multiRequest.getParameter("title");
String boardContent = multiRequest.getParameter("content");
String category = multiRequest.getParameter("category"); // "20"
HttpSession session = request.getSession();
int userNo = ((Member)session.getAttribute("loginUser")).getUserNo();
Board b = new Board();
b.setBoardTitle(boardTitle);
b.setBoardContent(boardContent);
b.setCategory(category);
b.setBoardWriter(String.valueOf(userNo));
// 첨부파일 데이터 => Attachment 담기
Attachment at = null; // 넘어온 첨부파일이 있을 경우 => 생성
// * multiRequest.getOriginalFileName("input 태그의 key값") : 첨부파일이 있었을 경우 "원본명" | 없을 경우 null
if(multiRequest.getOriginalFileName("upfile") != null) {
at = new Attachment();
at.setOriginName(multiRequest.getOriginalFileName("upfile"));
at.setChangeName(multiRequest.getFilesystemName("upfile"));
at.setFilePath("/resources/board_upfiles/");
}
// 서비스 요청
int result = new BoardService().insertBoard(b, at);
- 요청시 넘어온 전달값들은 처음에는 request 객체에 있었겠지만 지금은 multiRequest 객체에서 뽑는다.
- 2개의 테이블에 insert하지만 하나의 서비스 메소드에서 다 진행한다. 결국 게시글 작성이라는 하나의 기능이다.
실행시킬 쿼리는 2개이므로 2개의 dao 메소드로 나눠서 실행한다.
- 첨부파일이 넘어왔는지 안넘어왔는지 비교하기 위해 일단 NULL로 초기화해놓는다.
- 첨부파일에 대한 정보도 multiRequest 객체에 담겨 있다.
- multiRequest.getOriginalFileName()에 input 태그의 key값을 제시하면 첨부파일에 대한 정보를 알아낼 수 있다.
첨부파일이 있었을 경우 문자열로 원본명을 반환한다.
- multiRequest.getFilesystemName()에 input 태그의 key값을 제시하면 넘어온 파일이 실제로 어떤 이름으로 저장되었는지를 반환한다.
- 이 파일이 저장된 폴더 경로는 C드라이브부터의 물리적인 경로를 담아서는 안 된다.
아까 저장시켰던 일부 경로를 제시한다. 이걸 db에 기록한다.
- 두 개의 insert문을 하나의 서비스로 묶어서 진행한다. 하나의 기능이니까.
public int insertBoard(Board b, Attachment at) {
Connection conn = getConnection();
// 1) Board에 Insert
int result = bDao.insertBoard(conn, b);
if(result > 0 && at != null) {
// 2) Attachment에 Insert
result = bDao.insertAttachment(conn, at);
}
if(result > 0) {
commit(conn);
}else {
rollback(conn);
}
close(conn);
return result;
}
- Attachment 테이블은 참조 게시글 번호 컬럼이 있기 때문에 부모 테이블인 Board에 먼저 insert 해야 한다.
- Attachment 테이블에 insert는 그냥 하면 안된다.
Board에 insert가 성공해야만 하고, 또 첨부파일이 있는 경우에만 해야 한다.
- 둘 중 하나라도 잘 안된 경우에는 전부 rollback을 해야 한다.
※ 시퀀스 현재값을 가져오는 방법
- 시퀀스.CURRVAL하면 위에서 INSERT문으로 마지막으로 수행된 NEXTVAL의 값(현재값)을 알아낼 수 있다.
(3) 응답
// 3. 응답
if(result > 0) { // 성공 => 다시목록페이지 => alert메세지
session.setAttribute("alertMsg", "성공적으로 게시글이 등록되었습니다.");
response.sendRedirect(request.getContextPath() + "/list.bo");
}else { // 실패 => 에러페이지 => 에러메세지
// 첨부파일이 있었을 경우
// 이미 업로드된 파일 => 더이상 쓸모없음 => 파일제거
if(at != null) {
new File(savePath + at.getChangeName()).delete();
}
request.setAttribute("msg", "게시글 등록 실패");
request.getRequestDispatcher("/views/common/errorPage.jsp").forward(request, response);
}
- redirect할 때 "/list.bo?page=n" 이렇게 키밸류 세트로 넘겨도 된다. 페이징처리 되어있어서.
"/list.bo"만 쓰면 1번 페이지 요청으로 간주된다.
- db에 기록이 실패했지만, 이미 그전에 첨부파일이 있었을 경우에는 이미 업로드가 되었다. 삭제해야 한다.
- 파일 제거는 삭제하고자하는 파일을 파일 객체로 생성해서 delete() 메소드만 호출하면 된다.
대신 그 파일을 선택해야 한다. 그 파일이 저장된 물리적인 경로 안에 실제로 저장된 파일명을 제시해서 파일 객체로 생성시킨다.
========================================================================================
ㅁ 문제
(1) com.test.common.MyFileRenamePolicy
@Override
public File rename(File arg0) {
// 파일명 수정작업하는 구문 작성하기.
// 파일명은 "test_" + "년월일시분초" + 랜덤5자리 + 확장자가 되도록 할 것.
// "저장경로 + 수정명" 하나의 문자열로 db에 file_url 컬럼에 보관할 것.
String originalFilename = arg0.getName(); // 원본파일명
int ranNum = (int)(Math.random() * 90000 + 10000); // 랜덤숫자 5자리 10000~99999
String ext = originalFilename.substring(originalFilename.lastIndexOf(".")); // 확장자
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
String upTime= sdf.format(new Date()); // 년월일시분초
String filesystemName = "test_" + upTime + ranNum + ext;
return new File(arg0.getParent(), filesystemName);
}
- 년월일시분초 형식을 위해 SimpleDateFormat 활용.
(2) com.test.board.controller.BoardInsertController
package com.test.board.controller;
import java.io.File;
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.oreilly.servlet.MultipartRequest;
import com.test.board.model.service.BoardService;
import com.test.board.model.vo.TestBoard;
import com.test.common.MyFileRenamePolicy;
@WebServlet("/insert.bo")
public class BoardInsertController extends HttpServlet {
private static final long serialVersionUID = 1L;
public BoardInsertController() {
super();
// TODO Auto-generated constructor stub
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 게시글 작성 요청시 실행해야되는 구문 작성하기.
// 넘어오는 첨부파일 "resources/upload_files" 폴더에 업로드 시키기
// 이때 파일명 수정 작업해주는 MyFileRenamePolicy 클래스가서 코드 작성하기
// 수정명은 앞에 "test_" 붙이고 그 뒤에 "xxxxxxxx"(년월일시분초), xxxxx(랜덤숫자5자리) 붙이도록 할 것
request.setCharacterEncoding("UTF-8");
String savePath = request.getServletContext().getRealPath("/resources/upload_files/");
int maxSize = 10 * 1024 * 1024;
MultipartRequest multiRequest
= new MultipartRequest(request, savePath, maxSize, "UTF-8", new MyFileRenamePolicy());
// 카테고리, 게시글제목, 게시글내용, 첨부파일원본명, 첨부파일경로(폴더경로+수정명 합쳐서 fileURL) 뽑아서 db에 insert 시키기 (Service쪽에 insertBoard 메소드 정의되어있음)
String category = multiRequest.getParameter("category");
String boardTitle = multiRequest.getParameter("title");
String boardContent = multiRequest.getParameter("content");
TestBoard b = new TestBoard();
b.setCategory(category);
b.setBoardTitle(boardTitle);
b.setBoardContent(boardContent);
b.setFileOriginName(multiRequest.getOriginalFileName("upfile"));
// b.setFileURL(savePath + multiRequest.getFilesystemName("upfile")); c부터 시작하는 경로 아님!
b.setFileURL("/resources/upload_files/" + multiRequest.getFilesystemName("upfile"));
int result = new BoardService().insertBoard(b);
//System.out.println("result: " + result);
// 작성 성공시 다시 게시글 목록페이지가 보여지도록 할 것
if(result > 0) {
response.sendRedirect(request.getContextPath() + "/list.bo");
}else {
// 첨부파일이 있었을 경우
// 이미 업로드된 파일 => 더이상 쓸모없음 => 파일제거
String filePath = savePath + multiRequest.getFilesystemName("upfile"); // 삭제할땐 savePath부터 시작하는 경로 맞음.
File failedFile = new File(filePath);
// 파일이 존재하면 삭제
if(failedFile.exists()) {
failedFile.delete();
}
request.setAttribute("msg", "게시글 등록 실패");
request.getRequestDispatcher("/views/common/errorPage.jsp").forward(request, response);
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
- 첨부파일 테이블이 따로 있지 않고, 한 테이블에 첨부파일관련 컬럼이 있다.
- 첨부파일 경로를 db에 기록할 때, "폴더경로" + "수정명"을 합친다.
이때 'savePath + multiRequest.getFilesystemName("upfile")'는 c드라이브부터 시작하는 경로다.
이게 아니라, "/resources/upload_files/" + multiRequest.getFilesystemName("upfile") 이 경로를 사용한다.