LoginSignup
2
3

More than 3 years have passed since last update.

JSPから送信された画像を表示した後、MySQLのBlob型のカラムに格納する

Last updated at Posted at 2020-07-08

はじめに

私は今、学校の課題でECサイトをチームで開発しています。その際に、画面から指定された画像をMySQLデータベースのBlob型のカラムに保存するのに手間取ったので、そのやり方を記事として投稿します。

やりたいこと

画面で画像を選択する

画面遷移して選択した画像を表示する

画像をデータベースに格納する

画面から画像を選択する

<form action="displayImage" method="post" enctype=multipart/form-data>
  <p>画像</p>
  <input type="file" name="image" accept="image/*">
  <input type="submit" value="送信">
</form>

上記のようにinputタグのtypefileに指定することでバイナリファイルを選択することができるようになります。
その際にformタグでenctype=multipart/form-dataを指定します。これを指定することで複数の種類のデータをサーバーに送信することができるようになります。
また、inputタグでaccept="image/*"を選択することで選択できるファイルを画像のみに制限することができます。

選択された画像を取得する

@WebServlet("/displayImage")
@MultipartConfig(location = "/tmp")
public class DisplayImageServlet extends HttpServlet {

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        Part part = request.getPart("image");
        InputStream inputStream = part.getInputStream();

        byte[] byte = convertInputStreamToByteArray(inputStream);
        ImageBean imageBean = new ImageBean;
        imageBean.setImage(byte);

        HttpSession session = request.getSession();
        session.setAttribute("imageBean", imageBean);

        request.getRequestDispatcher("WEB-INF/jsp/image_view.jsp").forward(request, response);
    }

    //InputStreamをByte配列にする
    public byte[] convertInputStreamToByteArray(InputStream inputStream) throws IOException {
        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
        int nRead;
        byte[] data = new byte[16777215];
        while ((nRead = inputStream.read(data, 0, data.length)) != -1) {
            buffer.write(data, 0, nRead);
        }
        return buffer.toByteArray();
    }
}

画面から送信された画像を取得するServletでは、@MultipartConfigアノテーションをつける必要があります。
multipart/form-dataで送信されたデータは、getParameter()ではなくgetPart()で取得します。
その後、取得したデータをInputStreamに変換し、さらにバイト配列に変換します。
そして、変換したバイト配列をBeanに格納し、セッションに保存します。

確認画面で画像を表示する

<p>画像</p>
<img src="getImage" alt="画像">
<form action="uploadImage" method="post">
  <input type="submit" value="格納">
</form>
@WebServlet("/getImage")
public class GetImageServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        HttpSession session = request.getSession();
        InputStream inputStream = new ByteArrayInputStream(((ImageBean) session.getAttribute("imageBean")).getImage());

        BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
        BufferedImage img = ImageIO.read(bufferedInputStream);

        response.setContentType("image/png");
        OutputStream outputStream = response.getOutputStream();
        ImageIO.write(img, "png", outputStream);
        outputStream.flush();
    }
}

imgタグのsrcに画像取得用のGetImageServletのアノテーションを指定することでServletを介して画像を取得します。
GetImageServletでは、先ほどセッションに保存したImageBeanから画像のバイト配列を取得し、InputStreamに戻した後に、それを読み込んで画面に返しています。

画像をデータベースに格納する

CREATE TABLE `image` (
  `image` mediumblob
) 
@WebServlet("/uploadImage")
public class UploadImageServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        HttpSession session = request.getSession();
        ImageBean imageBean = (ImageBean) session.getAttribute("imageBean");

        ImageDao imageDao = new ImageDao();
        imageDao.uploadImage(imageBean.getImage());
    }
}
public class ImageDao {
    public void uploadImage(byte[] byte){
        PreparedStatement stmt = null;

        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            con = DriverManager.getConnection("jdbc:mysql://localhost:3306/image", "root", "root");
            stmt = con.prepareStatement("INSERT INTO image (image) VALUES (?)");
            stmt.setBinaryStream(1, new ByteArrayInputStream(byte));
            stmt.executeUpdate();

        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        } finally {
            try {
                if (con != null) {
                    con.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

画像をデータベースに格納します。バイト配列をInputStreamに変換したものをSQLのプレースホルダーにsetBinaryStream()を使って格納します。最後にSQLを発行すればデータベースへの画像の格納は完了です。

ここで、もしDisplayImageServletで画像データをInputStreamに変換した後、バイト配列に変換していないと、画像をうまくデータベースに格納することができません。
バイト配列に変換しない場合、画像を表示する際にGetImageServletInputStreamreadするとデータの最後まで読み込むので、ImageDaosetBinaryStream()を使うときにInputStreamの終端からの値を格納するのが原因っぽい?

参考

[フロントエンド] multipart/form-dataを理解してみよう
JSP/サーブレット ファイルアップロードの実装
サーブレット・JSPでDBに登録されている画像を表示

2
3
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3