主题:使用JAVA读取ORACLE BLOB字段实现上传下载
作者:蔡毅()
时间:2005-6-22
一 BLOB概述
大对象类型BLOB全称为Binary Large Objects,即二进制大对象。可以把BLOB区别为三种形式:声像数据、二进制数据和大文本数据。因此,最常见的应用就是存储图形、声音等对象,此外大二进制对象、OLE对象也可以通过BLOB类型存入数据库,如果文本对象过大,超出了文本类型的规定长度,则必须用BLOB字段进行存储。我们在经常使用的编程环境中并不能直接支持BLOB字段,因此需要调用相应的函数完成BLOB的使用。
二 实际Struts项目的处理流程
1 插入BLOB字段的流程
表示层:
雷军演讲上传使用struts的<html:file property="drawingFile"/>标签,提交给指定处理的Action,在ActionForm中使用struts自带的FormFile
来保存文件。
核心代码:
<html:form action="/DrawingInputMultiAction" enctype="multipart/form-data">
<html:file property="drawingFile"/>
....省略
</html:form>
控制层:
在Action中将传入的ActionForm中的文件字段赋给VO值对象,并调用业务代理类的上传方法。
核心代码:
//新增
if(actionType.equals("inrt")) {
//得到文件类型
int iFileType = FileExtendName());
if(iFileType == 0) {
//不支持文件类型
this.addError(request, "s.upload.UnSupportedFileType");
} el {
DrawingVO objDrawingVO = new DrawingVO();
奔溃的意思//图纸基本属性
objDrawingVO.DrawingName());
...省略其他t方法
/
/执行新增(上传)
int iRt = objDrawingMan.inrtDrawing(objDrawingVO);
...省略
}
Facade门面:
通过业务代理类调用DAO中的上传方法,对客户端完全透明。调和气血
public int inrtDrawing(DrawingVO drawingVO) throws ComtopModuleException {
try {
DrawingDAO drawingDAO = new DrawingDAO();
return drawingDAO.inrtDrawing(drawingVO);
} catch(DrawingException ex) {
throw new ComtopModuleException("s.inrt", ex);
}
}
持久层:
DAO中实现和ORACLE数据库的底层交涉,完成真正的文件上传。
需要先插入一个空BLOB对象,然后Update这个空对象。
public int inrtDrawing(DrawingVO drawingVO) throws DrawingException {
PreparedStatement pstmt = null;
Statement stmt = null;
Connection conn = null;
int iKey = 0;
ResultSet rs = null;
//定义SQL语句
String strSQLInrt = null;
String strSQLUpdate = null;
try {
conn = Connection();
conn.tAutoCommit(fal);
//插入空BLOB,empty_blob(),其中表中的Content是BLOC类型字段
strSQLInrt =
"inrt into PROD_DRAWING (DRAWING_ID, DRAWING_NAME, 省略..." +
"CONTENT)" +
"values (?, ?, 省略..., empty_blob())";
//得到待处理文件
FormFile drawingFile = DrawingFile();
//插入普通字段
pstmt = conn.prepareStatement(strSQLInrt);
//得到主键
iKey = Instance().getNextKey(DrawingInfo.ID_STORE_KEY_DRAWING);
pstmt.tInt(1, iKey);
....省略其他t方法
stmt = ateStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_UPDATABLE);
strSQLUpdate =
"SELECT CONTENT FROM PROD_DRAWING WHERE DRAWING_ID ='" +
灰心丧气的反义词
iKey + "'" + " FOR UPDATE";
//读出记录以增加图片Blob字段
rs = uteQuery(strSQLUpdate);
()) {
logger.debug("开始写入BLOB");
受受一家亲
摄影的好处//这里不能用oracle.sql.BLOB,会报ClassCast异常
weblogic.acle.OracleThinBlob blob = (weblogic.jdbc.vendor.社会调研
oracle.
Blob(1);
logger.debug("得到输出流");
OutputStream outStream = BinaryOutputStream();
InputStream fin = InputStream();
logger.debug("开始分配缓存");
byte[] b = new BufferSize()];
int len = 0;
while((len = ad(b)) != -1) {
logger.debug("正在写入BLOB流");
outStream.write(b, 0, len);
}
logger.debug("关闭所有流");
fin.clo();
outStream.flush();
outStream.clo();
}
rs.clo();
} catch(Exception ex) {
...省略
}finally {
DBUtil.destroyDB(rs, pstmt, conn);
}
return iKey;
}
2 读取BLOB字段的流程
从数据库中读出BLOB数据没有上述由于连接池的不同带来的差异,程序流程同插入BLOB字段,但是读BLOB就不用那么复杂了,只需要J2SE的标准类java.sql.Blob就可以取得输出流。
DAO中的核心代码:
public DrawingVO readDrawing(int drawingId) throws DrawingException {
PreparedStatement pstmt = null;
Connection conn = null;
DrawingVO objDrawingVO = null;
ResultSet rs = null;
//定义SQL语句
String strSQL = "SELECT * FROM PROD_DRAWING WHERE DRAWING_ID=?";
try {
conn = C营销活动方案
onnection();
pstmt = conn.prepareStatement(strSQL);
//设置参数
pstmt.tInt(1, drawingId);
//执行查询
rs = uteQuery();
()) {
objDrawingVO = new DrawingVO();
objDrawingVO.Int("DRAWING_ID"));
objDrawingVO.String("DRAWING_NAME"));
...省略其他t方法
//t BLOB到VO中
objDrawingVO.Blob("CONTENT"));
}
} catch(Exception ex) {
...省略
}finally {
DBUtil.destroyDB(rs, pstmt, conn);
}
return objDrawingVO;
}
这样,传到Action中VO对象就包含这个BLOB对象了,然后需要在Action中对该对象转为输入流,可以选择文件输出流或Servlet输出流,根据具体情况定,这里选择文件输出流。
核心代码:
private String getBlobToFile(Blob blob, DrawingVO objDrawingVO) throws Exception {
InputStream ins = BinaryStream();
//用文件模拟输出流
String strFileName = DrawingName() + "." +
String strRootFilePath = Servlet().getServletContext().getRealPath("");
String strFilePath = "/temp/" + strFileName;
String contextFilePath = strRootFilePath + strFilePath;
//定义文件对象
File file = new Servlet().getServletContext().getRealPath("") + "/temp");
if(!ists()) {
file.mkdir();
}
//定义输出流
OutputStream fout = new FileOutputStream(contextFilePath, true);
//下面将BLOB数据写入文件
byte[] b = new byte[1024];
int len = 0;
while((len = ad(b)) != -1) {
fout.write(b, 0, len);
}
//依次关闭
fout.clo();
ins.clo();
return strFilePath;
}
最后,在Action中调用这个私有方法,完成读取操作。