스프링 Client 파일 업로드(1)
스프링 목록
- Spring(1) - 백엔드 초기설정
- Spring(2) -스프링 Client 파일 업로드(1)
- Spring(3) -스프링 Client 파일 업로드(2)
- Spring(4) - 백엔드 RESTFULL 로 바꾸기
- Spring(5) - 게시판 페이징 기능 추가하기
- Spring(6) - 검색 기능 추가
- Spring(7) - 프론트 ContextPath 동적 설정
스프링 부트 목록
- Spring Boot(1) - 스프링 부트 초기설정
- Spring Boot(2) - JPA 사용해 보기
- Spring Boot(3) - JPA 방향설정, 관계설정
- Spring Boot(4) - JPA 심화
- Spring Boot(5) - JPA 일대일 실습
Client가 파일을 업로드할때 서버측에서 구현해야할 것들
1. Commons-fileupload 설치
pom.xml파일에 해당내용 추가( <dependencies> 태그안에 )
<!-- 파일업로드 -->
<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
Commons FileUpload(링크)
Commons FileUpload 패키지를 사용하면 강력한 고성능 파일 업로드 기능을 서블릿과 웹 애플리케이션에 쉽게 추가할 수 있습니다.
FileUpload는 HTTP 요청을 RFC 1867, “HTML에서 양식 기반 파일 업로드”에 따라 구문 분석합니다. 즉, POST 메서드를 사용하여 HTTP 요청을 제출하면 “멀티파트/폼 데이터”의 콘텐츠 유형으로 해당 요청을 구문 분석하여 호출자가 쉽게 결과를 사용할 수 있습니다.
2. servlet-context.xml <bean> 추가
src/main/webapp/WEB-INF/spring/appServlet/servlet-context.xml
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="UTF-8"/>
<property name="maxUploadSize" value="104857568"/>
<property name="maxUploadSizePerFile" value="2097152"/>
</bean>
mutipartResolver 빈 추가한 후 인코딩형식, 최대 파일사이즈
-
maxUploadSize : 한 요청당 업로드가 허용되는 최대 용량을 바이트 단위로 설정합니다. -1 은 제한이 없다는 뜻으로 이 프로퍼티를 지정하지 않을때 기본값입니다.
-
maxUploadSizePerFile : 한 파일당 업로드가 허용되는 최대 용량을 바이트 단위로 설정합니다. -1 은 제한이 없다는 뜻으로 이 프로퍼티를 지정하지 않을때 기본값입니다.
-
defaultEncoding : 요청을 파싱할때 사용한 기본 인코딩을 지정합니다. 이 값을 개발 파트의 헤더와 폼 필드에 적용됩니다. 기본값은 서블릿 스펙에 따라 ISO-859-1 입니다. 만약 요청이 문자 인코딩을 지정하면 요청 인코딩이 이 설정을 재정의 합니다. 또한 ServletRequest.setCharacterEncoding 메서드를 호출하는 필터에서의 문자 인코딩을 일반적으로 재정의할 수 있습니다.
multipartResolver 자료 출처: https://offbyone.tistory.com/345 [쉬고 싶은 개발자]
3. 구현해야할 기능
3-1. Front 로부터 받은 letterFiles, imageFile, repBoard 데이터 처리
- reBoard값 DB에 저장
- List <letterFiles> 서버에 저장
- imageFile 서버에 저장
- 요청 url은 POST 방식으로 : “board/write”
3-2. 사용자가 올린 사진을 매번 풀 로드하는건 비효율 적임으로
- 섬네일 생성
- 생성된 섬네일 게시글 클릭시 보여주기
- 올린 파일도 추가로 게시글 클릭시 보여주고, 받을수 있게 설정하기
- Spring(3) -스프링 Client 파일 업로드(2)
3-2 는 아래 링크에서 구현 예정
4. BackEnd Controller 구현
- log는 log4J 설정후 사용
Logger log = Logger.getLogger(this.getClass());
- 아래 변수들 Controller 멤버 변수로 추가하기
//@Controller 멤버변수로 선언 private String saveDirectory = "f:\\files";//자기가 원하는 경로 private int s_width=100; private int s_height=100;
-
항상 글이나 ,자료같은건 Post방식으로 받기 (@PostMapping )
-
받는 파라미터 타입은 MultipartFile 사용(@RequestPard 어노테이션 붙이기!)
- 파일들 저장되는 위치는 String saveDirectory 참고(직접 수정가능)
Controller 의 write 메소드 기본 틀
@PostMapping("board/write")
public ResponseEntity<?> write(@RequestPart(name = "letterFiles") List<MultipartFile> paramLetterFiles,
@RequestPart(name = "imageFile") MultipartFile paramImageFile,
RepBoard repBoard) {
log.info("요청전달데이터 title=" + repBoard.getBoardTitle() + ", content=" + repBoard.getBoardContent());
log.info("letterFiles.size()=" + paramLetterFiles.size());
log.info("imageFile.getSize()=" + paramImageFile.getSize());
// 임시유저
Customer testUser = new Customer();
testUser.setId("id1");
testUser.setName("김치");
// 파일 경로생성
if (!new File(saveDirectory).exists()) {
log.info("업로드 실제경로생성");
new File(saveDirectory).mkdirs();
}
// 1.Add DATABASE
//Code ~~
// 2.Save List<letter> File
//Code ~~
// 3. Save image FiLe
//Code ~~
//아래 예시 코드 보고 주석칸에 코드 채워넣기
//RETURN
//프론트에 HttpStatus.OK전달
return new ResponseEntity(HttpStatus.OK);
}
아래 주석 Code~ 부분은 밑에 코드들로 채워넣기
1) RepBoard DB에 저장하기
// 1. Add DATABASE
try {
repBoard.setBoardC(testUser);
service.add(repBoard);
} catch (AddException e1) {
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
2) List<MultipartFile> letters 받은거 Server에 저장하기
// 2.Save List<letter> File
for (MultipartFile mf : paramLetterFiles) {
log.info("파일크기: " + mf.getSize() + ", 파일이름:" + mf.getOriginalFilename());
String mfFileName = repBoard.getBoardNo() + "_letter_" + UUID.randomUUID() + "_" + mf.getOriginalFilename();
try {
FileCopyUtils.copy(mf.getBytes(), new File(saveDirectory, mfFileName));
} catch (IOException e) {
e.printStackTrace();
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
3) MultipartFile imageFile 받은거 Server에 저장하기
// 3. Save image FiLe
boolean isSavedImageFileComplete = false;
boolean isImageFile = paramImageFile.getContentType().contains("image/");
if (!isImageFile){
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
log.info("파일크기: " + paramImageFile.getSize() + ", 파일이름:" + paramImageFile.getOriginalFilename());
String imageFileName = repBoard.getBoardNo() + "_image_" + UUID.randomUUID() + "_"
+ paramImageFile.getOriginalFilename(); // 저장할 파일이름을 지정한다 ex) 글번호_image_XXXX_원본이름
// ex) 0_image_ddf269da-3202-447a-a2c5-7ce395b63887_문어.png
File createdImagefile = new File(saveDirectory, imageFileName);
try {
FileCopyUtils.copy(paramImageFile.getBytes(), createdImagefile);
isSavedImageFileComplete = true;
log.info("이미지파일 저장:" + createdImagefile.getAbsolutePath() + ", 이미지파일 크기:" + createdImagefile.length());
} catch (IOException e1) {
e1.getStackTrace();
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
5.Front 파일 구현
write.html
<link rel="stylesheet" href="./css/write.css?ver=1" />
<script src="./js/write.js?ver=1"></script>
<div class="write">
<h2>글쓰기</h2>
<form>
<div class="data"><label>글제목</label><input type="text" name="boardTitle"></div>
<div class="data"><label>자소서및이력서첨부</label><input type="file" name="letterFiles" multiple> </div>
<div class="data"><label>이미지첨부</label><input type="file" name="imageFile" accept="image/jpeg, image/jpg, image/png" ></div>
<div class="image">
<img class="preview" style="max-width:100px;"><!-- 이미지 미리보기용 태그 -->
<img class="downloadview"><!-- 글쓰기후 이미지다운로드용 태그 -->
</div>
<div class="data"><label>글내용</label><textarea name="boardContent"></textarea></div>
<input type="button" value="글쓰기">
</form>
</div>
write.css
클릭시 펼처짐
write.js
- ajax 형식 주의해서 참고
$(function () {
//--이미지첨부파일 변경될때 미리보기 시작--
$('section>div.write>form>div.data>input[name=imageFile]').change(function(){
let file = this.files[0];
$("div.image>img.preview").attr('src',URL.createObjectURL(file));
});
//--이미지첨부파일 변경될때 미리보기 끝--
//--글쓰기 버튼 클릭 시작--
let $btObj = $('div.write form input[type=button]');
$btObj.click(function () {
let $writeFormObj = $("section>div.write form");
let formData = new FormData($writeFormObj[0]);
formData.forEach(function (value, key) {
console.log(key + ":" + value);
});
$.ajax({
url: backContextPath + "/board/write",
method: "post",
processData: false, //파일업로드용 설정
contentType: false, //파일업로드용 설정
data: formData, //파일업로드용 설정
cache:false, //이미지 다운로드용 설정
xhrFields:{ //이미지 다운로드용 설정
responseType: 'blob'
},
success: function (responseData) {
let $img = $('div.image>img.downloadview');
let url = URL.createObjectURL(responseData);
$img.attr('src', url);
},
error: function (jqXHR, textStatus) {//응답실패
alert("에러:" + jqXHR.status);
}
});
return false;
});
//--글쓰기 버튼 클릭 끝--
});
6.정상적인 BackEnd 콘솔 화면
INFO : com.my.board.controller.RepBoardController - 요청전달데이터 title=테스트 글제목 입니다, content=테스트 글내용 입니다.
INFO : com.my.board.controller.RepBoardController - letterFiles.size()=1
INFO : com.my.board.controller.RepBoardController - imageFile.getSize()=20202
INFO : com.my.board.controller.RepBoardController - 파일크기: 269, 파일이름:책.txt
INFO : com.my.board.controller.RepBoardController - 파일크기: 20202, 파일이름:문어.png
INFO : com.my.board.controller.RepBoardController - 이미지파일 저장:f:\files\33_image_09e70250-03f8-44ac-b380-7b7c3a78f7e4_문어.png, 이미지파일 크기:20202
히카리 log4J 콘솔내용은 가독성을 위해 글에서 지웠음
스프링 목록
- Spring(1) - 백엔드 초기설정
- Spring(2) -스프링 Client 파일 업로드(1)
- Spring(3) -스프링 Client 파일 업로드(2)
- Spring(4) - 백엔드 RESTFULL 로 바꾸기
- Spring(5) - 게시판 페이징 기능 추가하기
- Spring(6) - 검색 기능 추가
- Spring(7) - 프론트 ContextPath 동적 설정
스프링 부트 목록