始
在近期的项目开发中,第一次遇到了 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 类型的数据;
终
总结:
- 遇到问题多查看报错日志信息,只有报错信息看明白了才能对症下药,否则事倍功半;
- 多细心尝试;