博文背景:
客戶要求結構化圖片信息,而不是文件文檔話的管理,故要求將圖片信息存儲於DB2里,出於技術的角度,真不喜歡將文件存儲於數據庫,
但客戶是上帝,木有辦法,故有了如下的測試。
測試環境:DB2 V9.7 JDK7 spring3.x tomcat8
本機測試結果:在第一次訪問的時候動態獲取的速度是直接獲取的1/20的樣子,如果緩存的話就無法對比了。
時間檢測使用了chrome和firfox的F12工具。
寫測試代碼的過程中參考了網上很多文章,發現大部分都是copy來copy去,估計都沒去測試過十分能行的通。
這里記錄一下測試過程中遇到的麻煩吧
1、DB2保存的時候數據庫是Blob類型,java里設置成byte[]才能正常保存(BinaryStream和Blob均失敗).
2、讀取DB2的Blob的時候不知道為何使用PreparedStatement讀取不出來,使用Statement才行。
3、IO的操作比較生疏了。
表結構:
1、保存圖片
上傳圖片的頁面:
<form action="bs/test/uploadImg.do" method="post" enctype="multipart/form-data" target="testFrame"> ID:<input type="text" name="id"/><br /> 名字:<input name="name" type="text"/><br /> 文件:<input type="file" name="img"/><br /> <input type="submit" value="提交"/> </form> <iframe src="" id="testFrame" name="testFrame" height="0" width="0" frameborder="0"></iframe>
后台action示例:
import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.util.List; import java.util.Map; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import com.oreilly.servlet.multipart.FilePart; import com.oreilly.servlet.multipart.MultipartParser; import com.oreilly.servlet.multipart.ParamPart; import com.oreilly.servlet.multipart.Part; @Urls("uploadImg.do") @Ajax public void saveFile(HttpServletRequest request){ int fileSize = 10; try { MultipartParser mp = new MultipartParser (request, fileSize * 1024 * 1024 ); Part part; int fileCount = 0; byte[] bt = null; String name = null; String fileName = null; String id = "999"; //遍歷請求中的所有表單 while((part=mp.readNextPart())!=null){ if(part.isFile()){//是文件 FilePart fp = (FilePart)part; fileName = fp.getFileName(); if (fileName.endsWith("png") || fileName.endsWith("gif") || fileName.endsWith("jpg") || fileName.endsWith("jpeg")) { //輸出流的目的是將輸入流轉成byte數組 ByteArrayOutputStream out = new ByteArrayOutputStream(); InputStream in = fp.getInputStream(); int size = 0; byte[] buffer = new byte[1024]; while((size=in.read(buffer))!=-1){ out.write(buffer, 0, size); } bt = out.toByteArray(); fileCount++; }else { throw new Exception("文件不是圖片!"); } }else{ ParamPart pp = (ParamPart)part; String inputName = pp.getName(); if("name".equals(inputName)){ name = pp.getStringValue(); }else if("id".equals(inputName)){ id = pp.getStringValue(); } } } if(fileCount==0){ throw new Exception("請選擇圖片后再上傳!"); } this.testDao.saveFile(fileName, bt, name,Integer.parseInt(id)); } catch (Exception e) { e.printStackTrace(); } }
dao方法:
public void saveFile(final String fileName,final byte[] bt,final String name,final int id) throws SQLException{ String sql = "insert into SDE.T_TEST_IMG(ID,FILE_NAME,IMG_FILE,NAME) VALUES(?,?,?,?)"; this.getJdbcTemplate().update(sql, new PreparedStatementSetter() { public void setValues(PreparedStatement ps) throws SQLException { ps.setInt(1, id); ps.setString(2, fileName); //下面這2種都會報錯,網上一大堆例子都是這么寫的,很詫異.............. //ps.setBinaryStream(3, fis, fileSize); //ps.setBlob(3, fis); ps.setBytes(3, bt); ps.setString(4, name); } }); }
2、讀取圖片
前台:
<input type="button" onclick="setUrl()" value="加載圖片"/> <img src="" alt="動態生成" id="dImg"/> <img src="" alt="直接獲取" id="sImg"/>
js:
function setUrl(){ //動態生成同樣的圖片 document.getElementById("dImg").src="generationImg?id=3"; //直接訪問圖片 document.getElementById("sImg").src="mobileImage/17074_20130927160025.jpg"; }
處理生成圖片的servlet:
/** * 從數據庫里讀取Blob類型的圖片並顯示給前台 */ public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String id = request.getParameter("id"); response.setContentType("image/jpeg"); TestDao testDao = (TestDao)WebApplicationContextUtils.getWebApplicationContext(request.getSession().getServletContext()).getBean(TestDao.class); InputStream ins = null; try { ins = testDao.loadFile(id); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } //從輸入流構建圖片 BufferedImage image = null; image = ImageIO.read(ins); ServletOutputStream out = response.getOutputStream(); JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out); encoder.encode(image); ins.close(); out.flush(); out.close(); }
dao方法:
/** * 讀取DB2的blob字段並轉換成流 * @param id * @return * @throws SQLException */ public InputStream loadFile(String id) throws SQLException{ String sql = "select IMG_FILE from SDE.T_TEST_IMG where ID="+id; InputStream ins = null; Connection con = this.getJdbcTemplate().getDataSource().getConnection(); Statement ps = con.createStatement(); ResultSet rs = ps.executeQuery(sql); while(rs.next()){ Blob blob = rs.getBlob("IMG_FILE"); ins = blob.getBinaryStream(); } return ins; //下面這個寫法會有問題,而且上面那個Statement改成PrepareStatement后也獲取不到值,ResultSet是null /* InputStream ins = this.getJdbcTemplate().execute(sql, new PreparedStatementCallback() { public Object doInPreparedStatement(PreparedStatement ps) throws SQLException, DataAccessException { ResultSet rs = ps.getResultSet(); Blob blob = rs.getBlob(1); InputStream ins = blob.getBinaryStream(); return ins; } }); return ins;*/ }