Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
Tags
- pl/sql
- anaconda
- spring
- java
- form
- mybatis
- pymssql
- error
- DB 스케쥴러
- Git
- sqlMapConfig
- form태그
- javascript
- androidstudio
- JSP
- directivesTag
- sqldeveloper
- ibatis
- 파이썬
- sql
- sqlMapClient
- Oracle
- eclipse
- 드라이브 연결
- select문
- pagination
- PYTHON
- pyqt
- 비교표현식
- fastapi
Archives
- Today
- Total
기록하는 코더
[Spring] 파일업로드 MultipartFile 본문
스프링에서 파일업로드
1) common-fileupload , common-io 라이브러리
2) MultipartFile (★)
<input type="file"> 일 경우 jsp에서 보낸 파일을 spring에서 MultipartFile로 받음
<input type="file" multiple> 여러개의 파일을 업로드하고 받을 수 있다. (MultipartFile[] 로 받음)
(MultipartFile로 객체의 메소드)
multipartFile.originalFileName() → 실제 파일명 구하기(★★★)
multipartFile.getSize() → 크기
multipartFile.getContentType() → 컨텐츠 타입(MIME)
설정해야하는 것들
1. pom.xml
2. root-context.xml
3. web.xml
4. WAS의 context.xml
* 단축키 Ctrl + Shift + R를 이용해서 찾으면 편하다!
1. pom.xml
```
<!-- 파일업로드 시작 -->
<!-- common-fileupload 라이브러리는 tomcat7.0버전 이후로는
서블릿3.0이상에서 지원함
-->
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
<!-- 파일을 처리하기 위한 의존 라이브러리 -->
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
<!-- 썸네일 -->
<!-- https://mvnrepository.com/artifact/org.imgscalr/imgscalr-lib -->
<dependency>
<groupId>org.imgscalr</groupId>
<artifactId>imgscalr-lib</artifactId>
<version>4.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/net.coobird/thumbnailator -->
<dependency>
<groupId>net.coobird</groupId>
<artifactId>thumbnailator</artifactId>
<version>0.4.8</version>
</dependency>
<!-- 파일업로드 끝 -->
```
2. root-context.xml
```
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 파일업로드 용량 (10MB)-->
<property name="maxUploadSize" value="10485760"/>
<property name="defaultEncoding" value="UTF-8" />
</bean>
<!-- 파일업로드 디렉토리 설정 -->
<bean id="uploadPath" class="java.lang.String">
<constructor-arg value="[프로젝트 내 폴더, 절대경로로 설정]"/>
</bean>
```
전체코드
더보기
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- Root Context: defines shared resources visible to all other web components -->
<!-- root-context.xml : 스프링 설정 파일
스프링 설정? view와 관련되지 않은 객체를 정의
Service(기능), DAO(Repository : 저장소), DB 등 비즈니스 로직과 관련된 설정
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("oracle.jdbc.driver.OracleDriver");
-->
<!-- dataSource : 데이터베이스와 관련된 정보를 설정 -->
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource"
destroy-method="close" >
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:@localhost:1521:xe" />
<property name="username" value="spring" />
<property name="password" value="java" />
</bean>
<!-- 데이터베이스와 연결을 맺고 끊어질 때까지의 라이프 사이클을 관리해주는 sqlSession 객체를 생성
1) dataSource
2) 매퍼 xml의 위치를 지정 : src/main/resources
-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean" >
<property name="dataSource" ref="dataSource" /> <!-- ref를 통해 bean 객체가 주입됨 -->
<property name="mapperLocations" value="classpath:/sqlmap/**/*_SQL.xml" />
<property name="configLocation" value="/WEB-INF/mybatisAlias/mybatisAlias.xml" />
</bean>
<!-- 데이터베이스에 개별적으로 쿼리를 실행시키는 객체
이 객체를 통해 query를 실행함
-->
<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory" />
</bean>
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 파일업로드 용량 (10MB) -->
<property name="maxUploadSize" value="10485760" />
<property name="defaultEncoding" value="UTF-8" />
</bean>
<!-- 파일업로드 디렉토리 설정 -->
<bean id="uploadPath" class="java.lang.String">
<constructor-arg value="C:\\upload" />
</bean>
</beans>
3. web.xml
<load-on-startup>1</load-on-startup>
<!-- web.xml의 설정은 WAS(Tomcat) 자체 설정일 뿐임. -->
<!-- multipart-config : 메모리사이즈, 업로드 파일 저장 위치, 최대 크기 설정 -->
<multipart-config>
<location>c:\\upload</location><!-- 업로드 되는 파일을 저장할 공간 -->
<max-file-size>20971520</max-file-size><!-- 업로드 파일의 최대 크기 1MB * 20 -->
<max-request-size>41943040</max-request-size><!-- 한 번에 올릴 수 있는 최대 크기 40MB -->
<file-size-threshold>20971520</file-size-threshold><!-- 메모리 사용 크기 20MB -->
</multipart-config>
<!-- multipart filter 추가하기 -->
<filter>
<display-name>springMultipartFilter</display-name>
<filter-name>springMultipartFilter</filter-name>
<filter-class>org.springframework.web.multipart.support.MultipartFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>springMultipartFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
전체코드
더보기
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_3_1.xsd">
<!-- 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</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
<!-- web.xml의 설정은 WAS(Tomcat) 자체 설정일 뿐임 -->
<!-- multipart-config : 메모리사이즈 업로드 파일 저장 위치, 최대 크기 설정 -->
<multipart-config>
<location>C:\\upload</location> <!-- 업로드 되는 파일을 저장할 공간 -->
<max-file-size>20971520</max-file-size><!-- 업로드 파일의 최대 크기 1MB * 20 -->
<max-request-size>41943040</max-request-size><!-- 한 번에 올릴 수 있는 최대 크기 40MB -->
<file-size-threshold>20971520</file-size-threshold><!-- 메모리 사용 크기 20MB -->
</multipart-config>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- multipart filter 추가하기-->
<filter>
<display-name>springMultipartFilter</display-name>
<filter-name>springMultipartFilter</filter-name>
<filter-class>org.springframework.web.multipart.support.MultipartFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>springMultipartFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 한글 처리 -->
<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>
4. WAS의 context.xml
추가해야할 요소
<Context allowCasualMultipartParsing="true" >
<!-- 케시문제 해결 -->
<Resources cachingAllowed="true" cacheMaxSize="100000"></Resources>
전체코드
더보기
<?xml version="1.0" encoding="UTF-8"?>
<!-- The contents of this file will be loaded for each web application -->
<!-- 파싱 : 구문분석, 의미분석 -->
<Context allowCasualMultipartParsing="true">
<!-- 캐시 문제 해결 -->
<Resources cachingAllowed="true" cachemaxSize="100000"></Resources>
<!-- Default set of monitored resources. If one of these changes, the -->
<!-- web application will be reloaded. -->
<WatchedResource>WEB-INF/web.xml</WatchedResource>
<WatchedResource>${catalina.base}/conf/web.xml</WatchedResource>
<!-- Uncomment this to disable session persistence across Tomcat restarts -->
<!--
<Manager pathname="" />
-->
</Context>
실행코드
Controller
package kr.or.ddit.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;
import kr.or.ddit.service.LprodService;
import kr.or.ddit.vo.LprodVO;
import lombok.extern.slf4j.Slf4j;
import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.List;
import org.apache.commons.dbcp2.BasicDataSource;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
/* Controller 어노테이션
스프링 프레임워크에게 "이 클래스는 웹 브라우저(클라이언트)의 요청(request)를
받아들이는 컨트롤러야"라고 알려주는 것임
스프링은 servlet-context.xml의 context:component-scan의 설정에 의해 이 클래스를 자바빈 객체로 미리 등록(메모리에 바인딩)
*/
@RequestMapping("/lprod")
@Slf4j
@Controller
public class LprodController {
// 요청URL : /lprod/uploadForm
// 요청방식 : GET
@GetMapping("/uploadForm")
public String uploadForm() {
// forwarding
return "lprod/uploadForm";
}
/*
요청URL : /lprod/uploadFormAction
요청파라미터 : uploadFile이라는 이름의 파일 객체
요청방식 : POST
*/
@PostMapping("/uploadFormAction")
public String uploadFormAction(MultipartFile uploadFile) {
// MultipartFile : 스프링에서 제공해주는 타입 (인터페이스)
/*
String, getOriginalFileName() : 업로드 되는 파일의 실제 파일명
boolean, isEmpty() : 파일이 없다면 true
long, getSize() : 업로드되는 파일의 크기
transferTo(File file) : 파일을 저장
*/
// 파일이 저장되는 경로
String uploadFolder ="C:\\upload";
//make folder 시작 ---------------------------
// c:\\upload\\2023\\01\\27
File uploadPath = new File(uploadFolder,getFolder());
log.info("upload Path : " + uploadPath );
// 만약 연/월/일 해당 폴더가 없다면 생성
if(uploadPath.exists() == false) {
uploadPath.mkdirs();
}
//make folder 끝 ---------------------------
// 파일명
String uploadFileName = uploadFile.getOriginalFilename();
log.info("--------------------------");
log.info("이미지 명 : " + uploadFileName);
log.info("파일 크기 : " + uploadFile.getSize());
// ------------ 파일명 중복 방지 시작 ------------
// java.util.UUID => 랜덤값을 생성
UUID uuid = UUID.randomUUID();
// SDFKOJWEFOIJEWF_.핑구.jsp
uploadFileName = uuid.toString() + "_" + uploadFileName;
// ------------ 파일명 중복 방지 끝 ------------
// (어디에, 무엇을)
// 계획을 세움
File saveFile = new File(uploadPath,uploadFileName);
try {
// 계획 실행. 파일 복사됨(클라이언트의 파일을 서버의 공간으로 복사)
uploadFile.transferTo(saveFile);
AttachVO attachVO = new AttachVO();
// 1) filename : /2023/01/27/32321424b09_nullPointer.jpg
String filename = "/" + getFolder().replace("\\", "/") + "/" + uploadFileName;
attachVO.setFilename(filename);
// 2) filesize
Long l = uploadFile.getSize();
attachVO.setFilesize(l.intValue());
// 3) thumbnail
String thumb = "/" + getFolder().replace("\\", "/") + "/s_" + uploadFileName;
attachVO.setThumbnail(thumb);
log.info("attachVO : " + attachVO);
// 이미지인지 체킹
try {
// MIME 타입을 가져옴. images/jpeg
String contentType = Files.probeContentType(saveFile.toPath());
log.info("contentType : " + contentType);
// MIME 타입 정보가 images로 시작하는지 여(true) 부(false)
if(contentType.startsWith("image")) { // 이미지가 맞다면 true
// c:\\upload\\2023\\01\\27\s_12345467546_nullPointer.jpg
FileOutputStream thumbnail = new FileOutputStream(
new File(uploadPath, "s_"+uploadFileName)
);
// 섬네일 생성
Thumbnailator.createThumbnail(uploadFile.getInputStream(), thumbnail,100,100);
thumbnail.close();
}
int result = this.lprodService.uploadFormAction(attachVO);
log.info("result : " + result);
}catch(IOException e) {
e.printStackTrace();
}
} catch (IllegalStateException | IOException e) {
log.error(e.getMessage());
}
return "redirect:/lprod/uploadForm";
}
/*
요청URL : /lprod/uploadFormMultiAction
요청파라미터 : uploadFile이라는 이름의 파일 객체
요청방식 : POST
*/
@PostMapping("/uploadFormMultiAction")
public String uploadFormMultiAction(MultipartFile[] uploadFile) {
// 파일이 저장되는 경로
String uploadFolder ="C:\\upload";
//make folder 시작 ---------------------------
// c:\\upload\\2023\\01\\27
File uploadPath = new File(uploadFolder,getFolder());
log.info("upload Path : " + uploadPath );
// 만약 연/월/일 해당 폴더가 없다면 생성
if(uploadPath.exists() == false) {
uploadPath.mkdirs();
}
//make folder 끝 ---------------------------
for(MultipartFile multipartfile : uploadFile) {
// 파일명
String uploadFileName = multipartfile.getOriginalFilename();
log.info("----------");
log.info("이미지 명 : " +uploadFileName);
log.info("파일 크기 : " + multipartfile.getSize());
log.info("컨텐츠(MIME) 타입 : " + multipartfile.getContentType());
// ------------ 파일명 중복 방지 시작 ------------
// java.util.UUID => 랜덤값을 생성
UUID uuid = UUID.randomUUID();
// SDFKOJWEFOIJEWF_.핑구.jsp
uploadFileName = uuid.toString() + "_" + uploadFileName;
// ------------ 파일명 중복 방지 끝 ------------
// (어디에, 무엇을)
// 계획을 세움
// c:\\upload\\2023\\01\\27\\DFOLEKFEOK_핑구.jpg
File saveFile = new File(uploadPath,uploadFileName);
try {
// 계획 실행. 파일 복사됨(클라이언트의 파일을 서버의 공간으로 복사)
multipartfile.transferTo(saveFile);
//---------------------------------------------
AttachVO attachVO = new AttachVO();
// 1) filename : /2023/01/27/32321424b09_nullPointer.jpg
String filename = "/" + getFolder().replace("\\", "/") + "/" + uploadFileName;
attachVO.setFilename(filename);
// 2) filesize
Long l = multipartfile.getSize();
attachVO.setFilesize(l.intValue());
// 3) thumbnail
String thumb = "/" + getFolder().replace("\\", "/") + "/s_" + uploadFileName;
attachVO.setThumbnail(thumb);
log.info("attachVO : " + attachVO);
//---------------------------------------------
int result = this.lprodService.uploadFormAction(attachVO);
log.info("result : " + result);
try {
// MIME 타입을 가져옴. images/jpeg
String contentType = Files.probeContentType(saveFile.toPath());
log.info("contentType : " + contentType);
// MIME 타입 정보가 images로 시작하는지 여(true) 부(false)
if(contentType.startsWith("image")) { // 이미지가 맞다면 true
// c:\\upload\\2023\\01\\27\s_12345467546_nullPointer.jpg
FileOutputStream thumbnail = new FileOutputStream(
new File(uploadPath, "s_"+uploadFileName)
);
// 섬네일 생성
Thumbnailator.createThumbnail(multipartfile.getInputStream(), thumbnail,100,100);
thumbnail.close();
}
}catch(IOException e) {
e.printStackTrace();
}
} catch (IllegalStateException | IOException e) {
log.error(e.getMessage());
}
}
// redirect
return "redirect:/lprod/uploadForm";
}
// 연/월/일 폴더 생성
public static String getFolder() {
// 2023-01-27 형식(format) 지정
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
// 날짜 객체 생성(java.util 패키지)
Date date = new Date();
// 2023-01-27 => 2023(File.separator)01(File.separator)27
// 2023-01-27 => 2023\\01\\27
// 윈도우에서 separator가 \\
// 2023-01-27
String str = sdf.format(date);
// 단순 날짜 문자를 File 객체의 폴더 타입으로 바꾸기
// c:\\upload\\2023\\01\\27
return str.replace("-",File.separator);
}
}
jsp
<%@ page language="java" contentType="text/html;charset=UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!-- 파일업로드
1) method는 꼭 post!
2) enctype="multipart/form-data"
3) <input type="file" name="uploadFile" ... name 속성이 꼭 있어야 함
-->
<!--
요청URL : /lprod/uploadFormAction
요청파라미터 : uploadFile이라는 이름의 파일 객체
요청방식 : post
-->
<form action="/lprod/uploadFormAction" method ="post" enctype="multipart/form-data">
<input type="file" name="uploadFile" />
<button type="submit">업로드</button>
</form>
<hr />
<form action="/lprod/uploadFormMultiAction" method ="post" enctype="multipart/form-data">
<input type="file" name="uploadFile" multiple />
<button type="submit">다중업로드</button>
</form>
파일 업로드 미리보기 예제
<script text="text/javascript" src="/resources/js/jquery-3.6.0.js"></script>
<script type="text/javascript">
$(function(){
// 이미지 미리보기 시작~
let sel_file = [];
// 이벤트가 발생된 타겟
// <input type="file" id="input_imgs" name="uploadFile" />
$("#input_imgs").on("change",handleImgFileSelect);
$("#input_imgs2").on("change",handleImgFileSelect);
// 파라미터e : onchange 이벤트 객체
function handleImgFileSelect(e){
// 이벤트가 발생된 타겟 안에 들어있는 이미지 파일들을 가져옴
let files = e.target.files;
// files는 javascript object
//이미지가 여러개 있을 수 있으므로 이미지들을 분리해서 배열로 만듦
let fileArr = Array.prototype.slice.call(files);
// => Array.prototype 배열로 만들어줌
// => slice.call 잘라줌
// 파일 오브젝트의 배열 반복. f : 배열 안에 들어있는 각각의 이미지 파일 객체
fileArr.forEach(function(f){
// 이미지 파일이 아닌 경우 이미지 미리보기 실패 처리(image/jpeg)
if(!f.type.match("image.*")){
alert("이미지 확장자만 가능합니다");
//함수 종료
return;
}
// 이미지 객체(f)를 전역 배열타입 변수(sel_file)에 넣자
sel_file.push(f);
// 이미지 객체를 읽을 자바 스크립트의 reader 객체 생성
let reader = new FileReader();
// e : reader 객체가 이미지 객체를 읽는 이벤트
reader.onload = function(e){
// e.target : 이미지 개체
// e.target.result : reader가 이미지를 다 읽은 결과
let img_html ="<p><img src=\""+e.target.result+"\" /></p>";
// div 사이에 이미지가 렌더링되어 화면에 보임
// 객체.append : 누적
// 객체.html : 새로고침
// --> ajax쪽에서 사용
// innerHTML : J/S
// $('.imgs_wrap').html(img_html);
$('.imgs_wrap').append(img_html);
}
// f : 이미지 파일 객체를 읽은 후 다음 이미지 파일(f)을 위해 초기화 함
reader.readAsDataURL(f);
// 실제로 데이터를 읽어오는 곳
});
}
// 이미지 미리보기 끝~
});
</script>
'JAVA > spring' 카테고리의 다른 글
[Spring] 페이징 처리 (0) | 2023.02.09 |
---|---|
[Spring] form 태그 라이브러리 (0) | 2023.02.06 |
[Spring] 파일 다운로드 (0) | 2023.02.02 |
[Spring] ajax 데이터 처리 (0) | 2023.02.02 |
[Spring] Mybatis - resultMap (0) | 2023.01.31 |