cot_shaurma
@cot_shaurma
Java и всего понемногу

Как работать с изображениями в веб-приложениях на Java?

Делаю веб-приложение на Spring MVC - система тестирования для учеников. Суть в чём: ученик проходит тесты. При этом к каждому теста должна прилагаться картинка, с графиком функции например или с уравнением. Я никогда не сталкивался с изображениями в Java (как-то так вышло) и сейчас не вполне понимаю, каким образом мне с ними взаимодействовать и хранить их. Вопрос конкретно следующий:

1. Как хранить изображение? Насколько я знаю, их можно запихивать прямо в PostgreSQL, но я склоняюсь в сторону того, что изображения надо сохранять в ресурсы, а в бд хранить только ссылки.

2. Как сохранять изображение в ресурсы для новых тестов? Нормально ли это делать при помощи обычного FileWriter или есть какие-то специальные способы?
  • Вопрос задан
  • 3451 просмотр
Решения вопроса 1
azerphoenix
@azerphoenix Куратор тега Java
Java Software Engineer
Добрый день!

Как хранить изображение? Насколько я знаю, их можно запихивать прямо в 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);
  }
}
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы