2011年8月1日星期一

ADF_097:如何处理BLOB类型数据之三:使用Servlet在页面上显示BLOB中的图片

实验环境:JDeveloper 11.1.2.0.0。
接上一个实验《如何处理BLOB类型数据之二:下载BLOB内容并保存到文件中》。

我的设计思想:
这其实是一个动态显示图片的问题,类似于很多网站上登录时要求输入的图片认证码。
一开始,根据前面的思路,我打算继续使用ADF BC的来显示BLOB中的图片内容,后来发现这个功能相对来说比较独立,于是就想写一个通用的,这样没有ADF也可以使用。
于是,我参考了《一个读取BLOB中图片的Servlet代码》,写了一个Servlet。

1. 新建页面:get_image_from_blob.jspx
<af:image source="/blobimageservlet?id=75" id="i5"/>
我这里只是测试Servlet是否工作正常,因此参数id给的是常量75,因为我上传的id=75的文件是一个.jpg。
你可以根据你的需要,把参数动态设置。

2. 创建Servlet:BlobImageServlet.java
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.OutputStream;

import java.io.PrintWriter;

import java.sql.Blob;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

import java.sql.SQLException;

import javax.naming.Context;
import javax.naming.InitialContext;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import javax.sql.DataSource;

public class BlobImageServlet extends HttpServlet {
private static final String CONTENT_TYPE = "image/jpg; charset=utf-8";

public void init(ServletConfig config) throws ServletException {
super.init(config);
}

public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType(CONTENT_TYPE);
String idStr = request.getParameter("id");
int id = -1;
if (idStr != null) {
id = Integer.parseInt(idStr);
}

OutputStream os = response.getOutputStream();
Connection conn = null;

try {
Context ctx = new InitialContext();
DataSource ds = (DataSource)ctx.lookup("java:comp/env/jdbc/uploadFileToBlobConnDS");
conn = ds.getConnection();
PreparedStatement statement =
conn.prepareStatement("SELECT UploadedFiles.ID," +
" UploadedFiles.FILENAME, " +
" UploadedFiles.CONTENT " +
"FROM UPLOADED_FILES UploadedFiles " +
"WHERE UploadedFiles.ID = ?");

statement.setInt(1, new Integer(id));
ResultSet rs = statement.executeQuery();
if (rs.next()) {
Blob blob = rs.getBlob("Content");
BufferedInputStream in = new BufferedInputStream(blob.getBinaryStream());
int b;
byte[] buffer = new byte[10240];
while ((b = in.read(buffer, 0, 10240)) != -1) {
os.write(buffer, 0, b);
}
os.close();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (conn != null) {
conn.close();
}
} catch (SQLException sqle) {
System.out.println("SQLException error");
}
}
}
}

3. 运行,访问get_image_from_blob.jspx,显示BLOB中的图片内容
唉,斯人已逝,永远怀念的邓丽君......


4. 深入分析
使用Servlet来显示BLOB中的图片内容,可能会引起性能问题。因为每一个BLOB图片显示,都要占用一个数据库连接。
可以考虑修改Serverlt的逻辑如下:
如果在某个路径下没有某个图片,那么,再去访问数据库,获取图片,并生成在该路径下。
否则,直接访问已经生成的图片文件。
其中,为了保证图片名称的唯一性,图片名称包含时间戳。

5. 问题:如果使用ADF BC该如何做?
我认为在某些情况下,使用ADF BC还是比较方便的,比如一个天气预报表格中,某一列用小图片来表示不同的天气情况。
因为省去了连接数据库的代码,不会有性能问题。
而且可以非常方便的获取BlobDomain对象:row.Content。如果支持如下写法就更好了:
<af:image source="#{row.Content}" id="i5"/>
可惜这样写,是无法显示出图片的。
可以在Managed Bean中写一个方法来处理BlobDomain,放到image的source属性中。
这个以后有空在写吧。

Project 下载:UploadFileToBlob_DownloadBlobToFile_getBlobImage.7z

参考文献:
1. http://kr.forums.oracle.com/forums/thread.jspa?threadID=614954。

没有评论: