[게시판 첨부파일(write, view)]
1. 시나리오
1) 게시글마다 임의개수의 첨부파일 추가 가능
2) 업로드 경로는 Context Path / upload
3) 업로드시 파일이름 기억(저장)
4) 첨부파일 다운로드 가능
다운로드시 업로드된 파일이름으로 다운받게 하기
5) 글 수정에서 첨부파일 삭제 가능
6) 글 수정에서 첨부파일 새로 추가 가능
7) 글 삭제시 첨부파일도 경로에서 물리적인 삭제
8) 첨부파일 이 이미지인 경우 게시물 화면에 보이기
2. 첨부파일 DDL 작성
** test_write_orcle.erm
** test_write_orcle2.sql
/* Drop Tables */
DROP TABLE test_file CASCADE CONSTRAINTS;
DROP TABLE test_write CASCADE CONSTRAINTS;
/* Create Tables */
CREATE TABLE test_file
(
bf_uid number NOT NULL,
bf_source varchar2(200) NOT NULL,
bf_file varchar2(200) NOT NULL,
wr_uid number NOT NULL,
PRIMARY KEY (bf_uid)
);
CREATE TABLE test_write
(
wr_uid number NOT NULL,
wr_subject varchar2(200) NOT NULL,
wr_content clob,
wr_name varchar2(40) NOT NULL,
wr_viewcnt number DEFAULT 0,
wr_regdate date DEFAUT SYSDATE,
PRIMARY KEY (wr_uid)
);
/* Create Foreign Keys */
ALTER TABLE test_file
ADD FOREIGN KEY (wr_uid)
REFERENCES test_write (wr_uid)
;
-- 시퀀스 작성
CREATE SEQUENCE test_file_seq;
-- 확인용
SELECT * FROM test_write ORDER BY wr_uid DESC;
SELECT * FROM test_file ORDER BY bf_uid DESC;
3. 첨부파일 추가 쿼리문
** common > D.java
package common;
/*
* DB 접속 정보, 쿼리문, 테이블명, 컬럼명 등은
* 별도로 관리하든지
* XML, 초기화 파라미터 등에서 관리하는 것이 좋다.
*/
public class D {
public static final String DRIVER = "oracle.jdbc.driver.OracleDriver"; // JDBC 드라이버 클래스
public static final String URL = "jdbc:oracle:thin:@localhost:1521:XE"; // DB 접속 URL
public static final String USERID = "scott0316"; // DB 접속 계정 정보
public static final String USERPW = "tiger0316";
public static final String SQL_WRITE_SELECT =
"SELECT * FROM test_write ORDER BY wr_uid DESC";
public static final String SQL_WRITE_INSERT = "INSERT INTO test_write " +
"(wr_uid, wr_subject, wr_content, wr_name) " +
"VALUES(test_write_seq.nextval, ?, ?, ?)";
public static final String SQL_WRITE_INC_VIEWCNT = // 조회수 증가
"UPDATE test_write SET wr_viewcnt = wr_viewcnt + 1 WHERE wr_uid = ?";
public static final String SQL_WRITE_SELECT_BY_UID = // 글 읽어 오기
"SELECT * FROM test_write WHERE wr_uid = ?";
public static final String SQL_WRITE_UPDATE =
"UPDATE test_write SET wr_subject = ?, wr_content = ? WHERE wr_uid = ?";
public static final String SQL_WRITE_DELETE_BY_UID =
"DELETE FROM test_write WHERE wr_uid = ?";
// 첨부파일용 쿼리,
// 요구사항에서부터 출발,
// 매우 중요한 작업
// 특정 글(wr_uid)의 첨부파일 1개 INSERT
public static final String SQL_FILE_INSERT =
"INSERT INTO test_file"
+ "(bf_uid, bf_source, bf_file, wr_uid) " /* 기획에 따라 변동이 있을 수 있기 때문에 항목은 모두 작성하는 것이 좋다*/
+ "VALUES"
+ "(test_file_seq.nextval, ?, ?, ?)"
;
// 특정 글(wr_uid)의 첨부파일(들)을 SELECT
public static final String SQL_FILE_SELECT =
"SELECT bf_uid, bf_source, bf_file FROM test_file "
+ "WHERE wr_uid = ? "
+ "ORDER BY bf_uid DESC"
;
// 특정 첨부파일(bf_uid) 하나를 SELECT
public static final String SQL_FILE_SELECT_BY_UID =
"SELECT bf_uid, bf_source, bf_file FROM test_file "
+ "WHERE bf_uid = ?"
;
// 특정 첨부파일 (bf_uid) 하나를 DELETE
public static final String SQL_FILE_DELETE_BY_UID =
"DELETE FROM test_file WHERE bf_uid = ?"
;
// 특정 글 (wr_uid) 의 첨부파일(들)을 DELETE
public static final String SQL_FILE_DELETE_BY_WRUID =
"DELETE FROM test_file WHERE wr_uid = ?"
;
}
4. 첨부파일 용 DTO 빈 객체 작성
** com.lec.beans > FileDTO.java
package com.lec.beans;
public class FileDTO {
private int uid; // bf_uid
private String source; // bf_source
private String file; // bf_file
private boolean isImage; // 이미지 여부
// 생성자
public FileDTO() {}
public FileDTO(int uid, String source, String file) {
super();
this.uid = uid;
this.source = source;
this.file = file;
}
// getter & setter
public int getUid() {
return uid;
}
public void setUid(int uid) {
this.uid = uid;
}
public String getSource() {
return source;
}
public void setSource(String source) {
this.source = source;
}
public String getFile() {
return file;
}
public void setFile(String file) {
this.file = file;
}
public boolean isImage() {
return isImage;
}
public void setImage(boolean isImage) {
this.isImage = isImage;
}
}
5. 첨부파일용 DAO 작성
** com.lec.beans > FileDAO.java
package com.lec.beans;
import java.sql.Connection;
import java.sql.Date;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Time;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import common.D;
// DAO : Data Access Object
// DB 에 접속하여 트랜잭션을 수행하는 객체
// 다루는 데이터 소스의 종류에 따라 DAO는 여러개 정의 사용 가능
public class FileDAO {
Connection conn = null;
Statement stmt = null;
PreparedStatement pstmt = null;
ResultSet rs = null; // SELECT 결과, executeQuery()
// DAO 객체가 생성될때 Connection 도 생성된다.
public FileDAO() {
try {
Class.forName(D.DRIVER);
conn = DriverManager.getConnection(D.URL, D.USERID, D.USERPW);
System.out.println("WriteDAO 생성, 데이터 베이스 연결!");
} catch(Exception e) {
e.printStackTrace();
// throw e;
}
} // 생성자
// DB 자원 반납 메소드,
public void close() throws SQLException {
if(rs != null) rs.close();
if(pstmt != null) pstmt.close();
if(stmt != null) stmt.close();
if(conn != null) conn.close();
} // end close()
} // end DAO
6. 글 작성(write 화면 수정)
: write.jsp 수정, WriteDAO.java 수정[insert 추가(오버로딩)], WriteCommand.java 수정
** write.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>글작성</title>
</head>
<script>
function chkSubmit(){ // 폼 검증
frm = document.forms["frm"];
var name = frm["name"].value.trim();
var subject = frm["subject"].value.trim();
if(name == ""){
alert("작성자 란은 반드시 입력해야 합니다");
frm["name"].focus();
return false;
}
if(subject == ""){
alert("제목은 반드시 작성해야 합니다");
frm["subject"].focus();
return false;
}
return true;
}
</script>
<body>
<h2>글작성</h2>
<%-- 글 내용이 많을수 있기 때문에 POST 방식 사용 --%>
<form name="frm" action="writeOk.do" method="post" onsubmit="return chkSubmit()"
enctype="Multipart/form-data">
작성자:
<input type="text" name="name"/><br>
제목:
<input type="text" name="subject"/><br>
내용:<br>
<textarea name="content"></textarea>
<br><br>
<%-- 첨부파일 --%>
<div style="background-color: beige; padding: 2px 10px; margin-bottom: 5px; border: 1px solid black;">
<h4>첨부파일</h4>
<button type="button" id="btnAdd">추가</button>
<div id='files'></div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script>
var i = 0;
$("#btnAdd").click(function(){
$("#files").append("<div><input type='file' name='upfile" + i + "'/><button type='button' onclick='$(this).parent().remove()'>삭제</button></div>");
i++;
});
</script>
<input type="submit" value="등록"/>
</form>
<br>
<button type="button" onclick="location.href='list.do'">목록으로</button>
</body>
</html>
** com.lec.beans > WriteDAO.java
package com.lec.beans;
import java.sql.Connection;
import java.sql.Date;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Time;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import common.D;
// DAO : Data Access Object
// DB 에 접속하여 트랜잭션을 수행하는 객체
// 다루는 데이터 소스의 종류에 따라 DAO는 여러개 정의 사용 가능
public class WriteDAO {
Connection conn = null;
Statement stmt = null;
PreparedStatement pstmt = null;
ResultSet rs = null; // SELECT 결과, executeQuery()
// DAO 객체가 생성될때 Connection 도 생성된다.
public WriteDAO() {
try {
Class.forName(D.DRIVER);
conn = DriverManager.getConnection(D.URL, D.USERID, D.USERPW);
System.out.println("WriteDAO 생성, 데이터 베이스 연결!");
} catch(Exception e) {
e.printStackTrace();
// throw e;
}
} // 생성자
// DB 자원 반납 메소드,
public void close() throws SQLException {
if(rs != null) rs.close();
if(pstmt != null) pstmt.close();
if(stmt != null) stmt.close();
if(conn != null) conn.close();
} // end close()
// 새글 작성 <-- DTO
public int insert(WriteDTO dto) throws SQLException {
String subject = dto.getSubject();
String content = dto.getContent();
String name = dto.getName();
int cnt = this.insert(subject, content, name);
return cnt;
}
// 새글 작성 <-- 제목, 내용, 작성자
public int insert(String subject, String content, String name) throws SQLException {
int cnt = 0;
try {
pstmt = conn.prepareStatement(D.SQL_WRITE_INSERT);
pstmt.setString(1, subject);
pstmt.setString(2, content);
pstmt.setString(3, name);
cnt = pstmt.executeUpdate();
} finally {
close();
}
return cnt;
}
// 새글 작성 <-- 제목, 내용, 작성자
// <-- 첨부파일(들)
public int insert(String subject, String content, String name,
/* 이미 파일은 저장되어 있다 (cos 라이브러리) */
List<String> orginalFileName, // 원본파일명
List<String> fileSystemNames // 저장된 파일명(들)
) throws SQLException {
int cnt = 0;
int uid = 0; // INSERT 된 글의 wr_uid 값
try {
// 자동 생성된 컬럼의 이름(들)이 담긴 배열 준비(auto-generated keys)
String[] generatedCols = {"wr_uid"};
// Statement나 PreparedStatement 생성시 두번째 매개변수로
// auto-generated keys 배열 넘겨줌
pstmt = conn.prepareStatement(D.SQL_WRITE_INSERT, generatedCols);
pstmt.setString(1, subject);
pstmt.setString(2, content);
pstmt.setString(3, name);
cnt = pstmt.executeUpdate();
// auto-generated keys 값 뽑아오기
rs = pstmt.getGeneratedKeys(); // 리턴값이 ResultSet임
if(rs.next()) {
uid = rs.getInt(1); // 첫번째 컬럼
}
pstmt.close();
// 첨부파일(들) 정보 테이블에 INSERT 하기
pstmt = conn.prepareStatement(D.SQL_FILE_INSERT);
for(int i = 0; i < orginalFileName.size(); i++) {
pstmt.setString(1, orginalFileName.get(i));
pstmt.setString(2, orginalFileName.get(i));
pstmt.setInt(3, uid);
pstmt.executeUpdate();
} // end for()
} finally {
close();
}
return cnt;
}
// ResultSet --> DTO 배열로 리턴
public WriteDTO [] createArray(ResultSet rs) throws SQLException {
WriteDTO [] arr = null; // DTO 배열
ArrayList<WriteDTO> list = new ArrayList<WriteDTO>();
while(rs.next()) {
int uid = rs.getInt("wr_uid");
String subject = rs.getString("wr_subject");
String name = rs.getString("wr_name");
String content = rs.getString("wr_content");
int viewCnt = rs.getInt("wr_viewcnt");
Date d = rs.getDate("wr_regdate");
Time t = rs.getTime("wr_regdate");
String regDate = "";
if(d != null){
regDate = new SimpleDateFormat("yyyy-MM-dd").format(d) + " "
+ new SimpleDateFormat("hh:mm:ss").format(t);
}
WriteDTO dto = new WriteDTO(uid, subject, content, name, viewCnt);
dto.setRegDate(regDate);
list.add(dto);
} // end while
int size = list.size();
if(size == 0) return null;
arr = new WriteDTO[size];
list.toArray(arr); // List -> 배열
return arr;
}
// 전체 SELECT
public WriteDTO [] select() throws SQLException {
WriteDTO [] arr = null;
try {
pstmt = conn.prepareStatement(D.SQL_WRITE_SELECT);
rs = pstmt.executeQuery();
arr = createArray(rs);
} finally {
close();
}
return arr;
} // end select()
// 특정 uid 의 글 내용 읽기, 조회수 증가
// viewCnt 도 1 증가 해야 하고, 글 읽어와야 한다 --> 트랜잭션 처리
public WriteDTO [] readByUid(int uid) throws SQLException{
int cnt = 0;
WriteDTO [] arr = null;
try {
// 트랜잭션 처리
// Auto-commit 비활성화
conn.setAutoCommit(false);
// 쿼리들 수행
pstmt = conn.prepareStatement(D.SQL_WRITE_INC_VIEWCNT);
pstmt.setInt(1, uid);
cnt = pstmt.executeUpdate();
pstmt.close();
pstmt = conn.prepareStatement(D.SQL_WRITE_SELECT_BY_UID);
pstmt.setInt(1, uid);
rs = pstmt.executeQuery();
arr = createArray(rs);
conn.commit();
} catch(SQLException e) {
conn.rollback();
throw e;
} finally {
close();
}
return arr;
} // end readByUid()
// 특정 uid 의 글 만 SELECT (조회수 증가 없슴!)
public WriteDTO [] selectByUid(int uid) throws SQLException {
WriteDTO [] arr = null;
try {
pstmt = conn.prepareStatement(D.SQL_WRITE_SELECT_BY_UID);
pstmt.setInt(1, uid);
rs = pstmt.executeQuery();
arr = createArray(rs);
} finally {
close();
}
return arr;
}
// 특정 uid 의 글 수정 (제목, 내용)
public int update(int uid, String subject, String content) throws SQLException {
int cnt = 0;
try {
pstmt = conn.prepareStatement(D.SQL_WRITE_UPDATE);
pstmt.setString(1, subject);
pstmt.setString(2, content);
pstmt.setInt(3, uid);
cnt = pstmt.executeUpdate();
} finally {
close();
}
return cnt;
} // end update()
// 특정 uid 글 삭제하기
public int deleteByUid(int uid) throws SQLException {
int cnt = 0;
try {
pstmt = conn.prepareStatement(D.SQL_WRITE_DELETE_BY_UID);
pstmt.setInt(1, uid);
cnt = pstmt.executeUpdate();
} finally {
close();
}
return cnt;
} // end deleteByUid()
} // end DAO
** WriteCommand.java
package com.command.write;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.lec.beans.WriteDAO;
import com.oreilly.servlet.MultipartRequest;
import com.oreilly.servlet.multipart.DefaultFileRenamePolicy;
import com.oreilly.servlet.multipart.FileRenamePolicy;
public class WriteCommand implements Command {
@Override
public void execute(HttpServletRequest request, HttpServletResponse response) {
int cnt = 0;
WriteDAO dao = new WriteDAO();
// ---------------------------------------------
// 업로드 파일
ServletContext context = request.getServletContext();
String saveDirectory = context.getRealPath("upload");
int maxPostSize = 5 * 1024 * 1024;
String encoding = "utf-8";
FileRenamePolicy policy = new DefaultFileRenamePolicy();
MultipartRequest multi = null;
try {
multi = new MultipartRequest(
request,
saveDirectory,
maxPostSize,
encoding,
policy
);
} catch (IOException e1) {
e1.printStackTrace();
}
List<String> originalFileNames = new ArrayList<String>();
List<String> fileSystemNames = new ArrayList<String>();
Enumeration names = multi.getFileNames(); // type="file"요소의 name들 추출
while(names.hasMoreElements()) {
String name = (String)names.nextElement();
String originalFileName = multi.getOriginalFileName(name);
String fileSystemName = multi.getFilesystemName(name);
System.out.println("첨부파일 : " + originalFileName + " -> " + fileSystemName);
if(originalFileName != null && fileSystemName != null) {
originalFileNames.add(originalFileName);
fileSystemNames.add(fileSystemName);
}
} // end while()
// 매개변수 받아오기
// ★ MultipartRequest 객체 사용
String name = multi.getParameter("name");
String subject = multi.getParameter("subject");
String content = multi.getParameter("content");
if(name != null && subject != null &&
name.trim().length() > 0 && subject.trim().length() > 0) {
try {
// ★ 첨부파일 정보와 같이 INSERT
cnt = dao.insert(subject, content, name, originalFileNames, fileSystemNames);
} catch(SQLException e) {
e.printStackTrace();
}
} // end if
request.setAttribute("result", cnt);
} // end execute()
} // end Command
[write 결과]
[문제점] View 화면에서 업로드한 파일을 볼 수 없음
7. 글 읽기(View 화면 수정)
: FileDAO.java 추가, ViewCommand.java 수정, view.jsp 수정
** com.lec.beans > FileDAO.java
package com.lec.beans;
import java.sql.Connection;
import java.sql.Date;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Time;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import common.D;
// DAO : Data Access Object
// DB 에 접속하여 트랜잭션을 수행하는 객체
// 다루는 데이터 소스의 종류에 따라 DAO는 여러개 정의 사용 가능
public class FileDAO {
Connection conn = null;
Statement stmt = null;
PreparedStatement pstmt = null;
ResultSet rs = null; // SELECT 결과, executeQuery()
// DAO 객체가 생성될때 Connection 도 생성된다.
public FileDAO() {
try {
Class.forName(D.DRIVER);
conn = DriverManager.getConnection(D.URL, D.USERID, D.USERPW);
System.out.println("WriteDAO 생성, 데이터 베이스 연결!");
} catch(Exception e) {
e.printStackTrace();
// throw e;
}
} // 생성자
// DB 자원 반납 메소드,
public void close() throws SQLException {
if(rs != null) rs.close();
if(pstmt != null) pstmt.close();
if(stmt != null) stmt.close();
if(conn != null) conn.close();
} // end close()
// 뷰를 하기 위해 준비
// createArray, selectFilesByWrUid, selectByUid
// ResultSet --> DTO 배열로 리턴
public FileDTO[] createArray(ResultSet rs) throws SQLException {
FileDTO[] arr = null;
List<FileDTO> list = new ArrayList<FileDTO>();
while(rs.next()){
int uid = rs.getInt("bf_uid");
String source = rs.getString("bf_source");
String file = rs.getString("bf_file");
FileDTO dto = new FileDTO(uid, source, file);
list.add(dto);
} // end while()
arr = new FileDTO[list.size()];
list.toArray(arr);
return arr;
} // end createArray()
// 특정 글 (wr_uid) 의 첨부파일(들) SELECT
public FileDTO [] selectFilesByWrUid(int wrUid) throws SQLException{
FileDTO [] arr = null;
try {
pstmt = conn.prepareStatement(D.SQL_FILE_SELECT);
pstmt.setInt(1, wrUid);
rs = pstmt.executeQuery();
arr = createArray(rs);
} finally {
close();
}
return arr;
} // end selectFilesByWrUid
// 특정 파일(bf_uid)의 첨부파일 하나 SELECT
public FileDTO[] selectByUid(int uid) throws SQLException {
FileDTO [] arr = null;
try {
pstmt = conn.prepareStatement(D.SQL_FILE_SELECT_BY_UID);
pstmt.setInt(1, uid);
rs = pstmt.executeQuery();
arr = createArray(rs);
} finally {
close();
}
return arr;
} // end selectByUid
} // end DAO
** com.command.write > ViewCommand.java
package com.command.write;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.sql.SQLException;
import javax.imageio.ImageIO;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.lec.beans.FileDAO;
import com.lec.beans.FileDTO;
import com.lec.beans.WriteDAO;
import com.lec.beans.WriteDTO;
public class ViewCommand implements Command {
@Override
public void execute(HttpServletRequest request, HttpServletResponse response) {
WriteDAO dao = new WriteDAO();
WriteDTO [] arr = null;
// 첨부파일
FileDAO fileDao = new FileDAO();
FileDTO[] fileArr = null;
int uid = Integer.parseInt(request.getParameter("uid")); // 매개변수 검증 필요
try {
arr = dao.readByUid(uid); // 읽기 + 조회수 증가
request.setAttribute("list", arr);
} catch (SQLException e) { // 만약 ConnectionPool 을 사용한다면 여기서 NamingException 도 catch 해야 한다
e.printStackTrace();
}
// 첨부파일 읽어 들이기
try {
if(arr != null && arr.length == 1) {
fileArr = fileDao.selectFilesByWrUid(uid); // 첨부파일 읽어오기
// 이미지 파일 여부 세팅
String realPath = "";
String saveFolder = "upload";
ServletContext context = request.getServletContext();
realPath = context.getRealPath(saveFolder);
for(FileDTO fileDto : fileArr) {
String downloadedFilePath = realPath + File.separator + fileDto.getFile();
BufferedImage imgData = ImageIO.read(new File(downloadedFilePath));
if(imgData != null) {
fileDto.setImage(true); // 이미지 다!
}
}
request.setAttribute("file", fileArr);
}
} catch(SQLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
} // end execute()
} // end Command
** view.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<c:choose>
<c:when test="${empty list || fn:length(list) == 0}">
<script>
alert("해당 정보가 삭제되거나 없습니다");
history.back();
</script>
</c:when>
<c:otherwise>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>읽기 ${list[0].subject}</title> <!-- title에 글제목 넣기 -->
</head>
<script>
function chkDelete(uid){
// 삭제 여부, 다시 확인 하고 진행하기
var r = confirm("삭제하시겠습니까?");
if(r){
location.href = 'deleteOk.do?uid=' + uid;
}
}
</script>
<body>
<h2>읽기 ${list[0].subject}</h2>
<br>
UID : ${list[0].uid}<br>
작성자 : ${list[0].name}<br>
제목 : ${list[0].subject}<br>
등록일 : ${list[0].regDate}<br>
조회수 : ${list[0].viewCnt}<br>
내용: <br>
<hr>
<div>
${list[0].content}
</div>
<hr>
<%-- 첨부파일 및 다운로드 링크 --%>
<c:if test="${fn:length(file) > 0 }">
<h4>첨부파일</h4>
<ul>
<c:forEach var="element" items="${file }">
<li><a href="download.do?uid=${element.uid }">${element.source }</a></li>
</c:forEach>
</ul>
</c:if>
<%-- 이미지인 경우 보여주기 --%>
<c:forEach var="element" items="${file }">
<c:if test="${element.image == true }">
<div style="width:300px">
<img style="width:100%; height:auto"
src="upload/${element.file }"
/>
</div>
</c:if>
</c:forEach>
<br>
<button onclick="location.href='update.do?uid=${list[0].uid}'">수정하기</button>
<button onclick="location.href = 'list.do'">목록보기</button>
<button onclick="chkDelete(${list[0].uid})">삭제하기</button>
<button onclick="location.href = 'write.do'">신규등록</button>
</body>
</html>
</c:otherwise>
</c:choose>
[파일 읽기 완료, view단에 업로드한 이미지 확인 가능]
8. 파일 다운로드
: WriteController 서블릿 수정, DownLoadCommand.java 추가
** WriteControlloer 서블릿
package com.controller;
import java.io.IOException;
import javax.servlet.RequestDispatcher;
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.command.write.*;
@WebServlet("*.do")
public class WriteController extends HttpServlet {
private static final long serialVersionUID = 1L;
public WriteController() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
actionDo(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
actionDo(request, response);
}
protected void actionDo(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("actionDo() 호출");
request.setCharacterEncoding("UTF-8");
// 컨트롤러는 다음 두개를 선택해야 한다.
String viewPage = null; // 어떠한 뷰? --> 페이지
Command command = null; // 어떠한 커맨드? --> 어떠한 로직 수행.
// URL로부터 URI, ContextPath, Command 분리
String uri = request.getRequestURI();
String conPath = request.getContextPath();
String com = uri.substring(conPath.length());
// 테스트 출력
System.out.println("uri: " + uri);
System.out.println("conPath: " + conPath);
System.out.println("com: " + com);
// 컨트롤러는 커맨드에 따라, 로직을 수행하고
// 결과를 내보낼 view 를 결정한다
switch(com) {
case "/list.do":
command = new ListCommand();
command.execute(request, response);
viewPage = "list.jsp";
break;
case "/write.do":
viewPage = "write.jsp";
break;
case "/writeOk.do":
command = new WriteCommand();
command.execute(request, response);
viewPage = "writeOk.jsp";
break;
case "/view.do":
command = new ViewCommand();
command.execute(request, response);
viewPage = "view.jsp";
break;
case "/update.do":
command = new SelectCommand(); // '수정' 이지만, 일단 읽어오는것부터 시작이다.
command.execute(request, response);
viewPage = "update.jsp";
break;
case "/updateOk.do":
command = new UpdateCommand();
command.execute(request, response);
viewPage = "updateOk.jsp";
break; // 디버깅 훈련, 이 break를 없애고, 찾아보기
case "/deleteOk.do":
command = new DeleteCommand();
command.execute(request, response);
viewPage = "deleteOk.jsp";
break;
// 파일 다운로드
case "/download.do":
command = new DownloadCommand();
command.execute(request, response);
// 굳이 view 필요하지 않는다
break;
} // end switch
// request 를 위에서 결정된 view 에 forward 해줌.
if(viewPage != null) {
RequestDispatcher dispatcher = request.getRequestDispatcher(viewPage);
dispatcher.forward(request, response);
}
} // end actionDo()
}
** DownloadCommand.java
package com.command.write;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URLEncoder;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.lec.beans.FileDAO;
import com.lec.beans.FileDTO;
public class DownloadCommand implements Command {
@Override
public void execute(HttpServletRequest request, HttpServletResponse response) {
FileDAO fileDao = new FileDAO();
FileDTO[] fileArr = null;
int uid = Integer.parseInt(request.getParameter("uid"));
FileInputStream in = null;
ServletOutputStream sout = null;
try {
fileArr = fileDao.selectByUid(uid); // 특정 파일 (하나) 정보 읽어오기
String fileSystemName = fileArr[0].getFile(); // 저장된 파일명
String originalFileName = fileArr[0].getSource(); // 원본 파일명
String realPath = request.getServletContext().getRealPath("upload");
String downloadFilePath = realPath + File.pathSeparator + fileSystemName;
System.out.println("downloadFilePath: " + downloadFilePath);
String fileType = request.getServletContext().getMimeType(downloadFilePath);
// 파일 유형이 지정되지 않은 경우
if(fileType == null) {
fileType = "application/octet-stream";
}
response.setContentType(fileType);
// 원본 파일명으로 다운 받을 수 있게 처리
String enc = "utf-8";
String encFileName = URLEncoder.encode(originalFileName, enc);
response.setHeader("Content-Disposition", "attachment; filename=" +encFileName);
File srcFile = new File(downloadFilePath);
in = new FileInputStream(srcFile);
sout = response.getOutputStream();
byte[] buff = new byte[(int)srcFile.length()]; // 파일 크기만큼 버퍼 준비
int numRead = 0;
int totalRead = 0;
// 파일로부터 읽기
while((numRead = in.read(buff, 0, buff.length)) != -1) {
totalRead += numRead;
sout.write(buff, 0, numRead);
} // end while
System.out.println("전송한 byte: " + totalRead + " bytes");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if(sout != null) {
sout.flush();
sout.close();
}
if(in != null) {in.close();}
} catch (IOException e) {
e.printStackTrace();
}
}
} // end execute()
} // end Command
[최종 다운로드된 결과물]
'웹_프론트_백엔드 > JAVA프레임윅기반_풀스택' 카테고리의 다른 글
2020.06.05 (0) | 2020.06.05 |
---|---|
2020.06.03 (0) | 2020.06.03 |
2020.06.01 (0) | 2020.06.01 |
2020.05.28 (0) | 2020.05.28 |
2020.05.27 (0) | 2020.05.27 |