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


반응형

+ Recent posts