이클립스 재단으로 이관된 JavaEE는 JakartaEE로 이름이 변경되었다.
Tomcat 10 이후버전으로 구현시 이전과 차이점이 있어
이에 라이브러리 버전과 사용법을 정리 하고자 한다.
- 프로젝트 환경
- 라이브러리
- DB Table
- 구조
- 업로드
- 단건
- 다건
- 다운로드
프로젝트 환경
항목 | 버전 |
JDK | Java 17 |
WAS | Tomcat 10 |
DB | MySQL 8.0.32 |
Servlet | 5.0 |
라이브러리
<dependencies>
...
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>5.0.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.2.0</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
...
</dependencies>
Jakarta Servlet API | • Java 웹 애플리케이션을 개발할 때 필요한 서블릿과 관련된 클래스 및 인터페이스를 정의한 API • HTTP 요청 처리 및 응답 생성 |
MySQL Connector/J | • MySQL DB와의 연결을 위한 JDBC 드라이버 • Java 애플리케이션에서 MySQL DB 접속 및 SQL 쿼리 실행 |
Apache Commons IO | • Java의 I/O 작업을 쉽게 처리할 수 있는 유틸리티 라이브러리 • 파일 처리 관련 작업 수행 시 사용 |
DB Table
테이블 이름: File
Field | Type | Null | Key | Default | Extra |
id | int unsigned | NO | PRI | auto_increment | |
original_name | varchar(100) | NO | |||
saved_name | varchar(255) | YES | |||
saved_path | varchar(255) | NO | |||
ext | varchar(10) | NO | |||
size | bigint | NO | 0 |
구조

업로드 동작 순서
- 파일을 업로드 디렉토리 경로 가져오기
- 파일 업로드 후 FileVO 반환
- FileVO에 담긴 파일 정보 DB에 저장
다운로드 동작 순서
- 요청된 파일 번호로 파일 조회
- 다운로드
업로드, 다운로드에서 공용으로 사용할 클래스를 먼저 소개한다.
config.properties
업로드를 통해 파일을 저장할 경로
본인이 원하는 경로를 작성해도 된다
리눅스도 가능하다
saved.directory=C:/project/kb/jsp/upload
DBUtil
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
/**
* 데이터베이스 연결과 관련된 유틸리티 메소드를 제공하는 클래스
*/
public class DBUtil {
static final String DRIVER = "com.mysql.cj.jdbc.Driver";
static final String DB_URL = "jdbc:mysql://localhost:3306/테이블이름";
static final String USER = "root";
static final String PASS = "비밀번호";
// JDBC 드라이버 로드
static {
try {
Class.forName(DRIVER);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
* 데이터베이스 연결을 생성하고 반환
*
* @return 데이터베이스와의 연결
* @throws SQLException 데이터베이스 연결 생성 중 오류 발생 시
*/
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(DB_URL, USER, PASS);
}
/**
* 주어진 자원들을 안전하게 종료
* 주로 데이터베이스 연결, statement, resultset 등을 닫는 데 사용
*
* @param resources 닫을 자원들
*/
public static void release(AutoCloseable... resources) {
for (AutoCloseable resource : resources) {
if (resource != null) {
try {
resource.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
FileUtil
import com.cg.simplejsp._8_file.vo.FileVO;
import jakarta.servlet.MultipartConfigElement;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.Part;
import org.apache.commons.io.FilenameUtils;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.util.*;
public class FileUtil {
// 설정파일에서 업로드 위치 가져오기
public static String getSavedFileDirectoryPath() {
Properties p = new Properties();
try (InputStream input = FileUtil.class
.getClassLoader().getResourceAsStream("config.properties")) {
p.load(input);
return p.getProperty("saved.directory");
} catch (IOException e) {
e.printStackTrace();
return null; // 또는 기본값 반환
}
}
// 업로드할 디렉토리 반환
public static File getUploadDirectory() {
String dirPath = getSavedFileDirectoryPath();
// 파일을 upload 할 directory 생성
File uploadDir = new File(dirPath);
if (!uploadDir.exists()) {
uploadDir.mkdirs();
}
return uploadDir;
}
// request 에서 넘어온 파일 정보로 파일 저장 후 FileVO 반환(단건)
public static FileVO handleUploadFile(HttpServletRequest request, File uploadDir) throws ServletException, IOException {
// form 에서 파일 가져오기, 파일 처리
Part filePart = request.getPart("upload_file"); // form 태그 안에 있던 name 속성
if (filePart.getSize() > 0) {
return saveFileAndGetVo(filePart, uploadDir);
}
return null;
}
// request 에서 넘어온 파일 정보로 파일 저장 후 List<FileVO> 반환(다건)
public static List<FileVO> handleUploadFiles(HttpServletRequest request, File uploadDir) throws ServletException, IOException {
// form 에서 파일 가져오기, 파일 처리
Collection<Part> parts = request.getParts();
List<FileVO> files = new ArrayList<>();
for (Part part : parts) {
if (part.getName().equals("upload_file") && part.getSize() > 0)// 파일인 경우
files.add(saveFileAndGetVo(part, uploadDir));
}
return files;
}
//파일 저장
private static FileVO saveFileAndGetVo(Part part, File uploadDir) throws IOException {
String originalName = part.getSubmittedFileName();// 파일 원본 이름
String extension = FilenameUtils.getExtension(originalName); // 확장자
String fileName = originalName.substring(0, originalName.indexOf("."));// 확장자 제외 파일 이름
String savedName = UUID.randomUUID() + "_" + fileName; // 중복 방지
File file = new File(uploadDir, savedName + "." + extension); // File(File parent, File child), uploadDir + saveName(확장자 포함) 가진 파일(사실상 String 임)
// 파일 저장
try (InputStream input = part.getInputStream(); // 파일 데이터
OutputStream output = Files.newOutputStream(file.toPath()) // 저장 위치
) {
input.transferTo(output); // output 경로에 input 에 담긴 데이터를 내보냄
}
return new FileVO(fileName, savedName, file.getParent(), extension, part.getSize());
}
}
FileVO
public class FileVO {
private long fileId; // 식별자
private String originalName; // 파일 원본 이름
private String savedName; // 서버에 저장되는 파일 이름
private String savedPath; // 서버에 파일이 저장되는 경로
private String ext; // 확장자
private long size; // 파일 크기
// 파일 조회용
public FileVO(long fileId, String originalName, String savedName, String savedPath, String ext) {
this.fileId = fileId;
this.originalName = originalName;
this.savedName = savedName;
this.savedPath = savedPath;
this.ext = ext;
}
// 파일 저장용
public FileVO(String originalName, String savedName, String savedPath, String ext, long size) {
this(0, originalName, savedName, savedPath, ext);
this.size = size;
}
// getter and setter
}
업로드
단건
upload.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<center>
<h2> 파일 업로드 </h2>
<form action="/upload.do" method="post" enctype="multipart/form-data">
<input type="file" name="upload_file" />
<input type="submit" value="저장" />
</form>
</center>
</body>
</html>
FileUpload
import com.cg.simplejsp._8_file.dao.FileDAO;
import com.cg.simplejsp._8_file.util.FileUtil;
import com.cg.simplejsp._8_file.vo.FileVO;
import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.MultipartConfig;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
/**
* 파일 업로드 HTTP 요청을 처리하는 서블릿
*/
@MultipartConfig(
fileSizeThreshold = 1024 * 1024, // 파일이 메모리에 저장되기 시작하는 임계치, 임계치보다 클 경우 디스크에 저장
maxFileSize = 1024 * 1024 * 5, // 각 업로드 파일의 최대 허용 크기
maxRequestSize = 1024 * 1024 * 10 // 전체 요청의 최대 크기
)
@WebServlet("/upload.do")
public class FileUploadController extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
RequestDispatcher dispatcher = request.getRequestDispatcher("file/upload.jsp");
dispatcher.forward(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
processRequest(request, response);
}
private void processRequest(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
// 파일을 업로드할 디렉토리 경로 가져오기
File uploadDirectory = FileUtil.getUploadDirectory();
// 파일 업로드 후 파일 정보 반환
FileVO file = FileUtil.handleUploadFile(request, uploadDirectory);
// 파일 정보를 DB에 저장
if (file != null) {
FileDAO dao = new FileDAO();
dao.insert(file);
}
response.sendRedirect("/upload.do");
}
}
다건
단건처리 부분의 일부분을 변경하면 된다.
uploads.jsp(위 파일과 이름이 다름)
...
<form action="/uploads.do" method="post" enctype="multipart/form-data">
<% for (int i = 0; i < 3; i++) {%>
<input type="file" name="upload_file"/>
<%}%>
<input type="submit" value="저장"/>
</form>
...
FileUploadsController(위 파일과 이름이 다름)
...
private void processRequest(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
// 파일을 업로드할 디렉토리 경로 가져오기
File uploadDirectory = FileUtil.getUploadDirectory();
// 파일 업로드 후 파일 정보 반환
List<FileVO> files = FileUtil.handleUploadFiles(request, uploadDirectory);
// 파일 정보를 DB에 저장
if (!files.isEmpty()) {
FileDAO dao = new FileDAO();
dao.insert(files);
}
response.sendRedirect("/uploads.do");
}
...
다운로드
download.jsp
편의상 1번 (File 테이블 id 필드의 값) 파일을 다운로드 한다고 가정해보자
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Download a file</title>
</head>
<body>
<form action="/download.do" method="post">
<input type="hidden" name="seq" value="1">
<input type="submit" value="파일 다운로드">
</form>
</body>
</html>
FileDownloadController
import com.cg.simplejsp._8_file.dao.FileDAO;
import com.cg.simplejsp._8_file.vo.FileVO;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import jakarta.servlet.annotation.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
@WebServlet("/download.do")
public class FileDownloadController extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
RequestDispatcher rd = request.getRequestDispatcher("file/download.jsp");
rd.forward(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
processRequest(request, response);
}
private void processRequest(HttpServletRequest request, HttpServletResponse response) throws IOException {
// 파일 번호 받기
long id = Long.parseLong(request.getParameter("seq"));
// 파일 조회
FileDAO dao = new FileDAO();
FileVO vo = dao.findById(id);
// 다운로드
download(response, getFile(request, response, vo));
}
private static void download(HttpServletResponse response, File downloadFile) {
try (FileInputStream fileInputStream = new FileInputStream(downloadFile);
OutputStream outputStream = response.getOutputStream()
) {
// 파일을 읽어서 버퍼에 저장하고, 버퍼의 내용을 출력 스트림으로 전송
fileInputStream.transferTo(outputStream);
} catch (Exception e) {
e.printStackTrace();
}
}
private static File getFile(HttpServletRequest request, HttpServletResponse response, FileVO vo) {
// 경로와 파일 이름
String filePath = vo.getSavedPath();
String fileName = vo.getSavedName();
String fileOriginalName = vo.getOriginalName();
// MIME 타입 가져오기
String contentType = request.getServletContext().getMimeType(fileName);
// MIME 타입이 없을 경우 기본값으로 설정
if (contentType == null) {
contentType = "application/octet-stream";
}
/*
StandardCharsets.ISO_8859_1
라틴 알파벳과 일부 특수 문자를 포함한 문자 집합
파일 이름이 한글을 포함할 경우에 발생하는 인코딩 문제(한글 깨짐)를 해결하기 위해 설정
*/
// 파일 이름을 UTF-8 형식으로 인코딩
String encodingFileName = new String(fileOriginalName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);
// HTTP 응답의 컨텐츠 타입과 헤더 설정
response.setContentType(contentType);
response.setHeader(
"Content-Disposition",
"attachment; filename=\"" + encodingFileName + "." + vo.getExt() + "\""
);
// 다운로드할 파일의 전체 경로 생성
String fullPath = filePath + File.separator + fileName + "." + vo.getExt();
return new File(fullPath);
}
}
- https://velog.io/@yu-jin-song/Servlet-JSP-Servlet-5.0-jakarta-%ED%8C%8C%EC%9D%BC-%EC%B2%98%EB%A6%AC-1-%EC%97%85%EB%A1%9C%EB%93%9C
- https://velog.io/@yu-jin-song/Servlet-JSP-Servlet-5.0-jakarta-%ED%8C%8C%EC%9D%BC-%EC%B2%98%EB%A6%AC-2-%EB%8B%A4%EC%9A%B4%EB%A1%9C%EB%93%9C
- https://rebugs.tistory.com/536
728x90
'JSP' 카테고리의 다른 글
[JSP]jakarta JSTL 설정 (0) | 2024.06.02 |
---|---|
IntelliJ JSP 시작 설정 (0) | 2024.05.22 |
tomcat 설치, 실행 (0) | 2024.05.21 |
이클립스 web.xml 생성 (0) | 2023.06.18 |