SQL文を文字列で書かなければならないので、バイナリデータをSQLデータベースに入れるのはムリなんじゃないか、と思っていませんか?それができるんです。使うのはプリペアード ステートメントとBlob型。Blobというのは、Binary Large OBjectを表す略語です。
たとえば、次のようなテーブルがあったとします。
こんな感じです。
MySQLに格納したバイナリデータをブラウザに返すにはサーブレットを使います。
FileUploadの使い方やサーバからブラウザにデータを転送するサーブレットについては、拙著「Java+MySQL+Tomcatで作る掲示板とブログ」にも書いたので、こちらも参考にしてください。
画像をデータベースに入れておくと、ファイル名の重複による上書きを気にしなくてよかったり、ユーザーの権限によってアクセスコントロールができたりと、いろいろ便利ですが、オーバーヘッドがどれぐらいあるかはちょっと気になりますね。
----------------------
追記:テストに使用したjarファイルのバージョンは以下のとおりです。
commons-fileupload-1.2.1.jar
commons-io-1.4.jar
たとえば、次のようなテーブルがあったとします。
create table blob_test(
id INT auto_increment primary key,
title VARCHAR(255),
file_name VARCHAR(255),
data MEDIUMBLOB
);
dataカラムに指定しているMEDIUMBLOBは、約16Mバイトまでのバイナリデータを格納することができます。データを送信する側のフォームはこんな感じです。id INT auto_increment primary key,
title VARCHAR(255),
file_name VARCHAR(255),
data MEDIUMBLOB
);
<%@ page contentType="text/html; charset=Windows-31J"%>
<HTML>
<HEAD>
<TITLE>BLOB UPLOAD TEST</TITLE>
</HEAD>
<BODY>
<FORM ACTION ="BlobUploadProcess.jsp" METHOD="post" ENCTYPE="MULTIPART/FORM-DATA">
タイトル<INPUT TYPE="text" NAME="title"><BR>
ファイル<INPUT TYPE="file" NAME="file"><BR>
<INPUT TYPE="submit">
</FORM>
</BODY>
</HTML>
データを受信するコードではApache commonsのFileUploadを使います。<HTML>
<HEAD>
<TITLE>BLOB UPLOAD TEST</TITLE>
</HEAD>
<BODY>
<FORM ACTION ="BlobUploadProcess.jsp" METHOD="post" ENCTYPE="MULTIPART/FORM-DATA">
タイトル<INPUT TYPE="text" NAME="title"><BR>
ファイル<INPUT TYPE="file" NAME="file"><BR>
<INPUT TYPE="submit">
</FORM>
</BODY>
</HTML>
こんな感じです。
<%@ page contentType="text/html; charset=Windows-31J"%>
<%@ page import="java.sql.*"%>
<%@ page import="java.util.*"%>
<%@ page import="java.io.*"%>
<%@ page import="org.apache.commons.fileupload.*"%>
<%@ page import="org.apache.commons.fileupload.disk.*"%>
<%@ page import="org.apache.commons.fileupload.servlet.*"%>
<%
FileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
List<FileItem> items = upload.parseRequest(request);
String strTitle=null;
String strFileName=null;
InputStream stream=null;
for(FileItem item:items) {
if (item.isFormField()) { //フォームのフィールド
String strFieldName = item.getFieldName();
if(strFieldName.equals("title")){
strTitle = item.getString("Windows-31J");
}
} else { //ファイル転送
if(item.getString().equals("")){ //ファイル添付なし
}else{
strFileName=item.getName();
int intPBackslash = strFileName.lastIndexOf("\\");
if(intPBackslash!=-1){
strFileName = strFileName.substring(intPBackslash+1);
}
stream = item.getInputStream();
}
}
}
Class.forName("com.mysql.jdbc.Driver");
String strConn = "jdbc:mysql://localhost/test"
+"?user=Mulder&password=TrustNo1"
+"&useUnicode=true&characterEncoding=Windows-31J";
Connection conn = DriverManager.getConnection(strConn);
PreparedStatement pstmt = conn.prepareStatement("INSERT INTO blob_test set title=?,file_name=?,data=?");
pstmt.setString(1,strTitle);
pstmt.setString(2,strFileName);
pstmt.setBlob(3,stream);
pstmt.executeUpdate();
conn.close();
%>
<HTML><HEAD><TITLE>BLOB UPLOAD TEST</TITLE></HEAD>
<BODY>
<P>アップロード完了</P>
<P><a HREF="BlobList.jsp">一覧</a></P>
</BODY>
</HTML>
FileUploadのFileItemオブジェクトからgetInputStream()メソッドでInputStreamを取得できます。これをPreparedStatementオブジェクトのsetBlobメソッドに指定すればよいわけです。上のコードでは、アップロードできるファイルをブラウザで表示する画像に制限するため、拡張子がjpg、gif、pngのいずれかであるかどうかをチェックしています。<%@ page import="java.sql.*"%>
<%@ page import="java.util.*"%>
<%@ page import="java.io.*"%>
<%@ page import="org.apache.commons.fileupload.*"%>
<%@ page import="org.apache.commons.fileupload.disk.*"%>
<%@ page import="org.apache.commons.fileupload.servlet.*"%>
<%
FileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
List<FileItem> items = upload.parseRequest(request);
String strTitle=null;
String strFileName=null;
InputStream stream=null;
for(FileItem item:items) {
if (item.isFormField()) { //フォームのフィールド
String strFieldName = item.getFieldName();
if(strFieldName.equals("title")){
strTitle = item.getString("Windows-31J");
}
} else { //ファイル転送
if(item.getString().equals("")){ //ファイル添付なし
}else{
strFileName=item.getName();
int intPBackslash = strFileName.lastIndexOf("\\");
if(intPBackslash!=-1){
strFileName = strFileName.substring(intPBackslash+1);
}
stream = item.getInputStream();
}
}
}
Class.forName("com.mysql.jdbc.Driver");
String strConn = "jdbc:mysql://localhost/test"
+"?user=Mulder&password=TrustNo1"
+"&useUnicode=true&characterEncoding=Windows-31J";
Connection conn = DriverManager.getConnection(strConn);
PreparedStatement pstmt = conn.prepareStatement("INSERT INTO blob_test set title=?,file_name=?,data=?");
pstmt.setString(1,strTitle);
pstmt.setString(2,strFileName);
pstmt.setBlob(3,stream);
pstmt.executeUpdate();
conn.close();
%>
<HTML><HEAD><TITLE>BLOB UPLOAD TEST</TITLE></HEAD>
<BODY>
<P>アップロード完了</P>
<P><a HREF="BlobList.jsp">一覧</a></P>
</BODY>
</HTML>
MySQLに格納したバイナリデータをブラウザに返すにはサーブレットを使います。
package jp.veltec.test;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;
import java.io.*;
import java.sql.*;
public class FileDownload extends HttpServlet {
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException{
String strId = request.getParameter("id");
String strConn = "jdbc:mysql://localhost/test"
+"?user=Mulder&password=TrustNo1"
+"&useUnicode=true&characterEncoding=utf-8";
Blob data = null;
InputStream is = null;
String strFileName = null;
try{
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection(strConn);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(
"SELECT file_name,data FROM blob_test WHERE id = "
+ strId);
if(rs.next()){
data = rs.getBlob("data");
strFileName = rs.getString("file_name");
}else{
throw new IllegalArgumentException("ファイルがありません");
}
is = data.getBinaryStream();
conn.close();
}catch(SQLException e){
throw new ServletException(e.getMessage());
}catch(ClassNotFoundException e){
throw new ServletException(e.getMessage());
}
ServletOutputStream output = response.getOutputStream();
if(strFileName.endsWith(".jpg")){
response.setContentType("image/jpg");
}else if(strFileName.endsWith(".gif")){
response.setContentType("image/gif");
}else if(strFileName.endsWith(".png")){
response.setContentType("image/png");
}else{
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition"," attachment; filename=\"" + strFileName +"\"");
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[10000];
while(true){
int length = is.read(buffer);
if(length==-1){
break;
}
baos.write(buffer,0,length);
}
baos.writeTo(output);
output.flush();
}
}
上のコードでは、ResultSetオブジェクトのgetBlobメソッドでBlob型のオブジェクトを取得し、更にgetBinaryStreamメソッドでInputStreamを取得しています。その後、whileループで、InputStreamからデータを読み込んでByteArrayOutputStreamに書き出しています。import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;
import java.io.*;
import java.sql.*;
public class FileDownload extends HttpServlet {
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException{
String strId = request.getParameter("id");
String strConn = "jdbc:mysql://localhost/test"
+"?user=Mulder&password=TrustNo1"
+"&useUnicode=true&characterEncoding=utf-8";
Blob data = null;
InputStream is = null;
String strFileName = null;
try{
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection(strConn);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(
"SELECT file_name,data FROM blob_test WHERE id = "
+ strId);
if(rs.next()){
data = rs.getBlob("data");
strFileName = rs.getString("file_name");
}else{
throw new IllegalArgumentException("ファイルがありません");
}
is = data.getBinaryStream();
conn.close();
}catch(SQLException e){
throw new ServletException(e.getMessage());
}catch(ClassNotFoundException e){
throw new ServletException(e.getMessage());
}
ServletOutputStream output = response.getOutputStream();
if(strFileName.endsWith(".jpg")){
response.setContentType("image/jpg");
}else if(strFileName.endsWith(".gif")){
response.setContentType("image/gif");
}else if(strFileName.endsWith(".png")){
response.setContentType("image/png");
}else{
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition"," attachment; filename=\"" + strFileName +"\"");
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[10000];
while(true){
int length = is.read(buffer);
if(length==-1){
break;
}
baos.write(buffer,0,length);
}
baos.writeTo(output);
output.flush();
}
}
FileUploadの使い方やサーバからブラウザにデータを転送するサーブレットについては、拙著「Java+MySQL+Tomcatで作る掲示板とブログ」にも書いたので、こちらも参考にしてください。
画像をデータベースに入れておくと、ファイル名の重複による上書きを気にしなくてよかったり、ユーザーの権限によってアクセスコントロールができたりと、いろいろ便利ですが、オーバーヘッドがどれぐらいあるかはちょっと気になりますね。
----------------------
追記:テストに使用したjarファイルのバージョンは以下のとおりです。
commons-fileupload-1.2.1.jar
commons-io-1.4.jar
投稿:竹形 誠司[takegata]/2008年 01月 15日 22時 21分
/更新:2009年 02月 22日 00時 26分
バックアップの取り方
by 竹形 誠司[takegata]
バイナリデータを含むBLOBカラムは、そのままではmysqldumpでバックアップが取れません。この場合は次のようにmysqldumpで、hex-blobオプションを指定します。
shell> mysqldump --hex-blob -u root -p test > test.sql
投稿:竹形 誠司[takegata]/2008年 02月 06日 12時 19分
/更新:2008年 02月 06日 12時 20分
PreparedStatement の setBlobメソッドにInputStreamを直接渡せるのは、J2SE6.0からです。J2SE5.0ではBlob型(java.sqlパッケージで定義されている)のオブジェクトを渡す必要があります。
Mac OSX のJava 6 が早く欲しいところですね。
Mac OSX のJava 6 が早く欲しいところですね。
投稿:竹形 誠司[takegata]/2008年 02月 06日 14時 20分
/更新:2008年 02月 06日 14時 38分
setBlobではなく、setBytesでいけるかも知れません。こんな感じです。
情報元:
http://okwave.jp/qa3455885.html
pstmt.setBytes(3, item.get());
今、ちょっと時間がなくて試せませんが、これがOKならJ2SE5.0でも大丈夫ですね。情報元:
http://okwave.jp/qa3455885.html
投稿:竹形 誠司[takegata]/2008年 02月 09日 15時 45分
/更新:2008年 02月 09日 16時 15分
上のコードでは変数 「item」 がforループの中でしか使えないので、エラーになってしまいますね。「InputStreamの代わりにbyte[]を使う」ということなので、BlobUploadProcess.jspは次のようになります。
<%@ page contentType="text/html; charset=Windows-31J"%>
<%@ page import="java.sql.*"%>
<%@ page import="java.util.*"%>
<%@ page import="java.io.*"%>
<%@ page import="org.apache.commons.fileupload.*"%>
<%@ page import="org.apache.commons.fileupload.disk.*"%>
<%@ page import="org.apache.commons.fileupload.servlet.*"%>
<%
FileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
List<FileItem> items = upload.parseRequest(request);
String strTitle=null;
String strFileName=null;
//InputStream stream=null;
byte[] aryBytesFile = null;//←★
for(FileItem item:items) {
if (item.isFormField()) { //フォームのフィールド
String strFieldName = item.getFieldName();
if(strFieldName.equals("title")){
strTitle = item.getString("Windows-31J");
}
} else { //ファイル転送
if(item.getString().equals("")){ //ファイル添付なし
}else{
strFileName=item.getName();
int intPBackslash = strFileName.lastIndexOf("\\");
if(intPBackslash!=-1){
strFileName = strFileName.substring(intPBackslash+1);
}
//stream = item.getInputStream();
aryBytesFile = item.get();//←★
}
}
}
Class.forName("com.mysql.jdbc.Driver");
String strConn = "jdbc:mysql://localhost/test"
+"?user=Mulder&password=TrustNo1"
+"&useUnicode=true&characterEncoding=utf-8";
Connection conn = DriverManager.getConnection(strConn);
PreparedStatement pstmt = conn.prepareStatement("INSERT INTO blob_test set title=?,file_name=?,data=?");
pstmt.setString(1,strTitle);
pstmt.setString(2,strFileName);
//pstmt.setBlob(3,stream);
pstmt.setBytes(3,aryBytesFile);//←★
pstmt.executeUpdate();
conn.close();
%>
<HTML><HEAD><TITLE>BLOB UPLOAD TEST</TITLE></HEAD>
<BODY>
<P>アップロード完了</P>
<P><a HREF="BlobList.jsp">一覧</a></P>
</BODY>
</HTML>
<%@ page import="java.sql.*"%>
<%@ page import="java.util.*"%>
<%@ page import="java.io.*"%>
<%@ page import="org.apache.commons.fileupload.*"%>
<%@ page import="org.apache.commons.fileupload.disk.*"%>
<%@ page import="org.apache.commons.fileupload.servlet.*"%>
<%
FileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
List<FileItem> items = upload.parseRequest(request);
String strTitle=null;
String strFileName=null;
//InputStream stream=null;
byte[] aryBytesFile = null;//←★
for(FileItem item:items) {
if (item.isFormField()) { //フォームのフィールド
String strFieldName = item.getFieldName();
if(strFieldName.equals("title")){
strTitle = item.getString("Windows-31J");
}
} else { //ファイル転送
if(item.getString().equals("")){ //ファイル添付なし
}else{
strFileName=item.getName();
int intPBackslash = strFileName.lastIndexOf("\\");
if(intPBackslash!=-1){
strFileName = strFileName.substring(intPBackslash+1);
}
//stream = item.getInputStream();
aryBytesFile = item.get();//←★
}
}
}
Class.forName("com.mysql.jdbc.Driver");
String strConn = "jdbc:mysql://localhost/test"
+"?user=Mulder&password=TrustNo1"
+"&useUnicode=true&characterEncoding=utf-8";
Connection conn = DriverManager.getConnection(strConn);
PreparedStatement pstmt = conn.prepareStatement("INSERT INTO blob_test set title=?,file_name=?,data=?");
pstmt.setString(1,strTitle);
pstmt.setString(2,strFileName);
//pstmt.setBlob(3,stream);
pstmt.setBytes(3,aryBytesFile);//←★
pstmt.executeUpdate();
conn.close();
%>
<HTML><HEAD><TITLE>BLOB UPLOAD TEST</TITLE></HEAD>
<BODY>
<P>アップロード完了</P>
<P><a HREF="BlobList.jsp">一覧</a></P>
</BODY>
</HTML>
投稿:竹形 誠司[takegata]/2008年 08月 10日 16時 58分
/更新:2008年 08月 10日 17時 01分
BlobList.jspはこんな感じです。大したコードではありませんが、一応載せておきます。
<%@ page contentType="text/html; charset=Windows-31J"%>
<%@ page import="java.sql.*"%>
<%@ page import="jp.veltec.test.*"%>
<%
Class.forName("com.mysql.jdbc.Driver");
String strConn = "jdbc:mysql://localhost/test"
+"?user=Mulder&password=TrustNo1"
+"&useUnicode=true&characterEncoding=utf-8";
Connection conn = DriverManager.getConnection(strConn);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT id,title,file_name FROM blob_test");
%>
<HTML>
BLOB UPLOAD TEST<BR>
<%while(rs.next()){%>
<%=rs.getInt("id")%>:
<a HREF="FileDownload?id=<%=rs.getInt("id")%>"><%=rs.getString("title")%></a>:
<BR>
<%}%>
<a HREF="BlobUploadForm.jsp">アップロード</a><BR>
</FORM>
</HTML>
<%@ page import="java.sql.*"%>
<%@ page import="jp.veltec.test.*"%>
<%
Class.forName("com.mysql.jdbc.Driver");
String strConn = "jdbc:mysql://localhost/test"
+"?user=Mulder&password=TrustNo1"
+"&useUnicode=true&characterEncoding=utf-8";
Connection conn = DriverManager.getConnection(strConn);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT id,title,file_name FROM blob_test");
%>
<HTML>
BLOB UPLOAD TEST<BR>
<%while(rs.next()){%>
<%=rs.getInt("id")%>:
<a HREF="FileDownload?id=<%=rs.getInt("id")%>"><%=rs.getString("title")%></a>:
<BR>
<%}%>
<a HREF="BlobUploadForm.jsp">アップロード</a><BR>
</FORM>
</HTML>
投稿:竹形 誠司[takegata]/2009年 02月 20日 21時 34分
/更新:2009年 02月 20日 21時 40分
竹形様
ありがとうございました。
一覧開けました。
すみませんが、ワード文書、エクセル、PDFをアップロードダウンロードしたいのですが、FileDownload.javaのコンテントタイプはどのように設定すればよいのでしょうか。
BlobUpload.jspを以下のように修正してみたのですが、
ご教示おねがいします。
ありがとうございました。
一覧開けました。
すみませんが、ワード文書、エクセル、PDFをアップロードダウンロードしたいのですが、FileDownload.javaのコンテントタイプはどのように設定すればよいのでしょうか。
BlobUpload.jspを以下のように修正してみたのですが、
if(item.getString().equals("")){ //ファイル添付なし
}else{
strFileName=item.getName();
if(!strFileName.endsWith(".jpg") &&
!strFileName.endsWith(".gif") &&
!strFileName.endsWith(".pdf") &&
!strFileName.endsWith(".xls") &&
!strFileName.endsWith(".txt") &&
!strFileName.endsWith(".doc") &&
!strFileName.endsWith(".png") ){response.setContentType("image/png")
ダウンロードのファイルダウンロードのコンテントタイプの設定が分からず壊れたファイルになってしまいます。}else{
strFileName=item.getName();
if(!strFileName.endsWith(".jpg") &&
!strFileName.endsWith(".gif") &&
!strFileName.endsWith(".pdf") &&
!strFileName.endsWith(".xls") &&
!strFileName.endsWith(".txt") &&
!strFileName.endsWith(".doc") &&
!strFileName.endsWith(".png") ){response.setContentType("image/png")
ご教示おねがいします。
投稿:スワジランド[swajiland]/2009年 02月 20日 23時 45分
/更新:2009年 02月 20日 23時 45分
竹形様
何度もすみません。
jpgデータをアップロードしたところ、以下のようなエラーで落ちました。
You can change this value on the server by setting the max_allowed_packet' variable
とあるのですが、どこの設定をかえればよいのでしょうかご教示おねがいします。
何度もすみません。
jpgデータをアップロードしたところ、以下のようなエラーで落ちました。
org.apache.jasper.JasperException: An exception occurred processing JSP page /BlobUploadProcess.jsp at line 52
49: pstmt.setString(1,strTitle);
50: pstmt.setString(2,strFileName);
51: pstmt.setBlob(3,stream);
52: pstmt.executeUpdate();
53: conn.close();
54: %>
55: <HTML><HEAD><TITLE>BLOB UPLOAD TEST</TITLE></HEAD>
Stacktrace:
org.apache.jasper.servlet.JspServletWrapper.handleJspException(JspServletWrapper.java:505)
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:398)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:342)
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:267)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
原因
javax.servlet.ServletException: com.mysql.jdbc.PacketTooBigException: Packet for query is too large (2249702 > 1048576). You can change this value on the server by setting the max_allowed_packet' variable.
org.apache.jasper.runtime.PageContextImpl.doHandlePageException(PageContextImpl.java:852)
org.apache.jasper.runtime.PageContextImpl.handlePageException(PageContextImpl.java:781)
org.apache.jsp.BlobUploadProcess_jsp._jspService(BlobUploadProcess_jsp.java:126)
org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:374)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:342)
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:267)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
原因
com.mysql.jdbc.PacketTooBigException: Packet for query is too large (2249702 > 1048576). You can change this value on the server by setting the max_allowed_packet' variable.
com.mysql.jdbc.MysqlIO.send(MysqlIO.java:3202)
com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1932)
com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2101)
com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2554)
com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1761)
com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2046)
com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1964)
com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1949)
org.apache.jsp.BlobUploadProcess_jsp._jspService(BlobUploadProcess_jsp.java:110)
org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:374)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:342)
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:267)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
Packet for query is too large (2249702 > 1048576). だそうで49: pstmt.setString(1,strTitle);
50: pstmt.setString(2,strFileName);
51: pstmt.setBlob(3,stream);
52: pstmt.executeUpdate();
53: conn.close();
54: %>
55: <HTML><HEAD><TITLE>BLOB UPLOAD TEST</TITLE></HEAD>
Stacktrace:
org.apache.jasper.servlet.JspServletWrapper.handleJspException(JspServletWrapper.java:505)
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:398)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:342)
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:267)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
原因
javax.servlet.ServletException: com.mysql.jdbc.PacketTooBigException: Packet for query is too large (2249702 > 1048576). You can change this value on the server by setting the max_allowed_packet' variable.
org.apache.jasper.runtime.PageContextImpl.doHandlePageException(PageContextImpl.java:852)
org.apache.jasper.runtime.PageContextImpl.handlePageException(PageContextImpl.java:781)
org.apache.jsp.BlobUploadProcess_jsp._jspService(BlobUploadProcess_jsp.java:126)
org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:374)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:342)
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:267)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
原因
com.mysql.jdbc.PacketTooBigException: Packet for query is too large (2249702 > 1048576). You can change this value on the server by setting the max_allowed_packet' variable.
com.mysql.jdbc.MysqlIO.send(MysqlIO.java:3202)
com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1932)
com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2101)
com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2554)
com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1761)
com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2046)
com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1964)
com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1949)
org.apache.jsp.BlobUploadProcess_jsp._jspService(BlobUploadProcess_jsp.java:110)
org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:374)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:342)
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:267)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
You can change this value on the server by setting the max_allowed_packet' variable
とあるのですが、どこの設定をかえればよいのでしょうかご教示おねがいします。
投稿:スワジランド[swajiland]/2009年 02月 21日 01時 01分
/更新:2009年 02月 21日 01時 02分
原因の所に
com.mysql.jdbc.PacketTooBigException:
と書いてあるので、これはMySQLの設定ですね。設定ファイル(Windowsであれば、my.ini)のmysqldセクションに次のような行を入れて、MySQLを再起動してみてください。max_allowed_packet=10M
これで10Mバイトまでのファイルが登録できるようになると思います。
投稿:竹形 誠司[takegata]/2009年 02月 21日 11時 44分
/更新:2009年 02月 21日 12時 06分
上のサーブレットの次の部分
次のような行を上のブロックに挿入すると、PDFファイルを選んだときにダウンロードのダイアログボックスではなく、Adobeリーダーを起動してPDFファイルの内容を表示することができます。
if(strFileName.endsWith(".jpg")){
response.setContentType("image/jpg");
}else if(strFileName.endsWith(".gif")){
response.setContentType("image/gif");
}else if(strFileName.endsWith(".png")){
response.setContentType("image/png");
}else{
response.setContentType("application/octet-stream");
}
はファイル名の拡張子を調べてContentTypeを設定していますが、jpg、gif、png以外の場合は"application/octet-stream"を設定しています。.pdfや.docもここに入るので、ダウンロードのダイアログボックスが表示されるはずです。response.setContentType("image/jpg");
}else if(strFileName.endsWith(".gif")){
response.setContentType("image/gif");
}else if(strFileName.endsWith(".png")){
response.setContentType("image/png");
}else{
response.setContentType("application/octet-stream");
}
次のような行を上のブロックに挿入すると、PDFファイルを選んだときにダウンロードのダイアログボックスではなく、Adobeリーダーを起動してPDFファイルの内容を表示することができます。
}else if(strFileName.endsWith(".pdf")){
response.setContentType("application/pdf");
WordやExcelの場合も同様ですが、一般のアプリケーションの場合は一度ダウンロードしてから開いてもらった方が良いのではないでしょうか。response.setContentType("application/pdf");
投稿:竹形 誠司[takegata]/2009年 02月 21日 12時 05分
/更新:2009年 02月 21日 12時 05分
BlobUploadProcess.jspでファイルサイズを制限するようにしてみました。
画面を表示する際にstrErrorMessageがnullかどうかをチェックして表示を切り替えています。
<%@ page contentType="text/html; charset=Windows-31J"%>
<%@ page import="java.sql.*"%>
<%@ page import="java.util.*"%>
<%@ page import="java.io.*"%>
<%@ page import="org.apache.commons.fileupload.*"%>
<%@ page import="org.apache.commons.fileupload.disk.*"%>
<%@ page import="org.apache.commons.fileupload.servlet.*"%>
<%@ page import="org.apache.commons.fileupload.FileUploadBase.*"%>
<%
FileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
String strTitle=null;
String strFileName=null;
String strErrorMessage=null;
upload.setSizeMax(1000000);//1M byte ←★
try{ //←★
List<FileItem> items = upload.parseRequest(request);
//InputStream stream=null;
byte[] aryBytesFile = null;
for(FileItem item:items) {
if (item.isFormField()) { //フォームのフィールド
String strFieldName = item.getFieldName();
if(strFieldName.equals("title")){
strTitle = item.getString("Windows-31J");
}
} else { //ファイル転送
if(item.getString().equals("")){ //ファイル添付なし
}else{
strFileName=item.getName();
int intPBackslash = strFileName.lastIndexOf("\\");
if(intPBackslash!=-1){
strFileName = strFileName.substring(intPBackslash+1);
}
//stream = item.getInputStream();
aryBytesFile = item.get();
}
}
}
Class.forName("com.mysql.jdbc.Driver");
String strConn = "jdbc:mysql://localhost/test"
+"?user=Mulder&password=TrustNo1"
+"&useUnicode=true&characterEncoding=utf-8";
Connection conn = DriverManager.getConnection(strConn);
PreparedStatement pstmt = conn.prepareStatement("INSERT INTO blob_test set title=?,file_name=?,data=?");
pstmt.setString(1,strTitle);
pstmt.setString(2,strFileName);
//pstmt.setBlob(3,stream);
pstmt.setBytes(3,aryBytesFile);
pstmt.executeUpdate();
conn.close();
}catch(SizeLimitExceededException e){ //←★
strErrorMessage="フィルサイズが制限(1Mバイト)を超えています";
}
%>
<HTML><HEAD><TITLE>BLOB UPLOAD TEST</TITLE></HEAD>
<BODY>
<P>
<%if(strErrorMessage==null){//←★%>
アップロード完了<BR>
<a HREF="BlobList.jsp">一覧</a>
<%}else{%>
<%=strErrorMessage%><BR>
<INPUT TYPE="button" VALUE="戻る" ONCLICK="history.back()">
<%}%>
</P>
</BODY>
</HTML>
上のコードでは<%@ page import="java.sql.*"%>
<%@ page import="java.util.*"%>
<%@ page import="java.io.*"%>
<%@ page import="org.apache.commons.fileupload.*"%>
<%@ page import="org.apache.commons.fileupload.disk.*"%>
<%@ page import="org.apache.commons.fileupload.servlet.*"%>
<%@ page import="org.apache.commons.fileupload.FileUploadBase.*"%>
<%
FileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
String strTitle=null;
String strFileName=null;
String strErrorMessage=null;
upload.setSizeMax(1000000);//1M byte ←★
try{ //←★
List<FileItem> items = upload.parseRequest(request);
//InputStream stream=null;
byte[] aryBytesFile = null;
for(FileItem item:items) {
if (item.isFormField()) { //フォームのフィールド
String strFieldName = item.getFieldName();
if(strFieldName.equals("title")){
strTitle = item.getString("Windows-31J");
}
} else { //ファイル転送
if(item.getString().equals("")){ //ファイル添付なし
}else{
strFileName=item.getName();
int intPBackslash = strFileName.lastIndexOf("\\");
if(intPBackslash!=-1){
strFileName = strFileName.substring(intPBackslash+1);
}
//stream = item.getInputStream();
aryBytesFile = item.get();
}
}
}
Class.forName("com.mysql.jdbc.Driver");
String strConn = "jdbc:mysql://localhost/test"
+"?user=Mulder&password=TrustNo1"
+"&useUnicode=true&characterEncoding=utf-8";
Connection conn = DriverManager.getConnection(strConn);
PreparedStatement pstmt = conn.prepareStatement("INSERT INTO blob_test set title=?,file_name=?,data=?");
pstmt.setString(1,strTitle);
pstmt.setString(2,strFileName);
//pstmt.setBlob(3,stream);
pstmt.setBytes(3,aryBytesFile);
pstmt.executeUpdate();
conn.close();
}catch(SizeLimitExceededException e){ //←★
strErrorMessage="フィルサイズが制限(1Mバイト)を超えています";
}
%>
<HTML><HEAD><TITLE>BLOB UPLOAD TEST</TITLE></HEAD>
<BODY>
<P>
<%if(strErrorMessage==null){//←★%>
アップロード完了<BR>
<a HREF="BlobList.jsp">一覧</a>
<%}else{%>
<%=strErrorMessage%><BR>
<INPUT TYPE="button" VALUE="戻る" ONCLICK="history.back()">
<%}%>
</P>
</BODY>
</HTML>
upload.setSizeMax(1000000);
で上限を1Mバイトに設定しています。アップロードされたファイルがこのサイズを超えるとSizeLimitExceededException がスローされるので、これをキャッチしてstrErrorMessageにメッセージを書き込みます。画面を表示する際にstrErrorMessageがnullかどうかをチェックして表示を切り替えています。
投稿:竹形 誠司[takegata]/2009年 02月 21日 12時 30分
/更新:2009年 02月 21日 12時 31分
竹形様
ご指導ありがとうございます。
My.iniにmax_allowed_packet=10Mを追加しましたら、デスクトップにある2M程度のjpgファイルをアップロードすることが可能になりました。しかし、Cドライブの中の600k程度のファイルをアップロードしたら、以下のような別なエラーが発生しました。どうしてでしょうか。
それと、一覧画面でファイル名をクリックしてダウンロードした場合、どのファイルも拡張子なしでFileDownloadという名前になってしまいます。
どうかご教示おねがいいたします。
ご指導ありがとうございます。
My.iniにmax_allowed_packet=10Mを追加しましたら、デスクトップにある2M程度のjpgファイルをアップロードすることが可能になりました。しかし、Cドライブの中の600k程度のファイルをアップロードしたら、以下のような別なエラーが発生しました。どうしてでしょうか。
それと、一覧画面でファイル名をクリックしてダウンロードした場合、どのファイルも拡張子なしでFileDownloadという名前になってしまいます。
どうかご教示おねがいいたします。
org.apache.jasper.JasperException: An exception occurred processing JSP page /BlobUploadProcess.jsp at line 42
39: !strFileName.endsWith(".txt") &&
40: !strFileName.endsWith(".doc") &&
41: !strFileName.endsWith(".png") ){
42: throw new IllegalArgumentException("送信可能なファイルの拡張子は、jpg、gif、xls、doc、txt、pdfのいずれかです");
43: }
44: int intPBackslash = strFileName.lastIndexOf("\\");
45: if(intPBackslash!=-1){
Stacktrace:
org.apache.jasper.servlet.JspServletWrapper.handleJspException(JspServletWrapper.java:505)
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:416)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:342)
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:267)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
原因
java.lang.IllegalArgumentException: 送信可能なファイルの拡張子は、jpg、gif、xls、doc、txt、pdfのいずれかです
org.apache.jsp.BlobUploadProcess_jsp._jspService(BlobUploadProcess_jsp.java:100)
org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:374)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:342)
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:267)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
39: !strFileName.endsWith(".txt") &&
40: !strFileName.endsWith(".doc") &&
41: !strFileName.endsWith(".png") ){
42: throw new IllegalArgumentException("送信可能なファイルの拡張子は、jpg、gif、xls、doc、txt、pdfのいずれかです");
43: }
44: int intPBackslash = strFileName.lastIndexOf("\\");
45: if(intPBackslash!=-1){
Stacktrace:
org.apache.jasper.servlet.JspServletWrapper.handleJspException(JspServletWrapper.java:505)
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:416)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:342)
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:267)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
原因
java.lang.IllegalArgumentException: 送信可能なファイルの拡張子は、jpg、gif、xls、doc、txt、pdfのいずれかです
org.apache.jsp.BlobUploadProcess_jsp._jspService(BlobUploadProcess_jsp.java:100)
org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:374)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:342)
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:267)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
投稿:スワジランド[swajiland]/2009年 02月 21日 12時 44分
/更新:2009年 02月 21日 12時 45分
コード全体を見てみないと何とも言えませんが、ファイル名をMySQLに入れる時点でFileDownloadという名前になってしまっているのではないでしょうか。
投稿:竹形 誠司[takegata]/2009年 02月 21日 13時 00分
/更新:2009年 02月 21日 13時 00分
竹形様
MySQLへ登録しているfile_nameはアップロードしたファイル名になっています。
それと、txtファイルをアップロードして、それをダウンロードしたときに
ご指導お願い申し上げます。
MySQLへ登録しているfile_nameはアップロードしたファイル名になっています。
それと、txtファイルをアップロードして、それをダウンロードしたときに
javax.servlet.ServletException: サーブレットの実行により例外を投げました
原因
java.lang.NoClassDefFoundError: javax/servlet/ServletInputStream
org.apache.commons.fileupload.servlet.ServletFileUpload.parseRequest(ServletFileUpload.java:126)
UploadFile.doPost(UploadFile.java:53)
javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
原因
java.lang.ClassNotFoundException: javax.servlet.ServletInputStream
java.net.URLClassLoader$1.run(URLClassLoader.java:200)
java.security.AccessController.doPrivileged(Native Method)
java.net.URLClassLoader.findClass(URLClassLoader.java:188)
java.lang.ClassLoader.loadClass(ClassLoader.java:307)
sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
java.lang.ClassLoader.loadClass(ClassLoader.java:252)
java.lang.ClassLoader.loadClassInternal(ClassLoader.java:320)
org.apache.commons.fileupload.servlet.ServletFileUpload.parseRequest(ServletFileUpload.java:126)
UploadFile.doPost(UploadFile.java:53)
javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
注意 原因のすべてのスタックトレースは、Apache Tomcat/6.0.18のログに記録されています
というエラーが発生しました。プログラムはご指導いただいたものをほとんど無修正で使用しています。テーブルも同一のものを使用しています。原因
java.lang.NoClassDefFoundError: javax/servlet/ServletInputStream
org.apache.commons.fileupload.servlet.ServletFileUpload.parseRequest(ServletFileUpload.java:126)
UploadFile.doPost(UploadFile.java:53)
javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
原因
java.lang.ClassNotFoundException: javax.servlet.ServletInputStream
java.net.URLClassLoader$1.run(URLClassLoader.java:200)
java.security.AccessController.doPrivileged(Native Method)
java.net.URLClassLoader.findClass(URLClassLoader.java:188)
java.lang.ClassLoader.loadClass(ClassLoader.java:307)
sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
java.lang.ClassLoader.loadClass(ClassLoader.java:252)
java.lang.ClassLoader.loadClassInternal(ClassLoader.java:320)
org.apache.commons.fileupload.servlet.ServletFileUpload.parseRequest(ServletFileUpload.java:126)
UploadFile.doPost(UploadFile.java:53)
javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
注意 原因のすべてのスタックトレースは、Apache Tomcat/6.0.18のログに記録されています
ご指導お願い申し上げます。
投稿:スワジランド[swajiland]/2009年 02月 21日 14時 16分
/更新:2009年 02月 21日 14時 16分
うーむ、そうですか。
ちょっと調べるのでお待ちください。
ちょっと調べるのでお待ちください。
投稿:竹形 誠司[takegata]/2009年 02月 21日 14時 47分
/更新:2009年 02月 21日 15時 30分
ダウンロードの際のファイル名がFileDownloadになってしまう件は、私の勘違いでした。
アップロードの際にエラーが出る件は引き続き調べます。
response.setContentType("application/octet-stream");
の下あたりにresponse.setHeader("Content-Disposition"," attachment; filename=\"" + strFileName +"\"");
を入れてみてください。アップロードの際にエラーが出る件は引き続き調べます。
投稿:竹形 誠司[takegata]/2009年 02月 21日 15時 28分
/更新:2009年 02月 21日 15時 28分
アップロードの際のエラーはよく分かりませんね。エラーメッセージが
java.lang.IllegalArgumentException: 送信可能なファイルの拡張子は、jpg、gif、xls、doc、txt、pdfのいずれかです
とのことですが、アップロードしようとしているファイルの拡張子を判別している所が問題なのではないでしょうか。
投稿:竹形 誠司[takegata]/2009年 02月 21日 16時 43分
/更新:2009年 02月 21日 16時 43分
竹形様
どうもありがとうございました。
無事にアップロード、ダウンロードともにできるようになりました。
アップロードの失敗の原因はよくわかりませんが
必ずしも大きいファイルの時にここでひっかかっているわけではないみたいです。600kb程度でひっかかっていましたが、3Mbでは問題なく通っていましたのでとりあえずこの1行だけコメントにしたところ難なく通ってしまいました。
本当にありがとうございました。1日で解決できて感謝しております。
ラッキー!!
どうもありがとうございました。
無事にアップロード、ダウンロードともにできるようになりました。
アップロードの失敗の原因はよくわかりませんが
if(!strFileName.endsWith(".jpg") &&
!strFileName.endsWith(".gif") &&
!strFileName.endsWith(".pdf") &&
!strFileName.endsWith(".xls") &&
!strFileName.endsWith(".txt") &&
!strFileName.endsWith(".doc") &&
!strFileName.endsWith(".png") ){
// throw new IllegalArgumentException("送信可能なファイルの拡張子は、jpg、gif、xls、doc、txt、pdfのいずれかです");
}
のようにコメントアウトにしたところ、問題なく通るようになりました。!strFileName.endsWith(".gif") &&
!strFileName.endsWith(".pdf") &&
!strFileName.endsWith(".xls") &&
!strFileName.endsWith(".txt") &&
!strFileName.endsWith(".doc") &&
!strFileName.endsWith(".png") ){
// throw new IllegalArgumentException("送信可能なファイルの拡張子は、jpg、gif、xls、doc、txt、pdfのいずれかです");
}
必ずしも大きいファイルの時にここでひっかかっているわけではないみたいです。600kb程度でひっかかっていましたが、3Mbでは問題なく通っていましたのでとりあえずこの1行だけコメントにしたところ難なく通ってしまいました。
本当にありがとうございました。1日で解決できて感謝しております。
ラッキー!!
投稿:スワジランド[swajiland]/2009年 02月 22日 00時 15分
/更新:2009年 02月 22日 00時 15分
画像に限定しないのであれば、拡張子のチェックは不要でしたね。↑のソースも修正しました。
ただ、ダウンロードのコードには少し問題があって、ファイル名に日本語が含まれる場合は、保存するファイルの名前が化けてしまいます。これはブラウザに依存する要素もあって、なかなか一筋縄ではいかないようです。
ただ、ダウンロードのコードには少し問題があって、ファイル名に日本語が含まれる場合は、保存するファイルの名前が化けてしまいます。これはブラウザに依存する要素もあって、なかなか一筋縄ではいかないようです。
投稿:竹形 誠司[takegata]/2009年 02月 22日 00時 30分
/更新:2009年 02月 22日 00時 30分
竹形様
昨日はご指導誠にありがとうございました。
おかげさまで昨夜はぐっすり眠ることができました。(朝の4時頃までいろいろやってましたけど・・・)
お昼過ぎに起きて、日本語名のファイルをアップロード、ダウンロードしたら文字化けしたのでギョギョ!!いったい何が起こったのか?昨日と状態が変わってしまったのか?と思いきや昨夜は全て英数文字のファイル名しかアップロード、ダウンロードしていませんでした。
そして再度質問しようとしたら、既に先生からは先を読まれた書き込みがされていたので、恐れ入りました。結果的には残念。
この問題はcharset=Shift_JISのような呪文で解決できないのでしょうか。
折角MySQLには正しいファイル名が保存されているのにダウンロード時に文字化けしてしまうのはもったいない限りです。
昨日はご指導誠にありがとうございました。
おかげさまで昨夜はぐっすり眠ることができました。(朝の4時頃までいろいろやってましたけど・・・)
お昼過ぎに起きて、日本語名のファイルをアップロード、ダウンロードしたら文字化けしたのでギョギョ!!いったい何が起こったのか?昨日と状態が変わってしまったのか?と思いきや昨夜は全て英数文字のファイル名しかアップロード、ダウンロードしていませんでした。
そして再度質問しようとしたら、既に先生からは先を読まれた書き込みがされていたので、恐れ入りました。結果的には残念。
この問題はcharset=Shift_JISのような呪文で解決できないのでしょうか。
折角MySQLには正しいファイル名が保存されているのにダウンロード時に文字化けしてしまうのはもったいない限りです。
投稿:スワジランド[swajiland]/2009年 02月 22日 14時 40分
/更新:2009年 02月 22日 14時 40分
ダウンロード時に日本語のファイル名が化けてしまう問題については、「Content-Disposition 日本語」でGoogleを検索するといろいろ情報が出てきます。
http://www.google.co.jp/search?q=Content-Disposition+%E6%97%A5%E6%9C%AC%E8%AA%9E&lr=lang_ja&ie=utf-8&oe=utf-8
私もなんとか解決方法を見つけたいと思っています。何か分かれば、またここに書きますね。
http://www.google.co.jp/search?q=Content-Disposition+%E6%97%A5%E6%9C%AC%E8%AA%9E&lr=lang_ja&ie=utf-8&oe=utf-8
私もなんとか解決方法を見つけたいと思っています。何か分かれば、またここに書きますね。
投稿:竹形 誠司[takegata]/2009年 02月 22日 14時 55分
/更新:2009年 02月 22日 14時 55分
↓のサイトを参考にコードを修正してみました。IEとFirefoxはこれで行けそうな感じです。
http://blog.flup.jp/2008/04/04/servlet_japanese_filename_download/
http://blog.flup.jp/2008/04/04/servlet_japanese_filename_download/
package jp.veltec.test;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;
import java.io.*;
import java.sql.*;
import org.apache.commons.codec.binary.Base64;
import java.net.URLEncoder;
import javax.mail.internet.MimeUtility;
public class FileDownload extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException{
String strId = request.getParameter("id");
String strConn = "jdbc:mysql://localhost/test"
+"?user=Mulder&password=TrustNo1"
+"&useUnicode=true&characterEncoding=utf-8";
Blob data = null;
InputStream is = null;
String strFileName = null;
try{
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection(strConn);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT file_name,data FROM blob_test WHERE id = " + strId);
if(rs.next()){
data = rs.getBlob("data");
strFileName = rs.getString("file_name");
}else{
throw new IllegalArgumentException("ファイルがありません");
}
is = data.getBinaryStream();
conn.close();
}catch(SQLException e){
throw new ServletException(e.getMessage());
}catch(ClassNotFoundException e){
throw new ServletException(e.getMessage());
}
String strFileNameReturn = null;
//↓★
if(request.getHeader("User-Agent").indexOf("MSIE") != -1){
strFileNameReturn = URLEncoder.encode(strFileName,"utf-8");
}else{
strFileNameReturn = MimeUtility.encodeWord(strFileName, "ISO-2022-JP", "B");
}
ServletOutputStream output = response.getOutputStream();
if(strFileName.endsWith(".jpg")){
response.setContentType("image/jpg");
}else if(strFileName.endsWith(".gif")){
response.setContentType("image/gif");
}else if(strFileName.endsWith(".png")){
response.setContentType("image/png");
}else if(strFileName.endsWith(".pdf")){
response.setContentType("application/pdf");
}else{
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition"," attachment; filename=\"" + strFileNameReturn +"\""); //←★
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[10000];
while(true){
int length = is.read(buffer);
if(length==-1){
break;
}
baos.write(buffer,0,length);
}
baos.writeTo(output);
output.flush();
}
}
MimeUtilityはJavaMailのmail.jarに入っています。import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;
import java.io.*;
import java.sql.*;
import org.apache.commons.codec.binary.Base64;
import java.net.URLEncoder;
import javax.mail.internet.MimeUtility;
public class FileDownload extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException{
String strId = request.getParameter("id");
String strConn = "jdbc:mysql://localhost/test"
+"?user=Mulder&password=TrustNo1"
+"&useUnicode=true&characterEncoding=utf-8";
Blob data = null;
InputStream is = null;
String strFileName = null;
try{
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection(strConn);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT file_name,data FROM blob_test WHERE id = " + strId);
if(rs.next()){
data = rs.getBlob("data");
strFileName = rs.getString("file_name");
}else{
throw new IllegalArgumentException("ファイルがありません");
}
is = data.getBinaryStream();
conn.close();
}catch(SQLException e){
throw new ServletException(e.getMessage());
}catch(ClassNotFoundException e){
throw new ServletException(e.getMessage());
}
String strFileNameReturn = null;
//↓★
if(request.getHeader("User-Agent").indexOf("MSIE") != -1){
strFileNameReturn = URLEncoder.encode(strFileName,"utf-8");
}else{
strFileNameReturn = MimeUtility.encodeWord(strFileName, "ISO-2022-JP", "B");
}
ServletOutputStream output = response.getOutputStream();
if(strFileName.endsWith(".jpg")){
response.setContentType("image/jpg");
}else if(strFileName.endsWith(".gif")){
response.setContentType("image/gif");
}else if(strFileName.endsWith(".png")){
response.setContentType("image/png");
}else if(strFileName.endsWith(".pdf")){
response.setContentType("application/pdf");
}else{
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition"," attachment; filename=\"" + strFileNameReturn +"\""); //←★
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[10000];
while(true){
int length = is.read(buffer);
if(length==-1){
break;
}
baos.write(buffer,0,length);
}
baos.writeTo(output);
output.flush();
}
}
投稿:竹形 誠司[takegata]/2009年 02月 22日 16時 05分
/更新:2009年 02月 22日 16時 05分
竹形様
いろいろとご指導ありがとうございます。
日本語ファイル名がアップロード、ダウンロードできました。
ただ、ファイル名が全角文字で19文字以上になるとなぜが、文字化けします。もし何か対策がありましたら教えてください。よろしくおねがいします。
いろいろとご指導ありがとうございます。
日本語ファイル名がアップロード、ダウンロードできました。
ただ、ファイル名が全角文字で19文字以上になるとなぜが、文字化けします。もし何か対策がありましたら教えてください。よろしくおねがいします。
投稿:スワジランド[swajiland]/2009年 02月 22日 21時 24分
/更新:2009年 02月 22日 21時 24分
IEでダウンロードする際に長い日本語ファイル名が化けてしまうのは、仕方ないみたいですねぇ。URLエンコードせずにShift_JISでファイル名を送ることもできるようですが、その場合は特定の文字が化けるという現象が起こるようです。IEがRFCに合わせてくれればいいんですけどねぇ。
また、IE6とIE7でも挙動が異なるらしく、今の所は対処方法に決定版が無いような感じです。次善の策として、アップロード時にファイル名の文字数を制限するようなコードを入れてみるのはどうでしょうか。
参考:
http://www.agile-tech.com/blogs/dev/2007/12/contentdisposition.html
http://support.microsoft.com/kb/436616/ja
http://moodle.org/mod/forum/discuss.php?d=72567
また、IE6とIE7でも挙動が異なるらしく、今の所は対処方法に決定版が無いような感じです。次善の策として、アップロード時にファイル名の文字数を制限するようなコードを入れてみるのはどうでしょうか。
参考:
http://www.agile-tech.com/blogs/dev/2007/12/contentdisposition.html
http://support.microsoft.com/kb/436616/ja
http://moodle.org/mod/forum/discuss.php?d=72567
投稿:竹形 誠司[takegata]/2009年 02月 22日 23時 51分
/更新:2009年 02月 22日 23時 55分
竹形様
本当にいろいろとご指導くださいましてありがとうございました。
一冊の本に出会って、さらにその著者と対話できるというまさにIT技術のすごさをこの掲示板に見ることができました。
もうあまり若くはない私も、昔にプログラムを少しかじっていたころの興奮を覚えました。
自分の試してみたかったことが、2ヶ月でほぼ形になって見ることができました。そのためにかかった授業料は竹形様の御本以外にJAVA,MySQL,JSPサーブレット,Eclipseの4冊の本だけでした。オープンソース恐るべしです。
あとは、インターネットで無償提供されている多くの企業や優秀なプログラマの情報のおかげでした。これからもますます最先端でのご活躍期待しております。
私ももう少し何かチャレンジしてみたいと思います。
分からないことが出てきたら、またこちらを訪れさせていただきます。
どうもありがとうございました。
本当にいろいろとご指導くださいましてありがとうございました。
一冊の本に出会って、さらにその著者と対話できるというまさにIT技術のすごさをこの掲示板に見ることができました。
もうあまり若くはない私も、昔にプログラムを少しかじっていたころの興奮を覚えました。
自分の試してみたかったことが、2ヶ月でほぼ形になって見ることができました。そのためにかかった授業料は竹形様の御本以外にJAVA,MySQL,JSPサーブレット,Eclipseの4冊の本だけでした。オープンソース恐るべしです。
あとは、インターネットで無償提供されている多くの企業や優秀なプログラマの情報のおかげでした。これからもますます最先端でのご活躍期待しております。
私ももう少し何かチャレンジしてみたいと思います。
分からないことが出てきたら、またこちらを訪れさせていただきます。
どうもありがとうございました。
投稿:スワジランド[swajiland]/2009年 02月 24日 02時 29分
/更新:2009年 02月 24日 02時 30分
どういたしまして、当面の目標にだいぶ近付かれたようで何よりです。
以前はプログラマー35歳定年説などという話もあり、確かにCやC++などは年を取ってくるとなかなか厳しいものがありますが、デバッグの楽なJavaの登場でプログラマーの定年は大幅に延びたように思います。私も40代半ばですが、まだまだ行けそうな感じです。
今回いただいたご質問では、私もいろいろ勉強になりました。また何かありましたらよろしくお願いします。
以前はプログラマー35歳定年説などという話もあり、確かにCやC++などは年を取ってくるとなかなか厳しいものがありますが、デバッグの楽なJavaの登場でプログラマーの定年は大幅に延びたように思います。私も40代半ばですが、まだまだ行けそうな感じです。
今回いただいたご質問では、私もいろいろ勉強になりました。また何かありましたらよろしくお願いします。
投稿:竹形 誠司[takegata]/2009年 02月 24日 04時 36分
/更新:2009年 02月 24日 04時 39分
DAOの方式で同じ事をしようとしています。
pstmt.setBlob(3,stream);
となっている箇所のDAOでの扱いが分かりません。
StreamとBlobの変換が、上記の方式なら一気に
変換できるようですが、DAOでは適切な方法が
みつかりません。
もし分かるようでしたら教えて下さい。
pstmt.setBlob(3,stream);
となっている箇所のDAOでの扱いが分かりません。
StreamとBlobの変換が、上記の方式なら一気に
変換できるようですが、DAOでは適切な方法が
みつかりません。
もし分かるようでしたら教えて下さい。
投稿:ara[ikegi]/2011年 08月 11日 00時 21分
/更新:2011年 08月 11日 00時 22分
竹形です、どうも。
ちょっと漠然とした話で論点がよく分からないのですが、
具体的なコードなどを示していただけますか?
ちょっと漠然とした話で論点がよく分からないのですが、
具体的なコードなどを示していただけますか?
投稿:竹形 誠司[takegata]/2011年 08月 11日 09時 27分
/更新:2011年 08月 11日 09時 27分
しばらく連絡できない状況でした。質問しておきながら済みません。
下記のZuに当たるところが、Mysqlでは、Blobです。
Streamで入ってくるファイルの実態をとのやり取りが、
うまくいきません。Stream から Blobに
pstmt.setBlob(3,stream);
を使われていますが、DOAではどうすれば良いのかと
いうことです。下記のサンプルのようにやると、
型が違うよとエラーになってしまいます。
public class Sample {
private String uname;
private Blob zu;
public Sample(String uname , Blob zu ){
this.uname = uname;
this.zu = zu;
}
public Know_how_work(){
}
public String getUname() {return uname;}
public void setUname(String uname) {this.uname = uname;}
public Blob getZu() {return zu;}
public void setZu(Blob zu) {this.zu = zu;}
}
SampleDAO
public void create(Sample sch) {
Connection con = null;
con = createConnection();
String sql = "insert into sample values(?, ?)";
PreparedStatement stmt = con.prepareStatement(sql);
stmt.setString(1, sch.getUname());
stmt.setBlob(2, sch.getZu());
stmt.executeUpdate();
closeConnection(con);
}
処理ロジック
Sample sch = new Sample();
sch.setuname(uname_f);
sch.setZu(stream_f);
SampleDAO dao = new SampleDAO();
dao.create(sch);
下記のZuに当たるところが、Mysqlでは、Blobです。
Streamで入ってくるファイルの実態をとのやり取りが、
うまくいきません。Stream から Blobに
pstmt.setBlob(3,stream);
を使われていますが、DOAではどうすれば良いのかと
いうことです。下記のサンプルのようにやると、
型が違うよとエラーになってしまいます。
public class Sample {
private String uname;
private Blob zu;
public Sample(String uname , Blob zu ){
this.uname = uname;
this.zu = zu;
}
public Know_how_work(){
}
public String getUname() {return uname;}
public void setUname(String uname) {this.uname = uname;}
public Blob getZu() {return zu;}
public void setZu(Blob zu) {this.zu = zu;}
}
SampleDAO
public void create(Sample sch) {
Connection con = null;
con = createConnection();
String sql = "insert into sample values(?, ?)";
PreparedStatement stmt = con.prepareStatement(sql);
stmt.setString(1, sch.getUname());
stmt.setBlob(2, sch.getZu());
stmt.executeUpdate();
closeConnection(con);
}
処理ロジック
Sample sch = new Sample();
sch.setuname(uname_f);
sch.setZu(stream_f);
SampleDAO dao = new SampleDAO();
dao.create(sch);
投稿:ara[ikegi]/2011年 08月 22日 13時 35分