始
在近期的項目開發中,第一次遇到了 BLOB 類型數據的讀取,但是的業務是這樣的,需要將數據庫中的某些信息(包含有 BLOB 類型的數據)讀取出來傳給前台,本來很簡單的一個業務,當時只以為是可以按照正常類型的數據進行處理,結果就掉進坑里了,首先遇到的是:
1 // pass:錯誤信息為便於查看進行了回車,真實情況是全在一行 2 Type definition error: 3 [simple type, class oracle.jdbc.OracleConnection]; 4 nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: 5 Direct self-reference leading to cycle (through reference chain: 6 java.util.ArrayList[1]->java.util.LinkedHashMap["data"]->java.util.ArrayList[0]->java.util.HashMap["ABC"]->com.sun.proxy.$Proxy117["wrappedBlob"]->oracle.sql.BLOB["dbaccess"]->oracle.jdbc.driver.T4CConnection["wrapper"])
意思很簡單,就是說我這個(java.util.HashMap["ABC"]
) ABC 這個數據類型定義錯誤,(com.sun.proxy.$Proxy117["wrappedBlob"]
) 從這里可以看出來 ABC 它是代理類型的 BLOB 數據(這么說不知道嚴禁不嚴謹),那既然這樣,我們需要把 ABC 這個數據進行格式轉化后再進行保存到數據集合中,說干就干,考慮后選擇把BLOB數據轉換成BASE64類型的(base64百度百科),在轉換時直接使用了Base64.encode()
方法,結果發現又出現問題了,報了個如下的問題:
1 oracle.sql.BLOB cannot be cast to oracle.sql.BLOB
嗯,很無奈、很奇怪,但是沒法啊,只能繼續在網上找資料,最終找到了問題所在,問題解釋如下:
我們接收到的這個數據實例是個包裹着 java.sql.Blob 外殼的 Proxy 類型的實例。因此,當我們想操作這個 Blob 數據時就需要針對這個被包裝的 Blob 進行去殼,核心代碼如下:
1 SerializableBlobProxy proxy = (SerializableBlobProxy )Proxy.getInvocationHandler(blob); 2 java.sql.Blob realBlob = proxy.getWrappedBlob();
資料出處:隔壁老王
現在弄明白了問題的原因,也找到了相應的解決辦法,那就開始繼續往下處理吧。
破
經過開始的摸索,排除了各種問題,那接下來就開始整理思路編寫代碼了;
思路如下:
- 去殼,將 BLOB 數據的真正數據取出來;
- 轉流,將去殼后的數據轉換成 ’ byte[] ’ 的形式(為下一步做准備);
- 使用 BASE64 的數據轉換方法進行數據轉換;
現在思路通了,開始敲代碼:
BlobAndBase64Util.java
1 package ***.***.***.***.***.util; 2 3 import java.io.ByteArrayOutputStream; 4 import java.io.IOException; 5 import java.io.InputStream; 6 import java.lang.reflect.Proxy; 7 import java.sql.Blob; 8 import java.sql.SQLException; 9 10 import org.hibernate.engine.jdbc.SerializableBlobProxy; 11 12 import com.primeton.xfire.util.Base64; 13 14 /** 15 * @descript BLOB/BASE64相互轉化工具類 16 * @author *** 17 * 18 */ 19 public class BlobAndBase64Util { 20 21 Blob blob; 22 23 // BLOB 轉 BASE64 24 /* 25 * @Description :將BLOB類型數據轉化成BASE64類型 26 * @param : blobDate ———— blob類型的數據,直接扔進去就好 27 */ 28 public static String getBase64InBlob(Object blobDate) { 29 String result = new String(); 30 try { 31 // 獲取代理實例的調用處理程序 32 SerializableBlobProxy proxy = (SerializableBlobProxy) Proxy.getInvocationHandler(blobDate); 33 // 獲取被代理對象的BLOB數據對象 34 Blob realBlob = proxy.getWrappedBlob(); 35 // 創建byte數組輸出對象 36 ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); 37 // 創建一個長度為100的byte數組 38 byte[] buff = new byte[100]; 39 int rc = 0; 40 // 獲取BLOB數據對象的二進制流 41 InputStream binaryStream = realBlob.getBinaryStream(); 42 while ((rc = binaryStream.read(buff, 0, 100)) > 0) { 43 byteArrayOutputStream.write(buff, 0, rc); 44 } 45 byte[] byteArray = byteArrayOutputStream.toByteArray(); 46 result = Base64.encode(byteArray); 47 } catch (IOException e) { 48 e.printStackTrace(); 49 } catch (SQLException e) { 50 e.printStackTrace(); 51 } 52 return result; 53 } 54 55 // BLOB 轉 BASE64 56 // public static String getBlobInBase64(Object blobDate) { 57 // 58 // return null; 59 // } 60 }
經測試后以正確轉化成 String 類型的數據;
終
總結:
- 遇到問題多查看報錯日志信息,只有報錯信息看明白了才能對症下葯,否則事倍功半;
- 多細心嘗試;