웹_프론트_백엔드/JAVA프레임윅기반_풀스택

2020.06.02

shine94 2020. 6. 2. 09:09

[게시판 첨부파일(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