파일 업로드 및 파일과 DB를 연동하기 위한 웹프로그램 작성

woom·2023년 3월 7일
0

Framework

목록 보기
20/20
post-thumbnail

🌼 파일 업로드

  • 파일 업로드 : 클라이언트로부터 파일을 입력받아 서버 디렉토리에 저장하는 기능
    • 파일을 입력받아 전달하기 위한 form 태그를 사용하며 요청방식(method 속성)은 반드시 [post]로 설정하고 전달형태(enctype 속성)은 [mulitpart/form-data]로 설정
    • <form action="upload" method="post" enctype="multipart/form-data">
  • 파일 업로드 처리를 위한 환경설정 방법
  1. commons-fileupload 라이브러리를 프로젝트에 빌드 처리 (메이븐 : pom.xml)

  2. Spring Bean Configuration File(servlet-context.xml)에 파일 업로드 기능을 제공하는 클래스를 Spring Bean으로 등

  3. MultipartHttpServletRequest 객체를 사용하여 [multipart/form-data] 형태로 전달된 값 또는 파일 처리


📕 pom.xml

  • 파일 업로드 기능을 제공하는 라이브러리 빌드 처리

		<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
		<dependency>
		    <groupId>commons-fileupload</groupId>
		    <artifactId>commons-fileupload</artifactId>
		    <version>1.5</version>
		</dependency>



📕 servlet-context.xml

  • 파일 업로드 기능을 제공하는 클래스를 Spring Bean으로 등록
    • Spring Bean의 식별자(beanName)을 반드시 [multipartResolver]로 설정

	<beans:bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver" id="multipartResolver">
		<!-- maxUploadSize 필드에 최대 업로드 파일의 제한 용량(Byte)을 주입 -->
		<beans:property name="maxUploadSize" value="20971520"/>
		<!-- defaultEncoding 필드에 전달값에 대한 문자형태(캐릭터셋)을 주입 -->
		<beans:property name="defaultEncoding" value="utf-8"/>
	</beans:bean>




📙 Controller class

  • WebApplicationContext 객체(Spring Container)를 제공받아 필드에 의존성 주입 → ServletContext 객체를 제공받아 사용 (디렉토리의 시스템 경로)

방법1

  • 요청 처리 메소드에 MultipartHttpServletRequest 인터페이스로 매개변수를 선언하면 Front Controller에 의해 MultipartHttpServletRequest 객체를 제공받아 사용 가능
    • MultipartHttpServletRequest 객체 : [multipart/form-data] 형식으로 전달된 값 또는 파일을 처리하기 위한 객체
    • MultipartHttpServletRequest.getParameter(String name) : [multipart/form-data] 형식으로 전달된 값을 문자열(String 객체)로 반환하는 메소드
    • String uploaderName=request.getParameter("uploaderName");
    • MultipartHttpServletRequest.getFile(String name) : [multipart/form-data] 형식으로 전달된 파일을 MultipartFile 객체로 반환하는 메소드
    • MultipartFile 객체 : 사용자로부터 입력되어 전달된 파일정보를 저장하기 위한 객체
    • MultipartFile uploadFile=request.getFile("uploadFile");
  • 전달받은 파일에 대한 검증 작업

    • MultipartFile.isEmpty() : MultipartFile 객체에 파일정보가 없는 경우 [false]를 반환하고 파일정보가 있는 경우 [true]를 반환하는 메소드

    • MultipartFile.getContentType() : MultipartFile 객체에 저장된 파일의 형식(MimeType)를 반환하는 메소드
    • MultipartFile.getBytes() : MultipartFile 객체에 저장된 파일정보를 byte 배열(파일크기)로 반환하는 메소드
    • 전달파일을 저장하기 위한 서버 디렉토리의 시스템 경로를 반환받아 저장
    • String uploadDirectory=request.getServletContext().getRealPath("/resources/images/upload");
  • 전달파일을 서버 디렉토리에 저장하기 위한 File 객체 생성
    • File 객체 : 시스템에 존재하는 파일정보를 저장하기 위한 객체
    • MultipartFile.getOriginalFilename() : 전달파일의 파일명을 반환하는 메소드
    • File file=new File(uploadDirectory, uploadFile.getOriginalFilename());
    • MultipartFile.transferTo(File file) : MultipartFile 객체에 저장된 파일정보를 File 객체(서버 디렉토리)에 저장된 파일정보로 전달하여 저장하는 메소드 (업로드 처리 메소드)
    • uploadFile.transferTo(file);

방법2

  • 요청 처리 메소드에 매개변수를 작성하여 전달값과 전달파일을 제공받아 사용 가능
    • public String upload(@RequestParam String uploaderName, @RequestParam MultipartFile uploadFile, Model model)
    • 업로드 파일과 같은 이름의 파일이 서버 디렉토리에 존재할 경우 기존 파일 대신 업로드 파일이 저장 : 덮어씌위기(OverWrite)
    • 전달파일을 저장하기 위한 서버 디렉토리의 시스템 경로를 반환받아 저장
    • WebApplicationContext 객체(Spring Container)에게 ServletContext 객체를 제공받아 사용```
    • String uploadDirectory=context.getServletContext().getRealPath("/resources/images/upload");
    • 사용자로부터 입력되어 전달된 원본 파일명을 반환받아 저장
    • String originalFilename=uploadFile.getOriginalFilename();
    • 서버 디렉토리에 저장하기 위한 파일정보가 저장된 File 객체 생성
    • File file=new File(uploadDirectory, originalFilename);
    • 서버 디렉토리에 저장될 파일명을 저장하기 위한 변수 (초기값으로 사용자로부터 입력되어 전달된 원본 파일명을 저장)
    • String uploadFilename=originalFilename;
  • 업로드 파일과 같은 이름의 파일이 서버 디렉토리에 존재할 경우 서버 디렉토리에 저장될 파일명을 구분하기 위한 식별자를 저장가능


package xyz.itwill10.controller;

@Controller
@RequiredArgsConstructor
public class FileController {
	//WebApplicationContext 객체(Spring Container)를 제공받아 필드에 의존성 주입
	private final WebApplicationContext context;	
	
	@RequestMapping(value = "/upload", method = RequestMethod.GET)
	public String upload() {
		return "file/upload_form";
	}
	
	/*
	//요청 처리 메소드에 MultipartHttpServletRequest 인터페이스로 매개변수를 선언하면 Front
	//Controller에 의해 MultipartHttpServletRequest 객체를 제공받아 사용 가능
	//MultipartHttpServletRequest 객체 : [multipart/form-data] 형식으로 전달된 값 또는 파일을
	//처리하기 위한 객체
	@RequestMapping(value = "/upload", method = RequestMethod.POST)
	public String upload(MultipartHttpServletRequest request) throws IOException {
		//MultipartHttpServletRequest.getParameter(String name) : [multipart/form-data] 
		//형식으로 전달된 값을 문자열(String 객체)로 반환하는 메소드
		String uploaderName=request.getParameter("uploaderName");
		
		//MultipartHttpServletRequest.getFile(String name) : [multipart/form-data] 형식으로 
		//전달된 파일을 MultipartFile 객체로 반환하는 메소드
		//MultipartFile 객체 : 사용자로부터 입력되어 전달된 파일정보를 저장하기 위한 객체
		MultipartFile uploadFile=request.getFile("uploadFile");
	
		//전달받은 파일에 대한 검증 작업
		//MultipartFile.isEmpty() : MultipartFile 객체에 파일정보가 없는 경우 [false]를 반환하고 
		//파일정보가 있는 경우 [true]를 반환하는 메소드
		if(uploadFile.isEmpty()) {
			return "file/upload_fail";
		}
		
		//MultipartFile.getContentType() :  MultipartFile 객체에 저장된 파일의 형식(MimeType)를 반환하는 메소드 
		System.out.println("파일 형식 = "+uploadFile.getContentType());
		//MultipartFile.getBytes() : MultipartFile 객체에 저장된 파일정보를 byte 배열로 반환하는 메소드
		System.out.println("파일 크기 = "+uploadFile.getBytes().length);
	
		//전달파일을 저장하기 위한 서버 디렉토리의 시스템 경로를 반환받아 저장
		String uploadDirectory=request.getServletContext().getRealPath("/resources/images/upload");
		System.out.println("uploadDirectory = "+uploadDirectory);
		
		//전달파일을 서버 디렉토리에 저장하기 위한 File 객체 생성
		//File 객체 : 시스템에 존재하는 파일정보를 저장하기 위한 객체
		//MultipartFile.getOriginalFilename() : 전달파일의 파일명을 반환하는 메소드
		File file=new File(uploadDirectory, uploadFile.getOriginalFilename());
		
		//MultipartFile.transferTo(File file) : MultipartFile 객체에 저장된 파일정보를
		//File 객체에 저장된 파일정보로 전달하여 저장하는 메소드 - 업로드 처리 메소드
		uploadFile.transferTo(file);
		
		request.setAttribute("uploaderName", uploaderName);
		request.setAttribute("uploadFilename", uploadFile.getOriginalFilename());
		
		return "file/upload_ok";
	}
	*/
	
	//요청 처리 메소드에 매개변수를 작성하여 전달값과 전달파일을 제공받아 사용 가능
	// => 업로드 파일과 같은 이름의 파일이 서버 디렉토리에 존재할 경우 기존 파일 대신 업로드
	//파일이 저장 - 덮어씌위기(OverWrite)
	// => commons-fileupload 라이브러리에는 업로드 파일을 변경하는 기능의 클래스 미존재
	// => 업로드 파일과 같은 이름의 파일이 서버 디렉토리에 존재할 경우 업로드 파일명을 변경하는 명령 작성 필요
	@RequestMapping(value = "/upload", method = RequestMethod.POST)
	public String upload(@RequestParam String uploaderName
			, @RequestParam MultipartFile uploadFile, Model model) throws IOException {
		if(uploadFile.isEmpty()) {
			return "file/upload_fail";
		}
	
		//전달파일을 저장하기 위한 서버 디렉토리의 시스템 경로를 반환받아 저장
		// => WebApplicationContext 객체(Spring Container)에게 ServletContext 객체를 제공받아 사용
		String uploadDirectory=context.getServletContext().getRealPath("/resources/images/upload");
		
		//사용자로부터 입력되어 전달된 원본 파일명을 반환받아 저장
		String originalFilename=uploadFile.getOriginalFilename();
		
		//서버 디렉토리에 저장하기 위한 파일정보가 저장된 File 객체 생성
		File file=new File(uploadDirectory, originalFilename);
		
		//서버 디렉토리에 저장될 파일명을 저장하기 위한 변수
		// => 초기값으로 사용자로부터 입력되어 전달된 원본 파일명을 저장
		String uploadFilename=originalFilename;
		
		//업로드 파일과 같은 이름의 파일이 서버 디렉토리에 존재할 경우 서버 디렉토리에 
		//저장될 파일명을 구분하기 위한 식별자를 저장하기 위한 변수
		int i=0;
		
		//File.exists() : File 객체에 저장된 파일이 시스템이 존재하지 않을 경우 [false]를
		//반환하고 존재할 경우 [true]를 반환하는 메소드
		while(file.exists()) {//업로드 파일과 같은 이름의 파일이 서버 디렉토리에 존재할 경우 반복 처리
			i++;
			
			//파일명과 확장자를 구분하기 위한 문자열(.)를 사용하여 위치값(Index)을 반환받아 저장
			int index=originalFilename.lastIndexOf(".");

			//원본 파일명을 이용하여 업로드 파일명 생성
			uploadFilename=originalFilename.substring(0, index)+"_"+i+originalFilename.substring(index);
			
			//서버 디렉토리에 저장될 파일명을 저장하기 위한 변수
			file=new File(uploadDirectory, uploadFilename);
		}
		//파일의 이름을 변경하여 업로드 처리
		uploadFile.transferTo(file);
		
		model.addAttribute("uploaderName", uploaderName);
		model.addAttribute("originalFilename", originalFilename);
		model.addAttribute("uploadFilename", uploadFilename);
		
		return "file/upload_ok";
	}
}





🐣 view (upload form)


<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>SPRING</title>
</head>
<body>
	<h1>파일 업로드</h1>
	<hr>
	<%-- 파일 업로드 : 클라이언트로부터 파일을 입력받아 서버 디렉토리에 저장하는 기능 --%>
	<%-- => 파일을 입력받아 전달하기 위한 form 태그를 사용하며 요청방식(method 속성)은
	반드시 [post]로 설정하고 전달형태(enctype 속성)은 [mulitpart/form-data]로 설정 --%>
	<form action="upload" method="post" enctype="multipart/form-data">
	<table>
		<tr>
			<td>업로더 이름</td>
			<td><input type="text" name="uploaderName"></td>
		</tr>
		<tr>
			<td>업로드 파일</td>
			<td><input type="file" name="uploadFile"></td>
		</tr>
		<tr>
			<td colspan="2"><button type="submit">업로드</button></td>
		</tr>
	</table>
	</form>
</body>
</html>





🐣 view (upload success)


<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>SPRING</title>
</head>
<body>
	<h1>파일 업로드 성공</h1>
	<hr>
	<%-- 
	<p>업로더 이름 = ${uploaderName }</p>
	<p>업로드 파일명 = ${uploadFilename }</p>
	--%>
	
	<p>업로더 이름 = ${uploaderName }</p>
	<p>원본 파일명 = ${originalFilename }</p>
	<p>업로드 파일명 = ${uploadFilename }</p>
</body>
</html>





🐣 view (upload fail)


<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>SPRING</title>
</head>
<body>
	<h1>파일 업로드 실패</h1>
	<hr>
</body>
</html>






🌼 파일 전송 웹프로그램

  1. table
  2. DTO Class
  3. XML Mapper
  4. Interface Mapper
  5. DAO Interface
  6. DAO Class
  7. Service Interface
  8. Service Class
  9. Controller 클래스 (Model)
  10. HTML 문서를 JSP 문서로 변환

📕 1. table 생성


create table fileboard(num number primary key, writer varchar2(20), subject varchar2(100),
origin varchar2(100), upload varchar2(100));
create sequence fileboard_seq;


📕 2. DTO Class

package xyz.itwill10.dto;

/*
이름      널?       유형            
------- -------- ------------- 
NUM     NOT NULL NUMBER         - 글번호      
WRITER           VARCHAR2(20)   - 작성자
SUBJECT          VARCHAR2(100)  - 제목
ORIGIN           VARCHAR2(100)  - 원본 파일명
UPLOAD           VARCHAR2(100)  - 업로드 파일명(서버 디렉토리에 저장되는 파일명)
*/

//DTO 클래스 >> 전달값을 제공받아 사용하기 위한 Command 객체의 클래스
@Data
public class FileBoard {
	private int num;
	private String writer;
	private String subject;
	private String origin;
	private String upload;
	private MultipartFile file;//전달파일을 저장하기 위한 필드
}


📙 3. XML Mapper


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="xyz.itwill10.mapper.FileBoardMapper">
	<insert id="insertFileBoard">
		<selectKey resultType="int" keyProperty="num" order="BEFORE">
			select fileboard_seq.nextval from dual
		</selectKey>
		insert into values fileboard(#{num},#{writer},#{subject},#{origin},#{upload})		
	</insert>
	
	<delete id="deleteFileBoard">
		delete from fileboard where num=#{num}
	</delete>
	
	<select id="selectFileBoard" resultType="FileBoard">
		select * from fileboard where num=#{num}
	</select>
	
	<select id="selectFileBoardList" resultType="FileBoard">
		select * from fileboard order by num desc
	</select>
</mapper>



📙 4. Interface Mapper


package xyz.itwill10.mapper;

import java.util.List;

import xyz.itwill10.dto.FileBoard;

public interface FileBoardMapper {
	int insertFileBoard(FileBoard fileBoard);
	int deleteFileBoard(int num);
	FileBoard selectFileBoard(int num);
	List<FileBoard> selectFileBoardList();
}


📒 5. DAO Interface


package xyz.itwill10.dao;

import java.util.List;

import xyz.itwill10.dto.FileBoard;

public interface FileBoardDAO {
	int insertFileBoard(FileBoard fileBoard);
	int deleteFileBoard(int num);
	FileBoard selectFileBoard(int num);
	List<FileBoard> selectFileBoardList();
}


📒 6. DAO Class


package xyz.itwill10.dao;

import java.util.List;

import org.apache.ibatis.session.SqlSession;
import org.springframework.stereotype.Repository;

import lombok.RequiredArgsConstructor;
import xyz.itwill10.dto.FileBoard;
import xyz.itwill10.mapper.FileBoardMapper;

@Repository
@RequiredArgsConstructor
public class FileBoardDAOImpl implements FileBoardDAO {
	private final SqlSession sqlSession;
	
	@Override
	public int insertFileBoard(FileBoard fileBoard) {
		return sqlSession.getMapper(FileBoardMapper.class).insertFileBoard(fileBoard);
	}

	@Override
	public int deleteFileBoard(int num) {
		return sqlSession.getMapper(FileBoardMapper.class).deleteFileBoard(num);
	}

	@Override
	public FileBoard selectFileBoard(int num) {
		return sqlSession.getMapper(FileBoardMapper.class).selectFileBoard(num);
	}

	@Override
	public List<FileBoard> selectFileBoardList() {
		return sqlSession.getMapper(FileBoardMapper.class).selectFileBoardList();
	}

}


📗 7. Service interface


package xyz.itwill10.service;

import java.util.List;

import xyz.itwill10.dto.FileBoard;

public interface FileBoardService {
	void addFileBoard(FileBoard fileBoard);
	void removeFileBoard(int num);
	FileBoard getFileBoard(int num);
	List<FileBoard> getFileBoardList();
}


📗 8. Service class


package xyz.itwill10.service;

import java.util.List;

import org.springframework.stereotype.Service;

import lombok.RequiredArgsConstructor;
import xyz.itwill10.dao.FileBoardDAO;
import xyz.itwill10.dto.FileBoard;

@Service
@RequiredArgsConstructor
public class FileBoardServiceImpl implements FileBoardService {
	private final FileBoardDAO fileBoardDAO; 
	
	@Override
	public void addFileBoard(FileBoard fileBoard) {
		fileBoardDAO.insertFileBoard(fileBoard);
	}

	@Override
	public void removeFileBoard(int num) {
		fileBoardDAO.deleteFileBoard(num);
	}

	@Override
	public FileBoard getFileBoard(int num) {
		return fileBoardDAO.selectFileBoard(num);
	}

	@Override
	public List<FileBoard> getFileBoardList() {
		return fileBoardDAO.selectFileBoardList();
	}

}


📌 servlet-context.xml (메소드 호출)

  • BeanNameViewResolver 클래스를 Spring Bean으로 등록
    • BeanNameViewResolver : 요청 처리 메소드에서 반환되는 문자열(ViewName)을 제공받아 같은 이름(beanName)의 객체(Spring Bean)의 실행 메소드를 호출하여 클라이언트에게 응답
    • JSP 문서를 이용하여 응답하지 않고 메소드의 명령을 실행하여 응답 처리
    • 반드시 JSP 문서로 응답되는 ViewResolver 객체보다 우선순위를 높도록 설정

	<!-- BeanNameViewResolver 클래스를 Spring Bean으로 등록 -->
	<beans:bean class="org.springframework.web.servlet.view.BeanNameViewResolver">
		<beans:property name="order" value="1"/>
	</beans:bean>



📌 ViewResolver 객체의 우선순위

  1. BeanNameViewResolver : 요청 처리 메소드에서 반환되는 문자열(ViewName)을 제공받아 같은 이름(beanName)의 객체(Spring Bean)의 실행 메소드를 호출하여 클라이언트에게 응답

  2. UrlBasedViewResolver 객체 : 클라이언트 요청에 의해 호출되는 요청 처리 메소드의 반환값(ViewName)을 제공받아 Spring Framework가 제공하는 ViewResolver 객체가 아닌 외부의 뷰프로그램을 이용하여 응답 처리하는 객체

    • 뷰이름으로 응답하기 위한 뷰를 커스터마이징 할 때 사용하는 객체 (TilesView)
  3. InternalResourceViewResolver 객체 : 클라이언트 요청에 의해 호출되는 요청 처리 메소드의 반환값(ViewName)을 제공받아 응답 가능한 JSP 문서로 변환하여 반환하는 객체


📘 9. Controller class

  • 전달파일이 저장될 서버 디렉토리의 시스템 경로를 반환받아 저장

    • 다운로드 프로그램에서만 파일에 접근 가능하도록 /WEB-INF 폴더에 업로드 폴더 작성 (client 접근 불가)
    • String uploadDir=context.getServletContext().getRealPath("/WEB-INF/upload");
  • 서버 디렉토리에 저장된 업로드 파일명을 생성하여 저장

    • 업로드 파일명은 서버 디렉토리에 존재하는 파일명과 중복되지 않도록 고유값 사용
    • 업로드 파일명은 시스템의 현재 날짜와 시간에 대한 정수값(TimeStamp)를 사용하여 작성
    • String upload=System.currentTimeMillis()+"";


package xyz.itwill10.controller;

@Controller
@RequiredArgsConstructor
public class FileController {
	//WebApplicationContext 객체(Spring Container)를 제공받아 필드에 의존성 주입
	private final WebApplicationContext context;
	private final FileBoardService fileBoardService;
	
	@RequestMapping(value = "/fileboard/write", method = RequestMethod.GET)
	public String fileBoardWrite() {
		return "file/board_write";
	}
	
	//매개변수를 작성하여 모든 전달값과 전달파일을 Command 객체로 제공받아 사용 가능
	@RequestMapping(value = "/fileboard/write", method = RequestMethod.POST)
	public String fileBoardWrite(@ModelAttribute FileBoard fileBoard) throws IllegalStateException, IOException {
		if(fileBoard.getFile().isEmpty()) {
			return "file/board_write";
		}
		
		//전달파일이 저장될 서버 디렉토리의 시스템 경로를 반환받아 저장
		// => 다운로드 프로그램에서만 파일에 접근 가능하도록 /WEB-INF 폴더에 업로드 폴더 작성
		String uploadDir=context.getServletContext().getRealPath("/WEB-INF/upload");
		
		//사용자로부터 입력받아 전달된 원본파일의 이름을 반환받아 저장
		String origin=fileBoard.getFile().getOriginalFilename();
		
		//서버 디렉토리에 저장된 업로드 파일명을 생성하여 저장
		// => 업로드 파일명은 서버 디렉토리에 존재하는 파일명과 중복되지 않도록 고유값 사용
		// => 업로드 파일명은 시스템의 현재 날짜와 시간에 대한 정수값(TimeStamp)를 사용하여 작성
		String upload=System.currentTimeMillis()+"";
		
		//Command 객체(FileBoard 객체)의 필드값 변경
		fileBoard.setOrigin(origin);
		fileBoard.setUpload(upload);
		
		//파일 업로드 처리
		fileBoard.getFile().transferTo(new File(uploadDir, upload));
		
		//FILEBOARD 테이블에 행 삽입
		fileBoardService.addFileBoard(fileBoard);
		
		return "redirect:/fileboard/list";
	}
	
	@RequestMapping("/fileboard/list")
	public String fileBoardList(Model model) {
		model.addAttribute("fileBoardList", fileBoardService.getFileBoardList());
		return "file/board_list";
	}


  • 테이블 행 뿐만 아니라 서버 디렉토리에 저장된 업로드 파일을 삭제 처리
    • URL 주소로 전달된 값을 @PathVariable 어노테이션을 사용하여 매개변수로 제공받아 사용

	//URL 주소로 전달된 값을 @PathVariable 어노테이션을 사용하여 매개변수로 제공받아 사용
	@RequestMapping("/fileboard/delete/{num}")
	public String fileBoardDelete(@PathVariable int num) {
		FileBoard fileBoard=fileBoardService.getFileBoard(num);
		String uploadDir=context.getServletContext().getRealPath("/WEB-INF/upload");
		//서버 디렉토리에 저장된 업로드 파일을 삭제 처리
		new File(uploadDir, fileBoard.getUpload()).delete();
		fileBoardService.removeFileBoard(num);
		return "redirect:/fileboard/list";
	}
  • 다운로드(Download) : 서버 디렉토리에 존재하는 파일을 클라이언트에 전달하여 저장하는 기능

  • 요청 처리 메소드에 의해 반환되는 문자열(ViewName)으로 다운로드 프로그램을 실행하여 서버 디렉토리에 저장된 파일을 클라이언트에게 전달하여 응답 처리
    • BeanNameViewResolver 객체를 사용하여 반환하는 문자열로 특정 프로그램 실행
    • Spring Bean Configuration File(servlet-context.xml)에 BeanNameViewResolver 클래스를 Spring Bean으로 등록
    • 현재 사용중인 ViewResolver 객체는 요청 처리 메소드에서 반환되는 문자열을 이용해 JSP 문서로 응답되도록 처리
      (UrlBasedViewResolver(TilesView), InternalResourceViewResolver)


	@RequestMapping("/fileboard/download/{num}")
	public String fileBoardDownload(@PathVariable int num, Model model) {
		FileBoard fileBoard=fileBoardService.getFileBoard(num);
		
		//Model 객체를 이용하여 실행될 프로그램(Spring Bean)에서 사용하기 위한 객체를 속성값으로 저장하여 제공
		model.addAttribute("uploadDir", context.getServletContext().getRealPath("/WEB-INF/upload"));
		model.addAttribute("uploadFilename",fileBoard.getUpload());
		model.addAttribute("originalFilename",fileBoard.getOrigin());
		
		//실행될 프로그램(Spring Bean)의 식별자(beanName)를 반환
		// => 실행될 프로그램에 대한 클래스를 작성하여 Spring Bean Configuration File
		//(servlet-context.xml)에 Spring Bean으로 등록
		return "fileDownload";
	}
}





🎀 file download class

  • 파일 다운로드 기능을 제공하기 위한 클래스 (BeanNameViewResolver 객체에 의해 실행되는 클래스)
    • Spring Bean Configuration File(servlet-context.xml)에 Spring Bean으로 등록
    • BeanNameViewResolver 객체에 의해 실행되는 클래스는 반드시 AbstractView 클래스를 상속받아 작성
    • renderMergedOutputModel() 메소드를 오버라이드 선언하여 응답에 필요한 명령 작성
  • 클라이언트에게 응답될 파일형식(MimeType)에 대한 변경 (파일 다운로드 기능)
    • AbstractView.setContentType(String mimeType) : 응답 파일 형식을 변경하는 메소드
    • public FileDownload() {setContentType("application/download; utf-8");}

package xyz.itwill10.util;

public class FileDownload extends AbstractView {
	//클라이언트에게 응답될 파일형식(MimeType)에 대한 변경 - 파일 다운로드 기능
	public FileDownload() {
		//AbstractView.setContentType(String mimeType) : 응답 파일 형식을 변경하는 메소드
		setContentType("application/download; utf-8");
	}
	
	//BeanNameViewResolver 객체에 의해 자동 호출되는 메소드
	// => Map 자료형의 매개변수에는 요청 처리 메소드에서 제공된 속성값이 엔트리로 저장된 Map 객체 제공
	@Override
	protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		//요청 처리 메소드에서 제공된 속성값(파일 관련 정보)을 객체로 반환받아 저장
		String uploadDir=(String)model.get("uploadDir");
		String uploadFilename=(String)model.get("uploadFilename");
		String originalFilename=(String)model.get("originalFilename");
		
		//서버 디렉토리에 저장된 다운로드 파일에 대한 File 객체 생성
		File downloadFile=new File(uploadDir, uploadFilename);
		
		//클라이언트에게 파일을 전달하기 위해 리스폰즈 메세지의 머릿부 변경
		response.setContentType(getContentType());
		response.setContentLengthLong((int)downloadFile.length());
		
		//다운로드 처리되어 클라이언트에 저장될 파일명을 리스폰즈 메세지의 머릿부에 저장하여 전달
		// => 파일명에 대한 한글 문제로 인해 부호화 처리하여 전달
		originalFilename=URLEncoder.encode(originalFilename, "utf-8");
		response.setHeader("Content-Disposition","attachement;filename=\""+originalFilename+"\";");
		
		//리스폰즈 메세지 몸체부에 파일을 전달하여 저장하기 위한 출력스트림을 반환받아 저장
		OutputStream out=response.getOutputStream();
		
		//서버 디렉토리에 저장된 다운로드 파일을 읽기 위한 입력스트림을 생성하여 저장
		InputStream in=new FileInputStream(downloadFile);
		
		//FileCopyUtils.copy(InputStream in, OutputStream out) : 입력스트림으로 원시데이타를
		//반복적으로 읽어 출력스트림으로 전달하는 메소드 - 파일 복사 
		FileCopyUtils.copy(in, out);
		
		in.close();
	}

}





🐣 10. view (write)


<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>SPRING</title>
</head>
<body>
	<h1>자료실(입력페이지)</h1>
	<hr>
	<form method="post" enctype="multipart/form-data">
	<table>
		<tr>
			<td>작성자</td>
			<td><input type="text" name="writer"></td>
		</tr>
		<tr>
			<td>제목</td>
			<td><input type="text" name="subject"></td>
		</tr>
		<tr>
			<td>파일</td>
			<td><input type="file" name="file"></td>
		</tr>
		<tr>
			<td colspan="2"><button type="submit">파일전송</button></td>
		</tr>
	</table>
	</form>
</body>
</html>




🐣 10. view (boardlist)


<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>    
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>SPRING</title>
<style type="text/css">
table {
	border: 1px solid black;
	border-collapse: collapse;
}
th, td {
	border: 1px solid black;
	padding: 2px;
}
</style>
</head>
<body>
	<h1>자료실(출력페이지)</h1>
	<hr>
	<table>
		<tr>
			<th width="50">번호</th>
			<th width="100">작성자</th>
			<th width="300">제목</th>
			<th width="350">파일명</th>
			<th width="100">다운로드</th>
			<th width="100">삭제</th>
		</tr>
		
		<c:forEach var="fileBoard" items="${fileBoardList }">
		<tr>
			<td align="center">${fileBoard.num }</td>
			<td align="center">${fileBoard.writer }</td>
			<td>${fileBoard.subject }</td>
			<td>${fileBoard.origin }</td>
			<td align="center">
				<button type="button" onclick="fileDownload(${fileBoard.num });">다운로드</button> 
			</td>
			<td align="center">
				<button type="button" onclick="fileDelete(${fileBoard.num });">삭제</button> 
			</td>
		</tr>
		</c:forEach>
	</table>
	
	<p>
		<button type="button" onclick="location.href='${pageContext.request.contextPath}/fileboard/write';">업로드</button>
	</p> 
	
	<script type="text/javascript">
	function fileDownload(num) {
		//URL 주소를 이용하여 자료실 번호 전달
		location.href="${pageContext.request.contextPath}/fileboard/download/"+num;
	}
	
	function fileDelete(num) {
		if(confirm("자료를 정말로 삭제 하시겠습니까?")) {
			location.href="${pageContext.request.contextPath}/fileboard/delete/"+num;
		} 
	}
	</script>
</body>
</html>





profile
Study Log 📂

0개의 댓글