JAVA Developer 2003年11月号より転載
MySQLは、TINYBLOB、BLOB、MEDIUMBLOB、LONGBLOBという4種類の可変長バイナリデータを格納する型をサポートしています(表1)。それぞれの違いは、格納できるデータの最大長です。今回の目的はデジカメ写真ですので、1M~2MB前後のデータを格納できるMEDIUMBLOB型を使います。
型 | 最大サイズ(バイト) | TINYBLOB | 255(28-1) | BLOB | 65,535(216-1) | MEDIUMBLOB | 16,777,215(224-1) | LONGBLOB | 4,294,967,295(232-1) |
アップロードはJakartaCommons FileUploadを利用 | まずはクライアントPCからサーバーへのファイルアップロード機能を実装していきます。 はじめは、ファイルアップロード用のフォームです。ここでのポイントは、methodに必ず「post」を指定し、「enctype="multipart/form-data"」を記述することです。また、アップロードするファイル名は、「<input type="file" name="file1">」のように、typeで「file」を指定します。
リスト1 アップロードフォーム(抜粋) | <form name="upload" method="post" enctype="multipart/form-data"> ファイル1:<input type="file" name="file1"><br> ファイル2:<input type="file" name="file2"><br> ファイル3:<input type="file" name="file3"><br> <input type="submit" value="アップロード"> <input type="reset" value="リセット"><br> </form>
|
このフォームからデータを受け取って処理する部分には、JakartaCommons FileUpload 1.0(commons-fileupload-1.0.jar)を利用します。FileUploadのDiskFileUploadクラスでは、アップロードできる最大サイズ、メモリー内に保持するサイズなどを指定したあと、requestオブジェクトをパースし、ListにアップロードするFileItemオブジェクトを格納します(リスト2-(1))。Iteratorを使ってFileItemオブジェクトを取り出し、ImageFileオブジェクトを生成して、アップロードデータを格納していきます(リスト3)。
リスト2 ファイルのアップロードを実装(抜粋) | DiskFileUpload uploader = new DiskFileUpload(); uploader.setSizeMax(UPLOAD_LIMIT_SIZE); uploader.setSizeThreshold(IN_MEMORY_SIZE);
List items = uploader.parseRequest(request); //-(1) Iterator iter = items.iterator(); while (iter.hasNext()) { ImageFile image = new ImageFile(); if (image.set((FileItem)iter.next())) { iData.add(image); } }
|
リスト3 ImageFileクラス | public class ImageFile { public String fileName; public String contentType; public int fileSize; public InputStream inputStream;
public boolean set(FileItem item) throws IOException { fileSize = (int)item.getSize(); if (fileSize > 0) { fileName = item.getName(); contentType = item.getContentType(); inputStream = item.getInputStream(); return (fileName != null && contentType != null); } return false; } }
|
次に、ImageFileオブジェクトのデータをデータベースへ登録します。ここでは、BLOB型へのデータ登録にPreparedStatementを使います(リスト4-(2))。PreparedStatementには、データ型別にsetXXXメソッドが用意されており、その中にBLOB型に対応するsetBinaryStreamメソッドがあります(リスト4-(3))。このほかBLOB型に対応するメソッドとしては、setBlobやsetBytesメソッドがあります。
リスト4 PreparedStatementを使って登録(抜粋) | Connection con = ds.getConnection(); PreparedStatement stmt = con.prepareStatement( "INSERT INTO "+ "image(name,type,size,rawdata,entry) "+ "VALUES(?, ?, ?, ?, ?)"); //-(2)
stmt.setString(1, image.fileName); stmt.setString(2, image.contentType); stmt.setInt(3, image.size); stmt.setBinaryStream(4, image.inputStream, image.size); //-(3) java.util.Date now = new java.util.Date(); stmt.setTimestamp(5, new Timestamp(now.getTime()));
stmt.executeUpdate();
stmt.close(); con.close();
|
※imageはImageFileクラスのオブジェクト
ここまでで、アップロードからデータベースへ登録するまでのコーディングは終了です。テスト用にいくつかファイルをアップロードし、データベースに登録されていることを確認します。
「PacketTooBigException」で ファイルが格納できない |
図1 例外発生!
さらにファイルをアップロードしていくと、比較的大きめのファイルの場合に例外が発生して、うまく格納できないという症状に遭遇しました(図1)。例外はJDBCが投げているものです。例外名を手がかりにFAQを探してみると、それらしき記述を発見。解決策は、my.iniの[mysqld]セクションに、次のオプションを記述するというものです。
このオプションは、パケットの最大サイズを指定するものです。上記の場合はパケットサイズを4MBに指定しています。4MBは、普段使っているデジカメのファイルサイズより多少余裕を持たせた値です。あまり大きすぎても無駄にメモリーを使うだけですから、登録したいファイルサイズを考慮した値を指定しましょう。 MySQLを再起動し、先ほどうまく格納できなかったファイルを再度アップロード。今度は問題なく格納できました。これで、ファイルのアップロードからデータベースへの格納までは大丈夫。アップロードしたイメージの表示や検索などの機能は、これからじっくり盛り込んでいこうと思います。 読者の皆さんも、BLOB型を活用してみませんか。
参考リンク ●FileUpload 1.0 ●Jakarta CommonsなどのAPI翻訳
関連リンク JAVA Developer 定期購読のご案内 バックナンバー販売協力店
|