일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- git
- MySQL Error
- mysql
- ajax
- AWS
- html
- mongodb
- AWS RDS
- spread operator
- zombie-hit apartment
- AWS Route53
- ES6
- 예매로직
- Kubernetes
- javascript
- jsp
- 인생이재밌다
- 영화예매
- spring
- post
- ssh
- terminationGracePeriodSeconds
- node.js
- json
- topologySpreadConstraints
- chartjs
- Java
- Get
- sessionStorage
- Bootstrap
- Today
- Total
jongviet
June 30, 2021 - Spring 파일업로드 본문
*6월30일
-파일업로드에 대해 포스팅해보자.
파일업로드
-파일은 수정보다 통째로 올리고 통째로 지우는게 더 깔끔함.
*imports
org.springframework.web.multipart.MultipartFile
org.apache.tika.Tika
net.coobird.thumbnailator.Thumbnails
java.util.UUID.... 등등
*세팅 파일 업데이트
-web.xml
<multipart-config>
<location>C:\\Spring\\workspace\\upload</location>
<!-- 파일관련 추가 -->
<max-file-size>1048576</max-file-size> <!-- 1mb제한, 파일 하나당; byte 기준 -->
<max-request-size>10485760</max-request-size> <!-- 10개 파일 전체 사이즈 -->
<file-size-threshold>1048576</file-size-threshold> <!-- 검증할 사이즈 -->
</multipart-config>
-servlet-context.xml
<!-- mapping은 내가 쓰는 코드상의 주소체계 / location은 실제 위치 값 / 'file://' -->
<resources mapping="/upload/**" location="file:///C:/Spring/workspace/upload/"></resources>
<!-- 멀티파트는 별도 멀티파트 리졸버가 있어야 처리 가능 -->
<beans:bean id="multipartResolver"
class="org.springframework.web.multipart.support.StandardServletMultipartResolver">
</beans:bean>
<context:component-scan base-package="com.myweb.orm"/>
*view단
<form action="/product/register" method="post"
enctype="multipart/form-data"> //폼태그 enctype 변경
<div class="form-group">
<input type="file" class="form-control" id="files" name="files"
multiple style="display: none;">
<!-- 파일 다중 선택 가능 옵션 : multiple -->
<button type="button" class="btn btn-outline-info btn-block"
id="fileTrigger">파일업로드</button>
</div>
<div class="form-group">
<ul class="list-group" id="fileZone"></ul>
</div>
<script>
$(document).on("click", "#fileTrigger", function() {
$("#files").click(); //부트스트랩 버튼 사용
});
let regExp = new RegExp("\.(exe|sh|bat|js|msi|dll)$"); //정규식 객체 생성;
let maxSize = 1048576; // 1MB
function fileValidation(fname, fsize){
if(regExp.test(fname)){ //지정한 파일 형식 필터링
alert(fname + "는 허용되지 않는 파일 형식입니다!");
return false;
}else if(fsize > maxSize){
alert("1MB 이하의 파일만 허용됩니다!");
return false;
}else{
return true;
}
}
$(document).on("change", "#files", function() {
$("button[type=submit]").attr("disabled", false);
let formObj = $("#files");
let fileObjs = formObj[0].files; //업로드한 파일 전체 리스트 담김
let fileZone = $("#fileZone");
fileZone.html("");
for (let fobj of fileObjs) {
let li = '<li class="list-group-item d-flex justify-content-between align-items-center">';
if(fileValidation(fobj.name, fobj.size)){ //업로드 파일 검증 작업
// 정상출력
li += fobj.name + '<span class="badge badge-success badge-pill">';
}else{
// 크기나 타입 통과하지 않을 시
li += '<i class="fa fa-times-rectangle" style="font-size:24px;color:red"></i>';
li += fobj.name + '<span class="badge badge-danger badge-pill">';
$("button[type=submit]").attr("disabled", true);
}
li += (fobj.size/1024/1024).toFixed(2) +'MB</span></li>'; //mb 처리
fileZone.append(li);
}
});
</script>
<!-- File List part!! -->
<c:if test="${pvo.flist.size() > 0 }">
<tr>
<td colspan="2">
<ul class="list-group" id="fileZone">
<c:forEach items="${pvo.flist}" var="fvo">
<li
class="list-group-item d-flex justify-content-between align-items-center">
<c:choose>
<c:when test="${fvo.ftype > 0}">
<img src="/upload/${fvo.savedir }/${fvo.uuid}_th_${fvo.fname}"> //썸네일 저장용; servlet-context.xml에서 잡은 경로 기준 하단부만
</c:when>
<c:otherwise>
<i class="fa fa-file-text-o"
style="font-size: 48px; color: red"></i>
</c:otherwise>
</c:choose> <a href="/upload/${fvo.savedir }/${fvo.uuid}_${fvo.fname}"> // 다운로드용 링크
<span class="badge badge-success badge-pill">${fvo.fname }</span>
</a>
</li>
</c:forEach>
</ul>
</td>
</tr>
</c:if>
*Controller
@RequestParam(name="files", required = false) MultipartFile[] files //상품 등록 시, 배열형 multipart로 파일 접수
if(files[0].getSize() > 0) {
int pno = psv.getCurrPno(); //현재 pno
isUp = fp.upload_file(files, pno); //pno에 맞게 파일 업로드
}
*ORM/FileProcessor
@Inject
private FilesDAORule fdao;
public int upload_file(MultipartFile[] files, int pno) {
final String UP_DIR = "C:\\Spring\\workspace\\upload"; //파일 저장 경로
// 날짜별 폴더 경로 : upload/2021/06/28/uuid_fname.jpg => if 이미지 : uuid_th_fname.jpg
LocalDate date = LocalDate.now();
String today = date.toString(); //2021-06-28
today = today.replace("-", File.separator); //file.sesparator : '\\' -> 2021\\06\\28 //escape + 문자 '\'
File folder = new File(UP_DIR, today); //파일 경로
if(!folder.exists()) folder.mkdirs(); //폴더 없을 시 생성
int isUp = 1;
for (MultipartFile f : files) {
FilesVO fvo = new FilesVO();
fvo.setSavedir(today);
String originalFileName = f.getOriginalFilename();
logger.info(">>>>>>> orginalFileName : " + originalFileName);
fvo.setFname(originalFileName);
UUID uuid = UUID.randomUUID(); //랜덤넘버; 강력함!
fvo.setUuid(uuid.toString());
String fullFileName = uuid.toString() + "_" + originalFileName;
File storeFile = new File(folder, fullFileName); //파일 경로 및 파일명
try {
f.transferTo(storeFile); //파일 이동 및 저장
if(isImageFile(storeFile)) {
fvo.setFtype(1); //이미지는 1, 그외는 0
File thumbnail = new File(folder, uuid.toString() + "_th_" + originalFileName); //썸네일 객체 명칭
Thumbnails.of(storeFile).size(100, 100).toFile(thumbnail); //어떤경로의 어떤 파일을 어떠한 사이즈로 만들지~
}
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
fvo.setPno(pno);
isUp *= fdao.insert(fvo); //하나라도 에러나면 0곱해져서 0 리턴
}
return isUp; //for문 바깥쪽에
}
private boolean isImageFile(File storeFile) {
try {
String mimeType = new Tika().detect(storeFile); //단순 확장자명이 아닌 실제 파일 타입 검증 'lib - tika-parssers 1.25'
return mimeType.startsWith("image") ? true : false;
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
public int deleteFile(String uuid) {
return fdao.delete(uuid);
}
*Service, DAO, DB는 일반적인 CRUD 구조와 같으므로 생략
'Spring legacy' 카테고리의 다른 글
July 1, 2021 - DB : local 파일 정리(quartz-scheduler) (0) | 2021.07.01 |
---|---|
June 30, 2021 - Spring 서칭 (0) | 2021.06.30 |
June 25, 2021 - Spring 개인 필기 (1) | 2021.06.25 |
June 1, 2021 - 수업간 각종 에러들..... (0) | 2021.06.01 |
June 1, 2021 - 웹 보안 관련 기본(get&post 분기처리, session, admin account) (0) | 2021.06.01 |