Spring Boot + Java + PostgreSQL でDBに画像ファイルをアップロード&画面表示


はじめに

ユーザや商品等のテーブルに画像の一緒に保存したくなったので、データベース上に保存できないかどうか色々と調べた結果何とかその方法がわかったので備忘録としての残しておきます。誰かの参考になればと思います。

完成イメージ

  1. 以下のような、画面ファイルのアップロードボタンがあり、画像を選択する

  2. アップロードボタンをクリックするとアップロードしたファイルが画面に表示されます。

以下必要となるソースコードです

これの応用でウェブアプリケーションに画像の実装ができました:)

CREATE TABLE files (
  id SERIAL PRIMARY KEY,
  name VARCHAR,
  type VARCHAR,
  data BYTEA -- ポイント1: 保存したい写真のデータ型をBYTEA(byte array)にする
);
@Entity
@Table(name = "files")
@Getter @Setter @NoArgsConstructor
public class FileDB {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private String id;
  private String name;
  private String type;
   
  @Lob // ポイント2: @Lobと@Typeを以下のようにつける(@Lobはサイズが大きいデータのカラムにつけるみたい。@Typeがないと「bigintのデータが出力されてますよ」的なエラーが出る
  @Type(type = "org.hibernate.type.BinaryType")
  @Column(name = "data")
  private byte[] data;

  public FileDB(String name, String type, byte[] data) {
    this.name = name;
    this.type = type;
    this.data = data;
  }

}

<body><!-- ポイント3: formタグに「enctype="multipart/form-data"」追記 -->
  <form th:action="@{/portfolio/file/upload}" method="POST" enctype="multipart/form-data">
    <input type="file" name="file" id="file">
    <button type="submit">UPLOAD</button>
  </form>
  <div>
    <p th:text="${message}"></p>
    <img th:src="${'data:image/png;base64,'+image}" alt="">
  </div>
</body>
@Controller
@RequestMapping("/portfolio/file")
public class FileController {
  @Autowired  private FileStorageService storageService;

  @GetMapping(value="/index")
  public String index(Model m) {
    String path = "";
    m.addAttribute("path", path);
    return "file_upload";
  }

  @PostMapping("/upload")
  public String uploadFile(@RequestParam("file") MultipartFile file, Model m) {
    String message = "";
    try {
      FileDB savedFile = storageService.store(file);
      byte[] bytes = savedFile.getData();
      // ポイント4: Base64.getEncoder().encodeToString(bytes)でbyteをStringにして、Viewに渡す
      String image =  Base64.getEncoder().encodeToString(bytes);
      message = "Uploaded the file successfully: " + file.getOriginalFilename();
      m.addAttribute("message", message);
      m.addAttribute("image", image);
      return "file_upload";
    } catch (Exception e) {
      message = "Could not upload the file: " + file.getOriginalFilename() + "!";
      m.addAttribute("message", message);
      return "file_upload";
    }
  }
}
@Service
public class FileStorageService {

  @Autowired
  private FileDBRepository fileDBRepository;

  public FileDB store(MultipartFile file) throws IOException {
    String fileName = StringUtils.cleanPath(file.getOriginalFilename());
    FileDB FileDB = new FileDB(fileName, file.getContentType(), file.getBytes());

    return fileDBRepository.save(FileDB);
  }

}