스프링부트 JPA 게시판 만들기로 계획했을 때부터 꼭 해보고 싶었던 이미지(파일) 업로드 드디어 시작
Multipart란
스프링에서 제공하는 인터페이스로 웹 클라이언트가 요청을 보낼 때 HTTP 프로토콜 바디 부분에 데이터를 여러 부분으로 나눠 보내며 보통 파일 전송할 때 사용
환경 설정
스프링의 경우 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 |
댓글 영역