File 받기/보내기 기본적 구현 (REST API)
DB에 파일을 저장(업로드)하는 방식 JPA 어노테이션으로 @Lob
을 사용한다.
Entity : ImageData
@Entity
@Table(name = "ImageData")
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class ImageData {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String type;
@Lob
@Column(name = "imagedata", length = 1000)
private byte[] imageData;
@Builder
public ImageData(String name, String type, byte[] imageData) {
this.name = name;
this.type = type;
this.imageData = imageData;
}
}
Controller
@RestController
@RequiredArgsConstructor
@RequestMapping("/image")
public class StorageController {
final private StorageService storageService;
// 업로드
@PostMapping
public ResponseEntity<?> uploadImage(@RequestParam("image") MultipartFile file) throws IOException {
String uploadImage = storageService.uploadImage(file);
return ResponseEntity.status(HttpStatus.OK)
.body(uploadImage);
}
// 다운로드
@GetMapping("/{fileName}")
public ResponseEntity<?> downloadImage(@PathVariable("fileName") String fileName) {
byte[] downloadImage = storageService.downloadImage(fileName);
return ResponseEntity.status(HttpStatus.OK)
.contentType(MediaType.valueOf("image/png"))
.body(downloadImage);
}
}
Service
@Slf4j
@Service
@RequiredArgsConstructor
public class StorageService {
private final StorageRepository storageRepository;
public String uploadImage(MultipartFile file) throws IOException {
log.info("upload file: {}", file);
ImageData imageData = storageRepository.save(
ImageData.builder()
.name(file.getOriginalFilename())
.type(file.getContentType())
.imageData(ImageUtils.compressImage(file.getBytes()))
.build());
if (imageData != null) {
log.info("imageData: {}", imageData);
return "file uploaded successfully : " + file.getOriginalFilename();
}
return null;
}
// 이미지 파일로 압축하기
public byte[] downloadImage(String fileName) {
ImageData imageData = storageRepository.findByName(fileName)
.orElseThrow(RuntimeException::new);
log.info("download imageData: {}", imageData);
return ImageUtils.decompressImage(imageData.getImageData());
}
}
Repository
public interface StorageRepository extends JpaRepository<ImageData, Long> {
Optional<ImageData> findByName(String fileName);
}
Utils : ImageUtils
public class ImageUtils {
public static byte[] compressImage(byte[] data) {
Deflater deflater = new Deflater();
deflater.setLevel(Deflater.BEST_COMPRESSION);
deflater.setInput(data);
deflater.finish();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(data.length);
byte[] tmp = new byte[4*1024];
while (!deflater.finished()) {
int size = deflater.deflate(tmp);
outputStream.write(tmp, 0, size);
}
try {
outputStream.close();
} catch (Exception ignored) {
}
return outputStream.toByteArray();
}
public static byte[] decompressImage(byte[] data) {
Inflater inflater = new Inflater();
inflater.setInput(data);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(data.length);
byte[] tmp = new byte[4*1024];
try {
while (!inflater.finished()) {
int count = inflater.inflate(tmp);
outputStream.write(tmp, 0, count);
}
outputStream.close();
} catch (Exception ignored) {
}
return outputStream.toByteArray();
}
}
결과
POST - 업로드
localhost:8080/image
postman에서도 파일을 첨부해서 넣을 수 있다.
form-data
선택File
로 대체결과
DB에도 잘 저장되어 있는 것을 확인할 수 있었다.
GET - 다운로드
localhost:8080/image/black_horse_running-wallpaper-1680x1050.jpg
파일 이미지를 Body
를 통해 보여줌.
filePath를 DB에 저장하고 그 filePath에서 파일을 다운로드하는 방식
Entity : FileData
@Entity
@Table(name = "FileData")
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class FileData {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String type;
private String filePath;
@Builder
public FileData(String name, String type, String filePath) {
this.name = name;
this.type = type;
this.filePath = filePath;
}
}
Controller
@PostMapping("/fileSystem")
public ResponseEntity<?> uploadImageToFileSystem(@RequestParam("image") MultipartFile file) throws IOException {
String uploadImage = storageService.uploadImageToFileSystem(file);
return ResponseEntity.status(HttpStatus.OK)
.body(uploadImage);
}
@GetMapping("/fileSystem/{fileName}")
public ResponseEntity<?> downloadImageToFileSystem(@PathVariable("fileName") String fileName) throws IOException {
byte[] downloadImage = storageService.downloadImageFromFileSystem(fileName);
return ResponseEntity.status(HttpStatus.OK)
.contentType(MediaType.valueOf("image/png"))
.body(downloadImage);
}
Service
// 파일 경로 지정, 윈도우인 경우, '\' 이스케이프 2개 필요!
private final String FOLDER_PATH = "C:\\WebStudy\\WebDevelement\\SpringBoot\\storage-service\\files\\";
public String uploadImageToFileSystem(MultipartFile file) throws IOException {
log.info("upload file: {}", file.getOriginalFilename());
String filePath = FOLDER_PATH + file.getOriginalFilename();
FileData fileData = fileDataRepository.save(
FileData.builder()
.name(file.getOriginalFilename())
.type(file.getContentType())
.filePath(filePath)
.build()
);
// 파일 결로
file.transferTo(new File(filePath));
if (fileData != null) {
return "file uploaded successfully! filePath : " + filePath;
}
return null;
}
public byte[] downloadImageFromFileSystem(String fileName) throws IOException {
FileData fileData = fileDataRepository.findByName(fileName)
.orElseThrow(RuntimeException::new);
String filePath = fileData.getFilePath();
log.info("download fileData: {}", fileData);
log.info("download filePath: {}", filePath);
return Files.readAllBytes(new File(filePath).toPath());
}
Repository
public interface FileDataRepository extends JpaRepository<FileData, Long> {
Optional<FileData> findByName(String fileName);
}
결과
POST - filePath에 파일이 저장(업로드)
GET - GET은 위와 같음.(다운로드)