Добрый день!
Как хранить изображение? Насколько я знаю, их можно запихивать прямо в PostgreSQL, но я склоняюсь в сторону того, что изображения надо сохранять в ресурсы, а в бд хранить только ссылки.
Не самая лучшая идея хранить картинки в виде binary в БД. Лучше, как вы отметили в БД хранить ссылку на объект, а ресурс в файловой системе. Можно хранить файлы в распределенных файловых системах (AWS, Google), но вряд ли вы располагаете таким бюджетом.
Вот, простая реализация хранения картинок в FS.
Entity
@Entity
@Data
@NoArgsConstructor
@Table(name = "attachments")
public class Attachment {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long attachId;
private String attachTitle;
@Column(nullable = false, updatable = false)
private LocalDate uploadDate;
private String extension;
private String downloadLink;
}
Repository
@Repository
public interface AttachmentRepository extends JpaRepository<Attachment, Long> {}
Service
public interface AttachmentService {
/**
* Загрузить новый файл
*
* @param file
* @param user
* @throws IOException
*/
Attachment addAttachment(MultipartFile file, User user) throws IOException;
/**
* Найти Вложение по его ID
*
* @param attachId
* @return
*/
Attachment findAttachById(Long attachId);
/**
* Скачать файл
*
* @param uploadYear
* @param fileName
* @return
* @throws MalformedURLException
*/
Resource loadFileAsResource(String uploadYear, String fileName) throws MalformedURLException;
}
ServiceImpl
@Service
@RequiredArgsConstructor
public class AttachmentServiceImpl implements AttachmentService {
private final AttachmentRepository attachmentRepository;
private final AppProperties appProperties;
private final FileTools fileTools;
/**
* Загрузить новый файл
*
* @param file
* @param user
* @throws IOException
*/
@Override
public Attachment addAttachment(MultipartFile file, User user) throws IOException {
// Создаем директорию если ее не существует
File uploadDir = new File(appProperties.getUploadPath());
// Если директория uploads не существует, то создаем ее
if (!uploadDir.exists()) {
uploadDir.mkdirs();
}
String curDate = LocalDateTime.now().toString();
// Создаем уникальное название для файла и загружаем файл
String fileName =
"attach_" + curDate + "_" + file.getOriginalFilename().toLowerCase().replaceAll(" ", "-");
file.transferTo(new File(uploadDir + "/" + fileName));
Attachment attachment = Attachment.builder()
.attachTitle(fileName)
.uploadDate(LocalDate.now())
.extension(fileTools.getFileExtension(file.getOriginalFilename()))
.downloadLink("/attachments/get/" + Year.now() + "/" + fileName)
.build();
attachmentRepository.save(attachment);
return attachment;
}
/**
* Найти Вложение по его ID
*
* @param attachId
* @return
*/
@Override
public Attachment findAttachById(Long attachId) {
return attachmentRepository
.findById(attachId)
.orElseThrow(() -> new AttachmentNotFoundException("Attachment not found!"));
}
/**
* Скачать файл
*
* @param fileName
* @return
* @throws MalformedURLException
*/
@Override
public Resource loadFileAsResource( String fileName)
throws MalformedURLException {
Path fileStorageLocation =
Paths.get(appProperties.getUploadPath()).toAbsolutePath().normalize();
Path filePath = fileStorageLocation.resolve(fileName).normalize();
return new UrlResource(filePath.toUri());
}
}
Conroller
@Controller
@RequiredArgsConstructor
@RequestMapping("/attachments")
public class AttachmentController {
private final AttachmentService attachmentService;
private final UserService userService;
/**
* Загрузить новое вложение
*
* @param file
* @return
* @throws IOException
*/
@PostMapping(value = "/add", produces = "application/json")
@ResponseBody
public ResponseEntity<Map<String, String>> uploadAttachment(
@RequestPart(value = "file") MultipartFile file)
throws IOException {
Attachment attachment = attachmentService.addAttachment(file);
Map<String, String> attachmentStatus = new HashMap<>();
attachmentStatus.put("status", "ok");
attachmentStatus.put("attachId", attachment.getAttachId().toString());
return ResponseEntity.ok(attachmentStatus);
}
/**
* Получить ссылку на скачивание загруженного файла
*
* @param filename
* @param request
* @return
* @throws IOException
*/
@GetMapping("/get/{filename:.+}")
public ResponseEntity<Resource> serveFile(
@PathVariable String filename, HttpServletRequest request)
throws IOException {
Resource resource = attachmentService.loadFileAsResource(filename);
String contentType;
contentType = request.getServletContext().getMimeType(resource.getFile().getAbsolutePath());
if (contentType == null) {
contentType = "application/octet-stream";
}
return ResponseEntity.ok()
.contentType(MediaType.parseMediaType(contentType))
.header(
HttpHeaders.CONTENT_DISPOSITION,
"attachment; filename=\"" + resource.getFilename() + "\"")
.body(resource);
}
}