일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 객체지향
- FastAPI
- html
- 생활코딩
- Oracle
- crud
- ddit
- JDBC
- Homebrew
- Java
- 대덕인재개발원
- 이클립스
- 컬렉션프레임워크
- nodejs
- jsp
- servlet
- 배열
- 자바문제
- 단축키
- pyqt
- API
- spring
- Android
- Mac
- 반복문
- ibatis
- 자바
- Error
- python
- 맥
- Today
- Total
romworld
Spring 10 - LPROD를 이용한 파일 업로드, 썸네일 본문
1) Common0-fileupload 라이브러리
2) MultipartFile 를 사용하여
파일 업로드 구현을 해보자!
파일 업로드 환경설정
먼저 mvn repository에 가서 maven 코드 복사
- javax.servlet-api 3.1.0
- commons-fileupload 1.4
- commons-io 2.11.0
- (썸네일) imgscalr-lib 4.2
- (썸네일) thumbnailator 0.4.8
maven 프로젝트에 매핑해주자.
<pom.xml>
<!-- 파일업로드 시작 -->
<!-- commons -fileuplaod 라이브러리는 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>
<!-- 파일업로드 끝 -->
매핑 후 프로젝트 우클릭 - Run as - maven build 해준다.
<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="c:\\upload" />
</bean>
<web.xml>
1. servlet 태그 안에다가
<!-- web.xml의 설정은 tomcat 자체 설정 -->
<multipart-config>
<location>c:\\upload</location><!-- 어디에 업로드? -->
<max-file-size>20971520</max-file-size><!-- 업로드 최대크기 1MB * 20 -->
<max-request-size>4194340</max-request-size><!-- 한번에 업로드 크기 40MB -->
<file-size-threshold>20971520</file-size-threshold><!-- 메모리 20MB -->
</multipart-config>
multipart-config를 추가해준다.
<!-- 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의 설정은 tomcat 자체 설정 -->
<multipart-config>
<location>c:\\upload</location><!-- 어디에 업로드? -->
<max-file-size>20971520</max-file-size><!-- 업로드 최대크기 1MB * 20 -->
<max-request-size>4194340</max-request-size><!-- 한번에 업로드 크기 40MB -->
<file-size-threshold>20971520</file-size-threshold><!-- 메모리 20MB -->
</multipart-config>
</servlet>
2. servlet - mapping 태그 밑에 multipart 필터 추가
<!-- mlultipart 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>
servers의
<context.xml>
<!-- 파싱: 구문분석, 의미분석 -->
<Context allowCasualMultipartParsing="true">
<!-- 캐시문제 해결 -->
<Resources cashingAllowed="true" cacheMaxSize="100000"></Resources>
파일 업로드를 위한 jsp 파일 생성
<LprodController.java>
//요청URL : /lprod/uploadForm
//요청방식 : get
@GetMapping("/uploadForm")
public String uploadForm() {
//forwading
return "lprod/uploadForm";
}
- 우선 컨트롤러에서 jsp로 요청 보낸다
<uploadForm.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>
<!-- 롬아 사랑해 -->
<LprodController.java>
/*
요청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";
log.info("-------------");
log.info("이미지명 : "+ uploadFile.getOriginalFilename());
log.info("파일 크기 : "+ uploadFile.getSize());
// 파라미터가 2개가 필요하다 (어디에, 무엇을)
// 계획을 세움
File saveFile = new File(uploadFolder,uploadFile.getOriginalFilename());
// 계획 실행. 파일이 복사됨(클아이언트의 파일을 서버의 공간으로 복사)
try {
uploadFile.transferTo(saveFile);
} catch (IllegalStateException e) {
log.error(e.getMessage());
} catch (IOException e) {
log.error(e.getMessage());
}
return "redirect:/lprod/uploadForm";
}
재기동 후 실행 시키자!
다중업로드
input 태그에 multiple 속성을 추가해주면 다중 업로드가 가능하다
<uploadForm.jsp>
<hr />
<form action="/lprod/uploadFormMultiAction" method="post"
enctype="multipart/form-data">
<input type="file" name="uploadFile" multiple />
<button type="submit">다중업로드</button>
</form>
- 다중업로드이므로 MultipartFile[] 배열을 사용한다.
<LprodControlelr.java>
@PostMapping("/uploadFormMultiAction")
public String uploadFormMultiAction(MultipartFile[] uploadFile) {
// 파일이 저장되는 경로
String uploadFolder = "c:\\upload";
for(MultipartFile multipartfile : uploadFile) {
log.info("-------------");
log.info("이미지명 : "+ multipartfile.getOriginalFilename());
log.info("파일 크기 : "+ multipartfile.getSize());
log.info("컨텐츠타입 :" + multipartfile.getContentType());
File saveFile = new File(uploadFolder,multipartfile.getOriginalFilename());
try {
multipartfile.transferTo(saveFile);
} catch (IllegalStateException e) {
log.error(e.getMessage());
} catch (IOException e) {
log.error(e.getMessage());
}
}
return "redirect:lprod/uploadForm";
}
- 실행시키면 선택한 파일대로 파일 갯수가 보이고 마우스를 위에 올리면 파일명이 보인다.
이미지 미리보기
원래 작성해놨던 업로드폼을 고쳐서
이미지가 미리 보일 수 있게 고쳐보자.
<uploadForm.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 속성이 꼭 있어야 함!
-->
<script type="text/javascript" src="/resources/js/jquery.3.6.0.js"></script>
<script type="text/javascript">
$(function(){
// - 이미지 미리보기 시작 -
let sel_file = [];
$("#input_imgs").on("change", handleImgFileSelect);
$("#input_imgs2").on("change", handleImgFileSelect);
// 파라미터e : onchange 이벤트 객체
function handleImgFileSelect(e){
// 이벤트가 발생된 타겟 안에 들어있는 이미지 파일들을 가져옴
let files = e.target.files;
// 이미지가 여러개가 있을 수 있으므로 이미지들을 분리해서 배열로 만듦
let fileArr = Array.prototype.slice.call(files);
// 파일 오브젝트의 배열 반복. 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 : 새로고침, innerHTML : J/S
$(".imgs_wrap").append(img_html);
}
// f : 이미지 파일 객체를 읽은 후 다음 이미지 파일(f)를 위해 초기화 함
reader.readAsDataURL(f);
});//end forEach
}
// - 이미지 미리보기 끝 -
});
</script>
<!--
요청URL : /lprod/uploadFormAction
요청파라미터 : uploadFile이라는 이름의 파일객체
요청방식 : post
-->
<div class="imgs_wrap"></div>
<form action="/lprod/uploadFormAction" method="post"
enctype="multipart/form-data">
<input type="file" id="input_imgs" name="uploadFile" />
<button type="submit">업로드</button>
</form>
<hr />
<form action="/lprod/uploadFormMultiAction" method="post"
enctype="multipart/form-data">
<input type="file" id="input_imgs2" name="uploadFile" multiple />
<button type="submit">다중업로드</button>
</form>
파일명 중복 방지
UUID 를 사용하여 파일명 중복 방지를 해보자 ~
// - 파일명 중복 방지 시작 -
//java.util.UUID => 랜덤값을 생성
UUID uuid = UUID.randomUUID();
// ex) ERASDFASDFASD_새롬이.JSP
uploadFileName = uuid.toString() + "_" + uploadFileName;
// - 파일명 중복 방지 끝 -
<LprodController.java> 수정
/*
요청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";
// 파일명
String uploadFileName = uploadFile.getOriginalFilename();
log.info("---------------");
log.info("-------------");
log.info("이미지명 : "+ uploadFileName);
log.info("파일 크기 : "+ uploadFile.getSize());
// - 파일명 중복 방지 시작 -
//java.util.UUID => 랜덤값을 생성
UUID uuid = UUID.randomUUID();
// ex) ERASDFASDFASD_새롬이.JSP
uploadFileName = uuid.toString() + "_" + uploadFileName;
// - 파일명 중복 방지 끝 -
// 계획을 세움
// 파라미터가 2개가 필요하다 (어디에, 무엇을)
File saveFile = new File(uploadFolder,uploadFileName);
// 계획 실행. 파일이 복사됨(클아이언트의 파일을 서버의 공간으로 복사)
try {
uploadFile.transferTo(saveFile);
} catch (IllegalStateException e) {
log.error(e.getMessage());
} catch (IOException e) {
log.error(e.getMessage());
}
return "redirect:/lprod/uploadForm";
}
폴더명을 날짜 형식으로 생성
// 파일이 저장되는 경로
String uploadFolder = "c:\\upload";
// - make folder 시작 -
//2023-01-27 형식(format) 지정
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
// 날짜 객체 생성(java.util 패키지)
Date date = new Date();
//2023-01-27
String str = sdf.format(date);
// 단순 날짜 문자를 File객체의 폴더 타입으로 바꾸기
// c:\\upload\\2023\\01\\27
File uploadPath = new File(uploadFolder, str.replace("-", File.separator));
log.info("upload Path : " + uploadPath);
//만약 연/월/일 해당 폴더가 없다면 생성
if(uploadPath.exists()==false) {
uploadPath.mkdirs();
}
// - make folder 끝 -
<LprodController.java>
/*
요청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 시작 -
//2023-01-27 형식(format) 지정
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
// 날짜 객체 생성(java.util 패키지)
Date date = new Date();
//2023-01-27
String str = sdf.format(date);
// 단순 날짜 문자를 File객체의 폴더 타입으로 바꾸기
// c:\\upload\\2023\\01\\27
File uploadPath = new File(uploadFolder, str.replace("-", File.separator));
log.info("upload Path : " + uploadPath);
//만약 연/월/일 해당 폴더가 없다면 생성
if(uploadPath.exists()==false) {
uploadPath.mkdirs();
}
// - make folder 끝 -
// 파일명
String uploadFileName = uploadFile.getOriginalFilename();
log.info("---------------");
log.info("-------------");
log.info("이미지명 : "+ uploadFileName);
log.info("파일 크기 : "+ uploadFile.getSize());
// - 파일명 중복 방지 시작 -
//java.util.UUID => 랜덤값을 생성
UUID uuid = UUID.randomUUID();
// ex) ERASDFASDFASD_새롬이.JSP
uploadFileName = uuid.toString() + "_" + uploadFileName;
// - 파일명 중복 방지 끝 -
// 계획을 세움
// 파라미터가 2개가 필요하다 (어디에, 무엇을)
File saveFile = new File(uploadPath,uploadFileName);
// 계획 실행. 파일이 복사됨(클아이언트의 파일을 서버의 공간으로 복사)
try {
uploadFile.transferTo(saveFile);
} catch (IllegalStateException e) {
log.error(e.getMessage());
} catch (IOException e) {
log.error(e.getMessage());
}
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\\01\\27
String str = sdf.format(date);
// 단순 날짜 문자를 File객체의 폴더 타입으로 바꾸기
// c:\\upload\\2023\\01\\27
return str.replace("-", File.separator);
}
<LprodControoler.java>
/*
요청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("-------------");
log.info("이미지명 : "+ uploadFileName);
log.info("파일 크기 : "+ uploadFile.getSize());
// - 파일명 중복 방지 시작 -
//java.util.UUID => 랜덤값을 생성
UUID uuid = UUID.randomUUID();
// ex) ERASDFASDFASD_새롬이.JSP
uploadFileName = uuid.toString() + "_" + uploadFileName;
// - 파일명 중복 방지 끝 -
// 계획을 세움
// 파라미터가 2개가 필요하다 (어디에, 무엇을)
File saveFile = new File(uploadPath,uploadFileName);
// 계획 실행. 파일이 복사됨(클아이언트의 파일을 서버의 공간으로 복사)
try {
uploadFile.transferTo(saveFile);
} catch (IllegalStateException e) {
log.error(e.getMessage());
} catch (IOException e) {
log.error(e.getMessage());
}
return "redirect:/lprod/uploadForm";
}
@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("컨텐츠타입 :" + multipartfile.getContentType());
// - 파일명 중복 방지 시작 -
//java.util.UUID => 랜덤값을 생성
UUID uuid = UUID.randomUUID();
// ex) ERASDFASDFASD_새롬이.JSP
uploadFileName = uuid.toString() + "_" + uploadFileName;
// - 파일명 중복 방지 끝 -
//c:\\upload\\2023\\01\27\\ERASDFASDFASD_새롬이.jsp
File saveFile = new File(uploadPath,uploadFileName);
try {
multipartfile.transferTo(saveFile);
} catch (IllegalStateException e) {
log.error(e.getMessage());
} catch (IOException e) {
log.error(e.getMessage());
}
}
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\\01\\27
String str = sdf.format(date);
// 단순 날짜 문자를 File객체의 폴더 타입으로 바꾸기
// c:\\upload\\2023\\01\\27
return str.replace("-", File.separator);
}
썸네일
업로드 메서드 안에
try-catch문에서 작성해보자
<LprodController.java>
try {
uploadFile.transferTo(saveFile);
// 이미지인지 체킹
try {
//MIME 타입을 가져옴. image/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_이지미명.jpg
FileOutputStream thumbnail = new FileOutputStream(
new File(uploadPath,"s_" + uploadFileName)
);
//섬네일 생성
Thumbnailator.createThumbnail(uploadFile.getInputStream(),thumbnail,100,100);
thumbnail.close();
}
}catch(IOException e) {
e.printStackTrace();
}
} catch (IllegalStateException e) {
log.error(e.getMessage());
} catch (IOException e) {
log.error(e.getMessage());
}
다중업로드도 적용시켜보자
<LprodController.java>
/*
요청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("-------------");
log.info("이미지명 : "+ uploadFileName);
log.info("파일 크기 : "+ uploadFile.getSize());
// - 파일명 중복 방지 시작 -
//java.util.UUID => 랜덤값을 생성
UUID uuid = UUID.randomUUID();
// ex) ERASDFASDFASD_새롬이.JSP
uploadFileName = uuid.toString() + "_" + uploadFileName;
// - 파일명 중복 방지 끝 -
// 계획을 세움
// 파라미터가 2개가 필요하다 (어디에, 무엇을)
File saveFile = new File(uploadPath,uploadFileName);
// 계획 실행. 파일이 복사됨(클아이언트의 파일을 서버의 공간으로 복사)
try {
uploadFile.transferTo(saveFile);
// 이미지인지 체킹
try {
//MIME 타입을 가져옴. image/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_이지미명.jpg
FileOutputStream thumbnail = new FileOutputStream(
new File(uploadPath,"s_" + uploadFileName)
);
//섬네일 생성
Thumbnailator.createThumbnail(uploadFile.getInputStream(),thumbnail,100,100);
thumbnail.close();
}
}catch(IOException e) {
e.printStackTrace();
}
} catch (IllegalStateException e) {
log.error(e.getMessage());
} catch (IOException e) {
log.error(e.getMessage());
}
return "redirect:/lprod/uploadForm";
}
@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("컨텐츠타입 :" + multipartfile.getContentType());
// - 파일명 중복 방지 시작 -
//java.util.UUID => 랜덤값을 생성
UUID uuid = UUID.randomUUID();
// ex) ERASDFASDFASD_새롬이.JSP
uploadFileName = uuid.toString() + "_" + uploadFileName;
// - 파일명 중복 방지 끝 -
//c:\\upload\\2023\\01\27\\ERASDFASDFASD_새롬이.jsp
File saveFile = new File(uploadPath,uploadFileName);
try {
multipartfile.transferTo(saveFile);
// 이미지인지 체킹
try {
//MIME 타입을 가져옴. image/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_이지미명.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 e) {
log.error(e.getMessage());
} catch (IOException e) {
log.error(e.getMessage());
}
}
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\\01\\27
String str = sdf.format(date);
// 단순 날짜 문자를 File객체의 폴더 타입으로 바꾸기
// c:\\upload\\2023\\01\\27
return str.replace("-", File.separator);
}
파일 업로드를 위한 ATTACH 테이블 생성
SQL DEVELOPER를 킨다
- 테이블 생성
<AttachVO.java>
@Data
기본 생성자, getter/setter, toString을 자동으로 생성시키는 어노테이션
package kr.or.ddit.vo;
import java.util.Date;
import lombok.Data;
// 기본 생성자, getter/setter, toString를 생성시켜줌
// lombok의 힘을 빌림
// Pojo에 위반..
@Data
public class AttachVO {
private int seq;
private String filename;
private int filesize;
private String thumbnail;
private Date regdate;
}
<INSERT문 SQL구문>
INSERT INTO ATTACH(SEQ, FILENAME, FILESIZE, THUMBNAIL, REGDATE)
VALUES(
(SELECT NVL(MAX(SEQ),0)+1 FROM ATTACH),
'/upload/2023/01/27//e4397843-a33f-4d00-8758-f17044f7efcc_KakaoTalk_20230127_145604043.jpg',
12345,'s_e4397843-a33f-4d00-8758-f17044f7efcc_KakaoTalk_20230127_145604043.jpg',
SYSDATE
);
<lprod_SQL.xml>
<!-- 첨부파일 등록 -->
<insert id="uploadFormAction" parameterType="attachVO">
<selectKey resultType="int" order="BEFORE" keyProperty="seq" >
SELECT NVL(MAX(SEQ),0)+1 FROM ATTACH
</selectKey>
INSERT INTO ATTACH(SEQ, FILENAME, FILESIZE, THUMBNAIL, REGDATE)
VALUES(
#{seq},#{filename},#{filesize},#{thumbnail},SYSDATE
)
</insert>
<mybatisAlias.xml>
<typeAlias type="kr.or.ddit.vo.AttachVO" alias="attachVO" /> 추가
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--
[마이바티스] 스프링에서 "_"를 사용한 컬럼명을 사용 시(BOOK 테이블의 BOOK_ID)
카멜케이스로 읽어줌(bookId)
ex) 테이블 컬럼명이 member_id인 경우 jsp화면단에서 이 값을 사용 시 memberId로 사용
-->
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<!-- 자주 사용하는 타입의 별칭을 세팅 -->
<typeAliases>
<typeAlias type="kr.or.ddit.vo.BookVO" alias="bookVO" />
<typeAlias type="kr.or.ddit.vo.LprodVO" alias="LprodVO" />
<typeAlias type="kr.or.ddit.vo.AttachVO" alias="attachVO" />
</typeAliases>
</configuration>
<LprodDao.java>
//첨부파일 등록
//<insert id="uploadFormAction" parameterType="attachVO">
public int uploadFormAction(AttachVO attachVO) {
return this.sqlSessionTemplate.insert("lprod.uploadFormAction",attachVO);
}
<LprodService.java>
// 첨푸파일 등록
public int uploadFormAction(AttachVO attachVO);
<LprodServiceImpl.java>
//첨부파일 등록
@Override
public int uploadFormAction(AttachVO attachVO) {
return this.lprodDao.uploadFormAction(attachVO);
}
<LprodController.java>
try-catch 부분을 수정해준다 (AttachVO 추가해줬기 때문에)
/*
요청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("-------------");
log.info("이미지명 : "+ uploadFileName);
log.info("파일 크기 : "+ uploadFile.getSize());
// - 파일명 중복 방지 시작 -
//java.util.UUID => 랜덤값을 생성
UUID uuid = UUID.randomUUID();
// ex) ERASDFASDFASD_새롬이.JSP
uploadFileName = uuid.toString() + "_" + uploadFileName;
// - 파일명 중복 방지 끝 -
// 계획을 세움
// 파라미터가 2개가 필요하다 (어디에, 무엇을)
File saveFile = new File(uploadPath,uploadFileName);
// 계획 실행. 파일이 복사됨(클아이언트의 파일을 서버의 공간으로 복사)
try {
uploadFile.transferTo(saveFile);
AttachVO attachVO = new AttachVO();
//1) filename : /2023/01/27/이지미명.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 타입을 가져옴. image/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_이지미명.jpg
FileOutputStream thumbnail = new FileOutputStream(
new File(uploadPath,"s_" + uploadFileName)
);
//섬네일 생성
Thumbnailator.createThumbnail(uploadFile.getInputStream(),thumbnail,100,100);
thumbnail.close();
}
//ATTACH 테이블에 insert
int result = this.lprodService.uploadFormAction(attachVO);
log.info("result : " + result);
}catch(IOException e) {
e.printStackTrace();
}
} catch (IllegalStateException e) {
log.error(e.getMessage());
} catch (IOException e) {
log.error(e.getMessage());
}
return "redirect:/lprod/uploadForm";
}
- 파일을 업로드하면
- 데이터베이스에 잘 insert되는 걸 볼 수 있다.
이제 마지막으로 강아지 이미지를
내 사진으로 바꿔보자 ㅋ
- 여기에서 file inputdml default , div class=""mb-3"를 카피해온다.
- 또한 부트스트랩 적용을 위해 추가해줌
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-GLhlTQ8iRABdZLl6O3oVMWSktQOp6b7In1Zl3/Jr59b6EGGoI1aFkw7cmDA6j6gD" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js" integrity="sha384-w76AqPfDkMBDXo30jS1Sgez6pr3x5MlQ1ZAGC+nuZB+EYdgRZgiwxhTBTkF7CXvN" crossorigin="anonymous"></script>
https://getbootstrap.com/docs/5.3/forms/form-control/
- (create.jsp)클래스 이름과 라벨을 지워준다. ( id, name) 추가
<div class="form-group">
<input class="form-control" type="file" id="uploadFile" name="uploadFile">
</div>
- 스크립트 추가
$(function(){
// - 이미지 미리보기 시작 -
$("#input_imgs").on("change", handleImgFileSelect);
function handleImgFileSelect(e){
let files = e.target.files;
let fileArr = Array.prototype.slice.call(files);
fileArr.forEach(function(f){
if(!f.type.match("image.*")){
alert("이미지만 가능합니다.");
return;
}
let reader = new FileReader();
reader.onload = function(e){
let img_html = "<img src=\"" + e.target.result + "\" />";
$(".bg-register-image").html(img_html);
}
reader.readAsDataURL(f);
});
}
// - 이미지 미리보기 끝 -
<create.jsp>
<%@ page language="java" contentType="text/html;charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-GLhlTQ8iRABdZLl6O3oVMWSktQOp6b7In1Zl3/Jr59b6EGGoI1aFkw7cmDA6j6gD" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js" integrity="sha384-w76AqPfDkMBDXo30jS1Sgez6pr3x5MlQ1ZAGC+nuZB+EYdgRZgiwxhTBTkF7CXvN" crossorigin="anonymous"></script>
<script type="text/javascript" src="/resources/js/jquery-3.6.0.js"></script>
<script>
// document의 요소들이 모두 로딩된 후 실행
$(function(){
// - 이미지 미리보기 시작 -
$("#input_imgs").on("change", handleImgFileSelect);
function handleImgFileSelect(e){
let files = e.target.files;
let fileArr = Array.prototype.slice.call(files);
fileArr.forEach(function(f){
if(!f.type.match("image.*")){
alert("이미지만 가능합니다.");
return;
}
let reader = new FileReader();
reader.onload = function(e){
let img_html = "<img src=\"" + e.target.result + "\" style='width:100%;' />";
$(".bg-register-image").html(img_html);
}
reader.readAsDataURL(f);
});
}
// - 이미지 미리보기 끝 -
$(".btn-icon-split").on("click", function(){
console.log("새롬이");
// 상품분류코드 자동생성
/*
url : 요청경로
contentType : 보내는 데이터의 타입
dataType : 응답 데이터 타입
data : 요청 시 전송할 데이터
type : 요청방식. get,post,put
*/
$.ajax({
url:"/lprod/getLprodGu",
type:"post",
success:function(result){
//console.log("result : " + result);
$("input[name='lprodGu']").val(result);
}
});
});
$("#btnRegist").on("click", function(){
let lprodGu = $("#lprodGu").val();
let lprodNm = $("#lprodNm").val();
if(jQuery.trim(lprodGu)==""){
alert("상품분류코드를 작성해주세요");
$("#lprodGu").focus();
return false;
}
if(jQuery.trim(lprodNm)==""){
$("#lprodNm").focus();
alert("상품분류명을 작성해주세요");
}
// submit을 실행
//$("#frm").submit();도 가능
/*
요청URI : /lprod/createPost
요청파라미터 : {"lprodId:"10","lprodGu:"P404""lprodNm:"간식류"}
요청방식 : post
*/
$("form").submit();
});
});
</script>
<div class="container">
<div class="card o-hidden border-0 shadow-lg my-5">
<div class="card-body p-0">
<!-- Nested Row within Card Body -->
<div class="row">
<div class="col-lg-5 d-none d-lg-block bg-register-image"></div>
<div class="col-lg-7">
<div class="p-5">
<div class="text-center">
<h1 class="h4 text-gray-900 mb-4">상품분류 추가!</h1>
</div>
<form id="frm" class="user" action="/lprod/createPost"
method="post" enctype="multipart/form-data">
<div class="form-group row">
<div class="col-sm-6 mb-3 mb-sm-0">
<!-- 변경 제약
disabled : 값이 전달 안됨
readonly : 파라미터로 값이 전달됨 -->
<input type="text" class="form-control form-control-user"
id="lprodId" name="lprodId"
value="${lprodId}"
placeholder="상품분류 아이디"
readonly>
</div>
<div class="col-sm-6">
<a href="#" class="btn btn-info btn-icon-split">
<span class="icon text-white-50">
<i class="fas fa-info-circle"></i>
</span>
<span class="text">분류코드 자동생성</span>
</a>
</div>
</div>
<div class="form-group">
<input type="email" class="form-control form-control-user"
id="lprodGu" name="lprodGu" placeholder="상품분류 코드"
value="${data.lprodGu}" required />
</div>
<div class="form-group">
<input type="text" class="form-control form-control-user"
id="lprodNm" name="lprodNm" placeholder="상품분류 명"
value="${data.lprodNm}" required />
</div>
<div class="form-group">
<input class="form-control" type="file" id="input_imgs" name="uploadFile">
</div>
<a href="#" id="btnRegist" class="btn btn-primary btn-user btn-block">
등록 </a>
<hr>
<a href="/lprod/list" class="btn btn-google btn-user btn-block">
<i class="fab fa-google fa-fw"></i> 목록보기
</a>
</form>
<hr>
<div class="text-center">
<a class="small" href="forgot-password.html">Forgot Password?</a>
</div>
<div class="text-center">
<a class="small" href="login.html">Already have an account?
Login!</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<lprodVO>
<LprodController.java>
- createPost 메서드를 수정해준다.
/*
요청URI : /lprod/createPost
요청파라미터 : {"lprodId:"10","lprodGu:"P404""lprodNm:"간식류"}
요청방식 : post
*/
@PostMapping("/createPost")
public String createPost(@ModelAttribute LprodVO lprodVO,
Model model) {
log.info("lprodVO :" +lprodVO);
MultipartFile multipartFile = lprodVO.getUploadFile();
log.info("multipartFile : " + multipartFile);
int result = this.lprodService.createPost(lprodVO);
if(result > 0) { //입력 성공
return "redirect:/lprod/detail?lprodGu="+lprodVO.getLprodGu();
}else { // 입력 실패
model.addAttribute("data",lprodVO);
model.addAttribute("lprodId",lprodVO.getLprodId());
return "/lprod/create";
}
}
우선 실행시키면
강아지 위에 덮어씌워진다.
**다만 한글이 깨진다. 한글 처리를 바로 해보자**
'Spring' 카테고리의 다른 글
Spring 12 - Book 테이블도 파일업로드 해보자 (0) | 2023.01.30 |
---|---|
Spring 11 - LPROD, ATTACH 테이블 연결 (일대다 관계 ResultMap 사용) + 한글깨짐 해결하기 (0) | 2023.01.30 |
Spring 09 - LPROD 테이블을 이용한 CRUD (0) | 2023.01.25 |
Spring 08 - 도서 CRUD(7) - 부트스트랩 적용하기, 타일즈(Tiles) (1) | 2023.01.25 |
Spring 07 - 도서 CRUD(6) - 검색 기능 (0) | 2023.01.25 |