개발자/Spring

[SPRING] 다중 파일 업로드(중첩 커맨드객체)

푸루닉 2023. 1. 4. 09:23

중첩 커맨드객체란?

커맨드 객체 안에 커맨드 객체가 있는 형식

사용자가 HTTP로 사용자 데이터를 보내올 때 커맨드 객체를 여러 번 중첩시켜서 보낼 수 있다. 이 중첩 커맨드 객체는 VO List 형태로 데이터를 받을 수 있다. HTML 파일에서 데이터를 전송할 때 데이터의 name 속성은 아래처럼 커맨드 객체의 속성명과 인덱스 그리고 속성을 명시해야한다.

 

JSP

헤더 부분
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<c:set var="cpath" value="${pageContext.request.contextPath }" />

------------------------------------
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ include file="header.jsp" %>

<h3>DTO를 이용한 여러 파일 업로드</h3>

<form method="POST" enctype="multipart/form-data">
	<p><input type="text" name="name" placeholder="이름"></p>
	<p><input type="number" name="age" placeholder="나이"></p>
	<p>
		<label><input type="checkbox" name="color" value="red">빨강</label>
		<label><input type="checkbox" name="color" value="green">초록</label>
		<label><input type="checkbox" name="color" value="blue">파랑</label>
	</p>
	<p><input type="file" name="uploadFile" multiple></p>
	<p><input type="submit"></p>
</form>

<table>
	<tr>
		<th>NAME</th>
		<th>AGE</th>
		<th>FILENAME</th>
		<th>이미지태그</th>
	</tr>
	<c:forEach var="dto" items="${list }">
	<tr>
		<td>${dto.name }</td>
		<td>${dto.age }</td>
		<td>${dto.fileName }</td>
		<td>
				<!-- java의 if else -->
				<!-- 문자열 분리 delims의 값(,)을 이용하여 분리 하여 name에 담음 -->
			<c:choose>			
				<c:when test="${fn:contains(dto.fileName, ',') }">
					<c:forTokens var="name" items="${dto.fileName }" delims=",">
						<img src="${cpath }/upload/${name }" height="100">
					</c:forTokens>
				</c:when>
				<c:otherwise>
					<img src="${cpath }/upload/${dto.fileName }" height="150">
				</c:otherwise>
			</c:choose>
		</td>
	</tr>
	</c:forEach>
</table>


</body>
</html>

새로운 개념

1. c:choose

  • java의 switch case와 유사함.
  • when(~~일 경우)
  • otherwise(when이 모두 해당안될 경우 case)

2. function 태그

  • jstl fuctions를 사용하겠다고 최 상단에 선언해야 함.
  • 함수들은 단독으로 사용할 수 없고 EL표현식과 함께 사용해야 함.
  • contains
    • String이 substr을 포함하면 return true

3. c:forTokens

  • 문자열을 분리자를 사용해서 출력한다.
    • 분리자 : delims=" "

컨트롤러

package com.itbank.controller;

import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;

import com.itbank.model.Ex04DTO;
import com.itbank.service.FileService;

@Controller
@RequestMapping("/ex04")
public class EX04Controller {
	
	@Autowired
	private FileService fileService;
	
	@GetMapping
	public ModelAndView ex04() {
		ModelAndView mav = new ModelAndView();
		List<Ex04DTO> list = fileService.getLists();
		mav.addObject("list", list);
		return mav;
	}
	
	@PostMapping
	public ModelAndView ex04(Ex04DTO dto) {
		List<MultipartFile> list = dto.getUploadFile();	// dto에서 업로드 파일 목록을 가져와서
		list.removeIf(file -> file.getSize() == 0);		// 크기가 0인것은 모두 없앤다
		dto.setUploadFile(list);				// 수정된 리스트를 다시 dto에 세팅하고
		System.out.println(dto);				// dto를 출력

		int row = fileService.uploadMultipleFile(dto);
		System.out.println(row);
		
//		1) forEach를 이용하여 신규 리스트에 추가하기
//		ArrayList<String> fileNameList = new ArrayList<String>();
//		list.forEach(f -> fileNameList.add(f.getOriginalFilename()));
//		System.out.println(fileNameList);
		
//		2) stream().map() 을 이용하여 특정 속성만 남기기
//		List<String> fileNameList = list.stream()
//										.map(f -> f.getOriginalFilename())
//										.collect(Collectors.toList());
//		System.out.println(fileNameList);
		
		ModelAndView mav = new ModelAndView("redirect:/ex04");
		return mav;
	}

}

service

	package com.itbank.service;

import java.io.File;
import java.io.IOException;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import com.itbank.model.Ex03DTO;
import com.itbank.model.Ex04DTO;
import com.itbank.repository.UploadDAO;

@Service
public class FileService {
	
	@Autowired private UploadDAO dao;
	
	private final String saveDirectory = "D:\\upload_2023";
	
	public FileService() {
		File dir = new File(saveDirectory);
		if(dir.exists() == false) {
			dir.mkdirs();
		}
	}
    
    
    public List<Ex04DTO> getLists() {
		return dao.selectAlls();
	}
	public int uploadMultipleFile(Ex04DTO dto) {
		int row = 0;
		
		// 문자열을 특정 글자로 구분하여 저장하기
		String fileName = "";
		
		for(MultipartFile f : dto.getUploadFile()) {
			row += upload(f);
			fileName += f.getOriginalFilename();
			fileName += ",";
		}
		fileName = fileName.substring(0, fileName.lastIndexOf(","));
		dto.setFileName(fileName);
		System.out.println(fileName);
		
		row = dao.insertEx04DTO(dto);
		
		
		return row;
	}

DTO

package com.itbank.model;

import java.util.List;

import org.springframework.web.multipart.MultipartFile;

public class Ex04DTO {
	private String name;
	private int age;
	private List<String> color;
	private List<MultipartFile> uploadFile;
	private String fileName;
	
	@Override
	public String toString() {
		String str = String.format("%s, %d살, ", name, age);
//		String colors = "";
//		for(int i = 0; color != null && i < color.length; i++) {
//			colors += color[i];
//			colors += (i != color.length - 1) ? ", " : "\n";
//		}
//		str += colors;
		str += color;
		str += "\nuploadFile : " + uploadFile;
		return str;
	}
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}

	public List<String> getColor() {
		return color;
	}

	public void setColor(List<String> color) {
		this.color = color;
	}

	public List<MultipartFile> getUploadFile() {
		return uploadFile;
	}

	public void setUploadFile(List<MultipartFile> uploadFile) {
		this.uploadFile = uploadFile;
	}

	public String getFileName() {
		return fileName;
	}

	public void setFileName(String fileName) {
		this.fileName = fileName;
	}


}

다중으로 올릴 수 있어야 하므로 자바빈즈는의 자료형이 리스트가 되야 한다.(배열도 가능하나 리스트가 더 편함)