728x90
300x250

[JSP] 12. Jsp/Servlet(MVC) Maven 기반의 다중 파일 업로드, 다운로드 구현(1)


조금 실질적으로 도움이 되는 프로젝트라고 주장한다.

다중 파일 업로드, 다운로드 프로젝트를 조금 실용적으로 유용하게 사용할 수 있도록 특화하여 따로 만들어보게 되었다.


사용하는 것은 쉽지만, 구현하는 것은 다소 많은 시간이 소요된다고 본다.

현재 시중에 판매되는 교제 등의 내용이 공개 비판하면 그렇지만, 품질이 매우 낮다는 점이다.


최신 버전에 가까운 프로젝트를 위주로 직접 태스트를 엄선해서 수차례 검증하고, 작성하였다.


* apache-tomcat-9.0.37-windows-x64

* Maven - 3.6.3/1.16.0.20200610-1735   - http://maven.apache.org/download.cgi

  (pom.xml)

   - javax.servlet-api 4.0.1

   - commons-io 2.8.0 (apache project)   -  http://commons.apache.org/

   - commons-fileupload 1.4 (apache project)   - http://commons.apache.org/


적용한 모델은 MVC2 모델을 적용하였으니 참고하면 도움이 되겠다.



1. 결과


다운로드, 업로드 기능에 많은 시간이 소요된 프로젝트였다.



그림 1. 결과 



그림 2. 결과 




그림 3. 결과


그림 4. 결과




그림 5. 결과




2. 프로젝트 구성


작업을 해야하는 양이 조금 된다. 하나 잘 만들어놓으면 활용하거나 개선을 해서 사용해보는 것도 좋은 방법인 거 같다.



그림 6. 프로젝트 구성도



3. 프로젝트 초기 설정


새 프로젝트 만들기를 누른다.



그림 7. 새 프로젝트 만들기


Maven의 Maven Project를 클릭한다.

Next를 누른다.



그림 8. New Maven Project


"org.apache.maven.archetypes   | maven-archetype-webapp"를 선택하고 Next를 누른다.




그림 9. New Maven Project(2)


패키지명과 Artifact Id를 입력하고, Finish를 누른다.



그림 10. New Maven Project(3)


톰캣 서버 설정 등을 완료한다. 그리고 빌드를 시도하면, 이런 화면을 볼 수 있다.



4. 프로젝트 속성 - Java Build Path, Project Facets


14버전으로 변경해준다.



그림 11. Java Build Path -> Libraries 탭의 JRE System Library 버전


버전을 깔맞춤해줘야 한다.

14버전이면, 14로 일관성있게 설정 해준다.



그림 12. Project Facets -> Java 버전확인


마찬가지로 버전을 14로 맞춰준다.


비고: 대략 초기 Maven Project를 생성하면, 1.6? 1.7 버전으로 셋팅되어 있음.



5. Controller 생성하기(Servlet 만들기)


프로젝트에서 오른쪽 버튼을 클릭해서 New->Servlet을 클릭해서 하나 만들어준다.



그림 13. Servlet 만들기


패키지: com.fileWeb.controller

클래스명: FrontController(java)



6. pom.xml 설정하기(MvnRepository.com)


pom.xml 설정으로 필요한 라이브러리를 구비해준다.



<?xml version="1.0" encoding="UTF-8"?>


<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

  <modelVersion>4.0.0</modelVersion>


  <groupId>com.mavenUpload</groupId>

  <artifactId>web</artifactId>

  <version>0.0.1-SNAPSHOT</version>

  <packaging>war</packaging>


  <name>File - Multi Web Upload Project</name>

  <!-- FIXME change it to the project's website -->

  <url>http://www.example.com</url>


  <properties>

    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

    <maven.compiler.source>1.7</maven.compiler.source>

    <maven.compiler.target>1.7</maven.compiler.target>

  </properties>


  <dependencies>

    <dependency>

      <groupId>junit</groupId>

      <artifactId>junit</artifactId>

      <version>4.11</version>

      <scope>test</scope>

    </dependency>

    <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->

<dependency>

    <groupId>javax.servlet</groupId>

    <artifactId>javax.servlet-api</artifactId>

    <version>4.0.1</version>

    <scope>provided</scope>

</dependency>

<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->

<dependency>

    <groupId>commons-io</groupId>

    <artifactId>commons-io</artifactId>

    <version>2.8.0</version>

</dependency>

<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->

<dependency>

    <groupId>commons-fileupload</groupId>

    <artifactId>commons-fileupload</artifactId>

    <version>1.4</version>

</dependency>

  </dependencies>


  <build>

    <finalName>web</finalName>

    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->

      <plugins>

        <plugin>

          <artifactId>maven-clean-plugin</artifactId>

          <version>3.1.0</version>

        </plugin>

        <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->

        <plugin>

          <artifactId>maven-resources-plugin</artifactId>

          <version>3.0.2</version>

        </plugin>

        <plugin>

          <artifactId>maven-compiler-plugin</artifactId>

          <version>3.8.0</version>

        </plugin>

        <plugin>

          <artifactId>maven-surefire-plugin</artifactId>

          <version>2.22.1</version>

        </plugin>

        <plugin>

          <artifactId>maven-war-plugin</artifactId>

          <version>3.2.2</version>

        </plugin>

        <plugin>

          <artifactId>maven-install-plugin</artifactId>

          <version>2.5.2</version>

        </plugin>

        <plugin>

          <artifactId>maven-deploy-plugin</artifactId>

          <version>2.8.2</version>

        </plugin>

      </plugins>

    </pluginManagement>

  </build>

</project>



파일명: pom.xml


[첨부(Attachments)]

pom.zip



7. web.xml 설정하기


web.xml 설정에 관한 것이다.

jsp가 아닌 *.do로 처리하는 프로젝트에 대한 내용으로 작성되었다.

UTF-8 한글 언어셋도 정의하였다.


<?xml version="1.0" encoding="UTF-8"?>


<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 

xmlns="http://java.sun.com/xml/ns/javaee" 

xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" 

id="WebApp_ID" version="3.0">


  <display-name>Archetype Created Web Application</display-name>

  

  <welcome-file-list>


    <welcome-file>index.html</welcome-file>

    <welcome-file>index.htm</welcome-file>

    <welcome-file>index.do</welcome-file>

    <welcome-file>default.html</welcome-file>

    <welcome-file>default.htm</welcome-file>

    <welcome-file>default.do</welcome-file>

  </welcome-file-list>

  

  <servlet>

  <servlet-name>FrontController</servlet-name>

  <servlet-class>com.fileWeb.controller.FrontController</servlet-class>

  <init-param>

<param-name>charset</param-name>

<param-value>UTF-8</param-value>

</init-param>

  </servlet>

  <servlet-mapping>

  <servlet-name>FrontController</servlet-name>

  <url-pattern>*.do</url-pattern>

  </servlet-mapping>

</web-app>



파일명: web.xml


[첨부(Attachments)]

web.zip



8. Controller - HttpUtil.java


패키지명: com.fileWeb.controller

클래스명: HttpUtil (java)



package com.fileWeb.controller;


import java.io.File;

import java.io.FileInputStream;

import java.io.FileNotFoundException;

import java.io.IOException;

import java.io.InputStream;

import java.io.OutputStream;

import java.io.PrintWriter;


import javax.servlet.RequestDispatcher;

import javax.servlet.ServletConfig;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;



public class HttpUtil extends HttpServlet {

private static final long serialVersionUID = 1L;

private static String charset = null;


public static void forward(HttpServletRequest req, HttpServletResponse res,

String path) throws ServletException, IOException {

try {

RequestDispatcher dispatcher = req.getRequestDispatcher(path);

dispatcher.forward(req, res);

}catch(Exception e) {

e.printStackTrace();

}

}

public static void fileUpload(HttpServletRequest req, HttpServletResponse res,

String path) throws ServletException, IOException {


charset = (String) req.getAttribute("charset");

System.out.println(charset);

PrintWriter out = res.getWriter();

// 파일 업로드된 경로

String root = req.getSession().getServletContext().getRealPath("/");

String savePath = root + "upload" + File.separator + "upload";

// 서버에 실제 저장된 파일명

String filename = "1600955663095" ;

System.out.println("파일 실제 폴더경로:" + savePath);

// 실제 내보낼 파일명

String orgfilename = "license한글.txt" ;

req.setCharacterEncoding(charset);

res.setCharacterEncoding(charset);

InputStream in = null;

OutputStream os = null;

File file = null;

boolean skip = false;

String client = "";

try{

    // 파일을 읽어 스트림에 담기

    try{

        file = new File(savePath, filename);

        in = new FileInputStream(file);

    }catch(FileNotFoundException fe){

        skip = true;

    }

    client = req.getHeader("User-Agent");

    // 파일 다운로드 헤더 지정

    res.reset() ;

    res.setContentType("application/octet-stream");

    res.setHeader("Content-Description", "JSP Generated Data");

    if(!skip){

        // IE

        if(client.indexOf("MSIE") != -1){

            res.setHeader ("Content-Disposition", "attachment; filename="+new String(orgfilename.getBytes("KSC5601"),"ISO8859_1"));

        }else{

            // 한글 파일명 처리

            orgfilename = new String(orgfilename.getBytes("KSC5601"),"iso-8859-1");

            res.setHeader("Content-Disposition", "attachment; filename=\"" + orgfilename + "\"");

            res.setHeader("Content-Type", "application/octet-stream; charset=utf-8");

        }  

        res.setHeader ("Content-Length", ""+file.length() );

        os = res.getOutputStream();

        

        byte b[] = new byte[(int)file.length()];

        int leng = 0;

        while( (leng = in.read(b)) > 0 ){

            os.write(b,0,leng);

        }

    }else{

    // 한글 깨짐 - 해결

    res.setContentType("text/html;charset=" + charset);

        out.println("<html><head>");

        out.println("<script language='javascript'>alert('파일을 찾을 수 없습니다.');history.back();</script>");

        out.println("</head><body></body></html>");

    }

    in.close();

    os.close();

}catch(Exception e){

e.printStackTrace();

}

    

}


}



파일명: HttpUtil.java


[첨부(Attachments)]

HttpUtil.zip



9. Controller의 인터페이스 (Controller.java)


Controller.java 파일이다.

인터페이스로 설계되었다.


package com.fileWeb.controller;


import java.io.IOException;


import javax.servlet.ServletException;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;


public interface Controller {

public void execute(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException;

}



파일명: Controller.java


[첨부(Attachments)]

Controller.zip




10. Controller - FrontController와 Command 패턴 적용으로 구성함. 


설명도 중요하지만, 코드로 살펴보도록 하겠다.


package com.fileWeb.controller;


import java.io.IOException;

import java.util.HashMap;

import java.util.Map;


import javax.servlet.ServletConfig;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import javax.servlet.http.HttpSession;


/**

 * Servlet implementation class HomeController

 */

public class FrontController extends HttpServlet {

private static final long serialVersionUID = 1L;

       

private String charset = null;

    public FrontController() {

        super();

    }


protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {

doAction(req, res);

}

protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {

doAction(req, res);

}

// FrontController 패턴 & Command 패턴

protected void doAction(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {


ServletConfig sc = this.getServletConfig();

charset = sc.getInitParameter("charset");

req.setAttribute("charset", charset);

req.setCharacterEncoding(charset);

res.setContentType("text/html; charset=" + charset);

System.out.println(charset);

String uri = req.getRequestURI();

System.out.println("uri : " + uri);

String conPath = req.getContextPath();

System.out.println("conPath : " + conPath);

String command = uri.substring(conPath.length());

System.out.println("command : " + command);

Controller subController = null;

System.out.println("reqMapSize : " + req.getParameterMap().size());


if(command.equals("/board/insert.do")){

System.out.println("insert");

System.out.println("----------------");


    subController = new BoardInsertController();

    subController.execute(req, res);

   

}else if (command.equals("/board/insertResult.do")) {

System.out.println("insertResult");

System.out.println("----------------");


    subController = new BoardInsertResultController();

subController.execute(req, res);

}

else if(command.equals("/board/insertMultiResult.do")){

System.out.println("insertResult");

System.out.println("----------------");


    subController = new BoardInsertMultiResultController();

subController.execute(req, res);

}else if(command.equals("/board/download.do")) {

System.out.println("download");

System.out.println("----------------");

    HttpUtil.fileUpload(req, res, null);

}else if(command.equals("/board/update.do")){

System.out.println("update");

System.out.println("----------------");

}else if(command.equals("/board/select.do")){

System.out.println("select");

System.out.println("----------------");

}else if(command.equals("/board/delete.do")){

System.out.println("delete");

System.out.println("----------------");

}

}

}



파일명: FrontController.java


[첨부(Attachments)]

FrontController.zip



11. Controller - BoardInsertController.java


BoardInsertController의 핵심 내용은 "insert.jsp" 파일을 불러오는 데 있다.

없어도 된다고 생각했는데, 기능이 많아질 경우를 대비한다면, 있는 것이 낫다고 생각했다.


package com.fileWeb.controller;


import java.io.IOException;

import java.util.HashMap;

import java.util.Map;


import javax.servlet.ServletException;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;


public class BoardInsertController implements Controller {


@Override

public void execute(HttpServletRequest req, HttpServletResponse res) throws

ServletException, IOException {

HttpUtil.forward(req, res, "/WEB-INF/view/board/insert.jsp");

}


}



파일명: BoardInsertController.java


[첨부(Attachments)]

BoardInsertController.zip



12. View - board/insert.jsp


삽입 페이지에 대한 것이다.

구현 목표는 두 가지에 대한 실험이다.


하나는 순수한 POST 처리 방식이고, 하나는 POST기반의 multipart/form-data 방식에 관한 것이다.


실험 결과를 먼저 소개하면, 

1. multipart/form-data를 정의해버리면, 기본 정의된 request로는 parameter를 전송받을 수가 없다.


* com.oreilly.servlet   (결과: 오래된 프로젝트 / 서블릿 버전 충돌 발생)

  - http://www.servlets.com/cos/


다양한 검색을 통해서 MultipartRequest 정의를 활용해서 이 문제를 oreilly.Servlet으로 해결할 수 있다는 글을 봐서 적용하였으나 
서블릿 충돌 문제가 발생하였다. (사용할 수 없는 오래된 라이브러리)

2. Apache Common-io, Apache Common-FileUpload를 적용하면, 해결할 수 있다. (2020-09-24일 기준)



<%@ page language="java" contentType="text/html; charset=UTF-8"

    pageEncoding="UTF-8"%>

<!DOCTYPE html>

<html>

<head>

<meta charset="UTF-8">

<title>삽입</title>

</head>

<body>

<h3>삽입</h3>


<!-- 파일 업로드 화면 -->

<!-- 일반적으로 Multipart form으로 전송된 데이터는

      일반 request 메서드로 받아올 수 없습니다.  enctype="multipart/form-data" -->

<form method="post" action="insertResult.do" >

<table style="width:700px;border:1px solid #e2e2e2;">

<tr>

<td style="width:20%">

파일명

</td>

<td>

<input type="text" name="usrID" size="10">

<input type="file" name="uploadFile" multiple>

</td>

</tr>

<tr>

<td colspan="2">

<input type="submit" value="전송">

</td>

</tr>

</table>

</form>



<!-- 멀티파트/데이터 전송 -->

<form method="post" action="insertMultiResult.do" enctype="multipart/form-data" >

<table style="width:700px;border:1px solid #e2e2e2;">

<tr>

<td style="width:20%">

파일명

</td>

<td>

<input type="text" name="usrID" size="10">

<input type="password" name="usrPasswd" size="10">

<input type="file" name="uploadFile" multiple>

<input type="file" name="uploadFile" multiple>

<input type="file" name="uploadFile" multiple>

</td>

</tr>

<tr>

<td colspan="2">

<input type="submit" value="전송">

</td>

</tr>

</table>

</form>


</body>

</html>


파일명: insert.jsp


[첨부(Attachments)]

insert.zip




13. Controller - BoardInsertResultController


multipart/form-data를 미지원하는 타입으로 결과를 출력하는 방법에 대하여 작성하였다.


package com.fileWeb.controller;


import java.io.IOException;

import java.util.HashMap;

import java.util.Map;


import javax.servlet.ServletException;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;


public class BoardInsertResultController implements Controller {


@Override

public void execute(HttpServletRequest req, HttpServletResponse res) throws

ServletException, IOException {


Map<String, Object> reqMap = new HashMap<String, Object>();

reqMap.put("usrID", req.getParameter("usrID"));

reqMap.put("usrPasswd", req.getParameter("filename"));


            req.setAttribute("reqMap", reqMap);

        

HttpUtil.forward(req, res, "/WEB-INF/view/board/insertResult.jsp");

}


}


파일명: BoardInsertResultController.jsp


[첨부(Attachments)]

BoardInsertResultController.zip



2부에서 만나요.


양이 조금 많아서 2부에서 글을 이어서 소개하려고 한다.


- [JSP] 12. Jsp/Servlet(MVC) Maven 기반의 다중 파일 업로드, 다운로드 구현(2), 2020-09-24

   https://yyman.tistory.com/1415


반응형
728x90
300x250

[Spring-Framework] 12. 파일 업로드 구현하기, C태그 사용(if, else, foreach)


Spring-Framework로 파일 업로드 구현하는 방법에 대해서 소개하겠다.


[작업 환경]

* 웹 서버: Apache-tomcat-9.0.37-windows-x64

* IDE: Spring-Tool-Suite 4-4.7.2. Releases.

* Eclipse Marketplace: STS 검색 후 Spring Tools 3 Add-On for Spring Tools 4 3.9.14.Release 설치할 것

* POM 라이브러리: 

  - Apache Commons IO 2.8.0 (2020. 09)

  - Apache Commons FileUpload (2018. 12)

* C태그(JSTL)





1. Eclipse Marketplace 설치하기


help -> eclipse marketplace를 클릭한다.



그림 1. Spring Tools 3 Add-On for Spring Tools 4 3.9.14. Releases 설치하기





2. pom.xml 설정하기


http://mvnrepository.com 사이트에 접속한다.



그림 2. MVN-Repository (검색어: common-io)


검색은 "common-io"를 검색한다.



그림 3. Apache Commons IO - 2.8.0


최신 2.8.0을 클릭하여 pom을 복사한다. (maven)



그림 4. MVN-Repository (검색어: commons-fileupload)


검색은 "commons-fileupload"를 검색한다.





그림 5. Apache Commons FileUpload (1.4)


최신 1.4를 클릭하여 pom을 복사한다. (maven)



그림 6. MVN-Repository (검색어: servlet)


검색은 "Java Servlet API"를 검색한다.



그림 7. Java Servlet API (2018. 4)


최신 4.0.1을 클릭하여 pom을 복사한다. (maven)




그림 8. pom.xml 파일 수정하기


javax.servlet은 버전을 바꿔준다.

commons-io, commons-fileupload는 추가해준다.


(중략)

<!-- Servlet -->

<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->

<dependency>

    <groupId>javax.servlet</groupId>

    <artifactId>javax.servlet-api</artifactId>

    <version>4.0.1</version>

    <scope>provided</scope>

</dependency>

<dependency>

<groupId>javax.servlet.jsp</groupId>

<artifactId>jsp-api</artifactId>

<version>2.1</version>

<scope>provided</scope>

</dependency>

<dependency>

<groupId>javax.servlet</groupId>

<artifactId>jstl</artifactId>

<version>1.2</version>

</dependency>

<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->

<dependency>

    <groupId>commons-io</groupId>

    <artifactId>commons-io</artifactId>

    <version>2.8.0</version>

</dependency>

<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->

<dependency>

    <groupId>commons-fileupload</groupId>

    <artifactId>commons-fileupload</artifactId>

    <version>1.4</version>

</dependency>


(중략)


* 파일명: pom.xml



3. web.xml - Servlet 2.5 스팩 -> 3.1 스팩으로 변경하기


스팩 정보에 관한 것이다.

Spring Legacy Project의 Spring MVC Project를 생성하면, servlet 2.5버전의 web.xml가 생성되는 것을 확인할 수 있다.

Spec 2.5에서 Spec 3.1로 변경해줘야 한다.



그림 9. web.xml (servlet 2.5 -> servlet 3.1 스팩으로 변경 전)



그림 10. web.xml (servlet 2.5 -> servlet 3.1 스팩으로 변경 후)


<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"

version="3.1">


(중략)


* 파일명: web.xml (servlet 3.1 스팩)



4. context-common.xml - 생성하기


context-common.xml을 하나 만들어주겠다. 만드는 이유는 파일 업로드 관련해서 만드는 것이다.


경로: /src/main/webapp/WEB-INF/spring/appServlet/



그림 11. appServlet 폴더에서 마우스 오른쪽 버튼 모습


"appServlet 폴더에서 오른쪽 버튼" -> "New" -> "File"을 클릭한다.



그림 12. context-common.xml 파일 만들기


file명은 context-common.xml이라고 입력한 후 Finish를 누른다.



그림 13. context-common.xml 파일 수정하기


<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns:context="http://www.springframework.org/schema/context" 

xmlns:p="http://www.springframework.org/schema/p" 

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 

xmlns="http://www.springframework.org/schema/beans" 

xmlns:mvc="http://www.springframework.org/schema/mvc" 

xmlns:cache="http://www.springframework.org/schema/cache" 

xmlns:aop="http://www.springframework.org/schema/aop" 

xsi:schemaLocation="http://www.springframework.org/schema/beans 

http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 

http://www.springframework.org/schema/context 

http://www.springframework.org/schema/context/spring-context-3.0.xsd 

http://www.springframework.org/schema/mvc 

http://www.springframework.org/schema/mvc/spring-mvc.xsd 

http://www.springframework.org/schema/cache 

http://www.springframework.org/schema/cache/spring-cache.xsd">

<!-- MultipartResolver 설정 --> 

<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> 

<property name="maxUploadSize" value="100000000" /> 

<property name="maxInMemorySize" value="100000000" /> 

</bean>

</beans>


* 파일명: context-common.xml


[첨부(Attachments)]

context-common.zip


[비고]

파일 크기의 제한을 두기 위한 코드이다.

예: 최대 업로드 파일 크기는 20MB, 메모리에 최대로 저장할 수 있는 파일 크기는 10MB로 제한함.

1MB = 1,024KB

10MB = 10,485,760KB(1,024*1,024*10)

20MB = 20,971,520KB(1,024*1,024*20)



5. web.xml - context-common.xml 파일 인식시켜주기


web.xml을 연다.



그림 14. web.xml 수정 모습


<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"

version="3.1">


<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->

<context-param>

<param-name>contextConfigLocation</param-name>

<param-value>/WEB-INF/spring/root-context.xml</param-value>

</context-param>

<!-- Creates the Spring Container shared by all Servlets and Filters -->

<listener>

<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>

</listener>


<!-- Processes application requests -->

<servlet>

<servlet-name>appServlet</servlet-name>

<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

<init-param>

<param-name>contextConfigLocation</param-name>

<param-value>

/WEB-INF/spring/appServlet/servlet-context.xml

/WEB-INF/spring/appServlet/context-common.xml

</param-value>

</init-param>

<load-on-startup>1</load-on-startup>

</servlet>

<servlet-mapping>

<servlet-name>appServlet</servlet-name>

<url-pattern>/</url-pattern>

</servlet-mapping>



<!-- UTF-8 -->

<filter>

<filter-name>encodingFilter</filter-name>

<filter-class>

org.springframework.web.filter.CharacterEncodingFilter

</filter-class>

<init-param>

<param-name>encoding</param-name>

<param-value>UTF-8</param-value>

</init-param> <init-param>

<param-name>forceEncoding</param-name>

<param-value>true</param-value>

</init-param>

</filter>

<filter-mapping>

<filter-name>encodingFilter</filter-name>

<url-pattern>/*</url-pattern>

</filter-mapping>

</web-app>



파일명: web.xml


[첨부(Attachments)]

web.zip



6. (직접 파일구현에 있어서 연관이 있는지?): 아니다.

MemberVO.java


* 패키지 경로: com.example.postget.vo


package com.example.postget.vo;


public class MemberVO {


private int num;

private String id;

private String passwd;

private String address;

public int getNum() {

return num;

}

public void setNum(int num) {

this.num = num;

}

public String getId() {

return id;

}

public void setId(String id) {

this.id = id;

}

public String getPasswd() {

return passwd;

}

public void setPasswd(String passwd) {

this.passwd = passwd;

}

public String getAddress() {

return address;

}

public void setAddress(String address) {

this.address = address;

}

}



파일명: MemberVO.java


[첨부(Attachments)]

MemberVO.zip




7. Controller와 View 영역


지금 작업부터는 사용자 관점에서 파일 업로드를 구현하면 된다.

어떠한 작업을 할 것인지 개략적인 프로세스로 살펴보겠다.



그림 15. 프로세스 정의 - 파일 업로드


[첨부(Attachments)]

process.zip

process.pptx




8. Controller - BoardController.java 설정하기


POST 방식으로 /board/uploadResult를 호출하면, 파일 업로드 프로세스를 처리해주는 과정이 담긴 코드이다.

물론 루트 경로 등은 따로 별도로 재정의를 해서 사용하면 좋을 듯 싶다.

여력이 되면, 수정해봐도 좋을 듯 하다.


* 패키지 경로: com.example.postget.controller



그림 16, 그림 17. BoardController의 업로드 핵심 내용


POST 방식으로 업로드 처리에 관한 것이다.


(중략)


@RequestMapping(value = "uploadResult", method = RequestMethod.POST)

public String uploadResult(Model model, MemberVO memberVO, MultipartHttpServletRequest request) {

     // 루트 경로

           String rootUploadDir = "C:"+File.separator+"Upload"; // C:/Upload

           File dir = new File(rootUploadDir + File.separator + "testfile"); 

        

           if(!dir.exists()) { //업로드 디렉토리가 존재하지 않으면 생성

                dir.mkdirs();

           }

     Iterator<String> iterator = request.getFileNames(); // 다중 업로드 지원

           ArrayList<String> list = new ArrayList<String>();

        

           int fileLoop = 0;

           String uploadFileName;

           MultipartFile mFile = null;

           String orgFileName = ""; // 진짜 파일명

           String sysFileName = ""; // 변환된 파일명

        

            list.add("루트경로:" + dir + File.separator );

        

            while(iterator.hasNext()) {

       

                 fileLoop++;

            

                 uploadFileName = iterator.next();

                 mFile = request.getFile(uploadFileName);

            

                 orgFileName = mFile.getOriginalFilename();

                 logger.info(orgFileName);

            

                 if(orgFileName != null && orgFileName.length() != 0) { //sysFileName 생성

                

                   SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMDDHHmmss-" + fileLoop);

                   Calendar calendar = Calendar.getInstance();

                   sysFileName = simpleDateFormat.format(calendar.getTime()); //sysFileName: 날짜-fileLoop번호

                

                

                    try {

                        logger.info("try 진입");

                        mFile.transferTo(new File(dir + File.separator + sysFileName)); // C:/Upload/testfile/sysFileName

                        list.add("원본파일명: " + orgFileName + ", 시스템파일명: " + sysFileName);

                        list.add("파일크기: " + mFile.getSize() + ", 파일형식: " + mFile.getContentType() );

                    

                    }catch(Exception e){

                         list.add("오류: 파일 업로드 중 에러발생!!!");

                    }

                

                }//if

            

            }//while

        

            model.addAttribute("list", list);

return "/board/uploadResult";

}


(중략)


파일명: BoardController.java


[첨부(Attachments)]

BoardController.zip




9. View - board/insert.jsp


사용자 화면에 관한 것이다.


그림 18. /board/insert 페이지


미리 살펴보는 /board/insert 페이지에 대한 것이다.

파일 업로드 영역에 관한 핵심은 아래의 그림과 같다.



그림 19. views/board/insert.jsp



<!-- 파일 업로드 영역 -->

<h3>파일 업로드</h3>

<form method="POST" action="uploadResult" enctype="multipart/form-data">

<table style="width:900px; height:70px;">

<tr>

<td style="width:10%">아이디(UserID)</td>

<td style="width:90%">

<input type="text" name="id" class="login_id">

</td>

</tr>

<tr>

<td>

비밀번호(Password)

</td>

<td>

<input type="password" name="passwd" class="login_pwd">

</td>

</tr>

<tr>

<td colspan="2">

<input type="file" name="uploadFile" multiple>

</td>

</tr>

<tr>

<td colspan="2">

<input type="submit" value="로그인">

</td>

</tr>

</table>

</form>


파일명: insert.jsp


[첨부(Attachments)]

insert.zip



10. View - board/uploadResult.jsp


uploadResult 페이지에 대한 것이다.

앞서 Controller에서 정의된 것을 출력하는 페이지를 가리킨다.



그림 20. /board/uploadResult 페이지


소스코드는 다음과 같다.

c태그를 간단하게 if, else문도 적용시켜보았으니 참고해보면, 좋을 듯 싶다.


<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>

<%@ page language="java" contentType="text/html; charset=UTF-8"

    pageEncoding="UTF-8"%>

<!DOCTYPE html>

<html>

<head>

<meta charset="UTF-8">

<title>업로드 - 결과</title>

</head>

<body>


<!-- 업로드 결과 (출력) -->

<c:set var="i" value="1" />

<c:set var="num" value="1" />


<table style="width:700px; border:1px;">

<c:forEach items="${list}" var="list">

<c:choose>

<c:when test="${i == 1}">

<tr>

<td colspan="2" style="background-color:#e2e2e2;">

<c:out value="${num}" />

</td>

</tr>

</c:when>

</c:choose>

<c:choose>

<c:when test="${i <= 3}">

<tr>

<td><c:out value="${i}" /></td>

<td>${list}</td>

<c:set var="i" value="${i + 1}" />

</tr>

</c:when>

<c:otherwise>

<c:set var="i" value="1" />

<c:set var="num" value="${num + 1}" />

</c:otherwise>

</c:choose>

</c:forEach>

</table>

</body>

</html>


* 파일명: uploadResult.jsp


[첨부(Attachments)]

uploadResult.zip



11. 파일 업로드 결과 - 실제 업로드된 모습



그림 21. 파일 업로드 모습 (2020-09-24)



12. 맺음글(Conclusion)


파일 업로드 방법에 대해서 살펴보았다.



* 참고자료(References)


1. Maven Repository: commons-fileupload » commons-fileupload » 1.4, https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload/1.4, Accessed by 2020-09-24, Last Modified 2018-12-24.

2. Maven Repository: commons-io » commons-io » 2.8.0, https://mvnrepository.com/artifact/commons-io/commons-io/2.8.0, Accessed by 2020-09-24, Last Modified 2020-09-09.

3. web.xml 서블릿 버전별 DTD, https://antop.tistory.com/entry/webxml-%EC%84%9C%EB%B8%94%EB%A6%BF-%EB%B2%84%EC%A0%84%EB%B3%84-DTD#footnote_link_145_1, Accessed by 2020-09-24, Last Modified 2013-03-03.


반응형

+ Recent posts