스프링부트 JPA 게시판 만들기로 계획했을 때부터 꼭 해보고 싶었던 이미지(파일) 업로드 드디어 시작
Multipart란
스프링에서 제공하는 인터페이스로 웹 클라이언트가 요청을 보낼 때 HTTP 프로토콜 바디 부분에 데이터를 여러 부분으로 나눠 보내며 보통 파일 전송할 때 사용
MultipartFile (Spring Framework 5.3.14 API)
Transfer the received file to the given destination file. This may either move the file in the filesystem, copy the file in the filesystem, or save memory-held contents to the destination file. If the destination file already exists, it will be deleted fir
docs.spring.io
환경 설정
스프링의 경우 porm.xml에 의존성을 추가해준다거나 하는데 스프링 부트에서는 기본으로 제공되는건지 딱히 추가한 건 없다.
* content-type이 multipart/form-data인 HTTP 요청 처리는 내가 프로젝트 생성할 때 이미 추가한 spring-boot-starter-web 에 포함되어 있음
📄 build.gradel
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
....
}
📄 application.properties
spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=100MB
file.upload.location=/Users/juran/Desktop/images/
++ 파일이 저장되는 경로 환경변수 설정은 추후에 추가할 예정
간단한 파일 업로드 예제
1. 먼저 엔티티와 DTO 생성
📦 ImageTest
@Entity
@Getter
@Setter
@NoArgsConstructor
public class ImageTest {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long imageNo;
@Column(length = 500, nullable = false)
private String originImageName;
@Column(length = 500, nullable = false)
private String imageName;
@Column(length = 1000, nullable = false)
private String imagePath;
@Builder
public ImageTest(String originImageName, String imageName, String imagePath) {
this.originImageName = originImageName;
this.imageName = imageName;
this.imagePath = imagePath;
}
}
📦 ImageDto
이미지 객체를 이용하기 위한 DTO
@Getter
@Setter
@NoArgsConstructor
public class ImageDto {
private String originImageName;
private String imageName;
private String imagePath;
public ImageTest toEntity() {
ImageTest build = ImageTest.builder()
.originImageName(originImageName)
.imageName(imageName)
.imagePath(imagePath)
.build();
return build;
}
@Builder
public ImageDto (String originImageName, String imageName,String imagePath) {
this.originImageName = originImageName;
this.imageName = imageName;
this.imagePath = imagePath;
}
}
2. 레퍼지토리 작성
📄 ImageRepository
public interface ImageRepository extends JpaRepository<ImageTest, Long> {
}
3. 서비스 작성
📄 TestService
@Service
@RequiredArgsConstructor
public class TestService {
private final ImageRepository imageRepository;
@Transactional
public Long saveImage(ImageDto imageDto) {
return imageRepository.save(imageDto.toEntity()).getImageNo();
}
}
이미지 DTO를 엔티티로 변환하여 DB에 저장 후 이미지No 반환
4. 컨트롤러 작성
📄 TestApiController
@PostMapping("/image/V1/api")
public String imageUploadV1(@RequestParam(name = "image") MultipartFile image) throws IOException {
// 폴더 생성과 파일명 새로 부여를 위한 현재 시간 알아내기
LocalDateTime now = LocalDateTime.now();
int year = now.getYear();
int month = now.getMonthValue();
int day = now.getDayOfMonth();
int hour = now.getHour();
int minute = now.getMinute();
int second = now.getSecond();
int millis = now.get(ChronoField.MILLI_OF_SECOND);
String absolutePath = new File("/Users/juran/Desktop").getAbsolutePath() + "/"; // 파일이 저장될 절대 경로
String newFileName = "image" + hour + minute + second + millis; // 새로 부여한 이미지명
String fileExtension = '.' + image.getOriginalFilename().replaceAll("^.*\\.(.*)$", "$1"); // 정규식 이용하여 확장자만 추출
String path = "images/test/" + year + "/" + month + "/" + day; // 저장될 폴더 경로
try {
if(!image.isEmpty()) {
File file = new File(absolutePath + path);
if(!file.exists()){
file.mkdirs(); // mkdir()과 다르게 상위 폴더가 없을 때 상위폴더까지 생성
}
file = new File(absolutePath + path + "/" + newFileName + fileExtension);
imageV1.transferTo(file);
ImageDto imgDto = ImageDto.builder()
.originImageName(image.getOriginalFilename())
.imagePath(path)
.imageName(newFileName + fileExtension)
.build();
testService.saveImage(imgDto);
}
} catch (Exception e) {
e.printStackTrace();
}
return "test/imageV1";
}
* try/catch 구문으로 예외 처리하려 하였으나 이미지가 없는 경우나 여러 이미지가 들어왔을 때 등등 다양한 예외처리가 필요해 보임
5. 클라이언트 작성
📄 imageUpload.jsp
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Form 태그를 이용한 파일 전송</title>
</head>
<body>
<form name="form" method="post" action="/test/image/V1/api" enctype="multipart/form-data">
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
<input type="file" name="image" multiple="multiple"/>
<input type="submit" id="submit" value="전송"/>
</form>
</body>
</html>
* 현재 스프링 시큐리티가 적용된 상태라 csrf 토큰을 hidden값으로 넘겨줌
실행 결과
파일 선택한 모습
전송 결과 실행된 쿼리
insert
into
image_test
(image_name, image_path, origin_image_name)
values
(?, ?, ?)
지정한 경로에 이미지가 저장된 모습
데이터베이스에 저장된 모습
[SPRING BOOT] 2521 과몰입러의 스프링부트 웹소켓 채팅 서비스 만들기(1) 자바소스 (0) | 2022.03.14 |
---|---|
[SPRING] MultipartFile 게시판 이미지 업로드(2)ajax 이용과 게시판에 적용 (0) | 2022.01.10 |
[SPRING] Model, ModelMap, ModelAndView 차이점 (0) | 2021.11.14 |
[ERROR] @Builder와 @NoArgsConstructor 동시에 사용할 때 (0) | 2021.08.24 |
[ERROR] 스프링부트 UnsatisfiedDependencyException (0) | 2021.08.24 |
댓글 영역