項目開發(fā)馬上就要用到文件的上傳、下載、照片的顯示等功能,可是手頭還是沒有現(xiàn)成的解決方案,心一橫,就決定今天要搞定它。
分兩步走的:
1,先把文件拿到webwork的action里面。
這個我想了許多辦法,多半是因為自己無知吧,先是給文件的屬性設(shè)置為byte[],頁面上則是<input type="file" name="report.data">,這樣提交到action里面時,通過request死活拿不到文件數(shù)據(jù),傷心了一會,上網(wǎng)google,終于找到一段有價值的文字,可能是robbin的原話, 在action里面定義一個 java.io.File類型的變量,名字對應(yīng)你的頁面中的HTML標記<input type="file" name="XXX" />,這樣在Action中就可以直接通過這個File對象進行文件內(nèi)容的讀取了,這可以用webwork自帶的FileUploadInterceptor來實現(xiàn),要注意的是需要在action中配置一下,而且fileUpload攔截器要放在parameter攔截器前面。嗯,喜滋滋的配之。大問題來了!!uploadManager業(yè)務(wù)類總是不能實例化,一點提交按鈕,就會毫不猶豫的拋出一個nullPointException出來,更傷心了,檢查了約有2-3個小時,eclipse重啟n遍,脾氣也火爆起來了……最后,在同事的提醒下,很不好意思的發(fā)現(xiàn),在配置了FileUploadInterceptor和parameter攔截器之后,以前action共用的自動裝配攔截器就給屏蔽了,這樣spring就不會幫我把uploadManager給實例化……暈倒,加上autowire攔截器之后,ok,文件數(shù)據(jù)順利到達action。
<action name="submitReport"
class="com.hisign.webapp.action.common.TestReportAction" method="submit">
<result name="success" type="redirect">
/pages/intoReport.action
</result>
<interceptor-ref name="fileUpload"></interceptor-ref>
<interceptor-ref name="params"></interceptor-ref>
<interceptor-ref name="autowireDefault"></interceptor-ref>
</action>
2,然后就要想辦法把文件送到數(shù)據(jù)庫了。
這里我先是參考http://opensource.atlassian.com/confluence/oss/display/IBATIS/How+do+I+use+a+Custom+Type+Handler+with+a+BLOB+or+CLOB%3F這里提供的方法試了一下,發(fā)現(xiàn)上傳的文件大小果然有限制,最大為4k!!My god!趕緊放棄了……看來pojo里文件的屬性不能設(shè)置為byte[]了……還是改oracle.sql.BLOB吧……
這樣就出現(xiàn)了oracle.sql.BLOB+ibatis如何實現(xiàn)大文件存取的問題。我的POJO為
/** /**
* 取得主鍵
* @return Returns the id.
*/
public String getId() {
return id;
}
/**
* 設(shè)置主鍵
* @param id The id to set.
*/
public void setId(String id) {
this.id = id;
}
/**
* 二進制文件數(shù)據(jù)
*/
private BLOB data;
/**
* 獲得二進制文件數(shù)據(jù)
* @return
*/
public BLOB getData() {
return this.data;
}
/**
* 設(shè)置二進制文件數(shù)據(jù)
* @param data
*/
public void setData(BLOB data) {
this.data = data;
}
先是參考http://blog.csdn.net/rosen/archive/2005/02/18/293151.aspx里提到的方法。對應(yīng)的sql-map寫成了
<resultMap class="Report" id="ReportResult">
<result column="id" property="id" />
<result column="name" property="name" />
<result column="data" property="data" typeHandler="com.ibatis.sqlmap.engine.type.BlobTypeHandlerCallback"/>
</resultMap>
<select id="findReportById" parameterClass="string" resultMap="ReportResult">
SELECT * FROM TEST_REPORT
WHERE id = #value#
FOR UPDATE
</select>
<insert id="insertReportWithEmptyData" parameterClass="Report">
INSERT INTO
TEST_REPORT (
id, name,data)
values (
#id#,#name#, empty_blob())
</insert>
按照oracle的習慣,存取一個比較大的二進制文件到數(shù)據(jù)庫的blob字段中,必須先送進去一個empty_blob(),然后再馬上讀出來,同時鎖住該記錄,得到blob字段的二進制輸出流,用文件的輸入流往里寫數(shù)據(jù),即可。上面的SQL正好也是符合那個操作流程,其中插入數(shù)據(jù)庫的業(yè)務(wù)方法主要代碼如下:
dao.getSqlMapClientTemplate().insert("insertReportWithEmptyData", report);
report = (TestReport) dao.getSqlMapClientTemplate().queryForObject("findReportById",id);
BLOB blob = report.getData();
OutputStream out = blob.getBinaryOutputStream();
byte[] b = new byte[ blob.getBufferSize()];
InputStream fin = new FileInputStream(file);
int len = 0;
byte[] data = new byte[(int)fin.available()];
fin.read(data);
out.write(data);
fin.close();
out.close();
因此以為大功即將告成,一運行馬上報錯,說是類型轉(zhuǎn)換出錯,就在從數(shù)據(jù)庫中把數(shù)據(jù)讀出來的時候出錯的,因此問題很可能出在那個typeHandler上,找來源文件一看,里面出來的數(shù)據(jù)類型為java.sql.Blob,有些擔心是不是因為java.sql.Blob不能自動轉(zhuǎn)換為oracle.sql.BLOB類型,于是自做主張又寫了一個typeHandler,OracleBLOBTypeHandlerCallBack類,在這個類里面,強行將java.sql.Blob轉(zhuǎn)換為oracle.sql.BLOB,還是不成功,55555,這時候晚上都8點多了,晚飯還沒吃,郁悶死了。
偏偏此時在google上又發(fā)現(xiàn)了一些關(guān)于ibatis操作blob字段的悲觀看法,心理也是悲觀了,就想直接去拿ibatis的java.sql.Connection來做算了,這樣的話,網(wǎng)上的例子到處都是……
可又不太甘心,于是順手無意把我的pojo中data的屬性設(shè)置為Object,去掉了typeHandler,是想我在外邊才對出來的二進制數(shù)據(jù)進行BLOB的強行轉(zhuǎn)換,死馬當活馬醫(yī)吧……
于是就好象楊過的黯然銷魂掌一般,點下了提交按鈕……………………
^_^,驚喜的是,系統(tǒng)沒有報出異常信息,一查數(shù)據(jù)庫,數(shù)據(jù)進去了,大于4k的?。。〗舆B又試了幾個文件,都ok,于是這一步順利完成。
3,緊接著使用webwork的stream-result順利實現(xiàn)了二進制文件在瀏覽器中的打開。
主要就是首先在action中得到二進制文件的輸入流:
this.inputStream =this.testReportManager.getReportDataById("8CF3C311952BB91D16316E37B43659C1");
然后在xwork中作如下配置:
<result name="view" type="stream">
<param name="filename">${fileName}</param>
<param name="contentDisposition">filename=${fileName}</param>
</result>
于是大功告成,既可以顯示圖片,也可以實現(xiàn)文件下載,呵呵呵
- 作者: mingo 2005年07月16日, 星期六 23:36
你可以使用這個鏈接引用該篇日志 http://publishblog.blogdriver.com/blog/tb.b?diaryID=820453
你好,我現(xiàn)在也在學習webwork+spring+ibatis,能不能給發(fā)個例子呀,真羨慕你呀,我即將可能再在開發(fā)中面臨和你遇到的一樣的問題,請高手多關(guān)照
整個過程應(yīng)該沒有問題,因為事務(wù)的控制都是由Spring來控制的。在spring配置文件中有下面的事務(wù)控制配置:
〈property name="transactionAttributes"〉
〈props〉
〈prop key="insert*"〉PROPAGATION_REQUIRED,-AppBaseException〈/prop〉
〈prop key="update*"〉PROPAGATION_REQUIRED,-AppBaseException〈/prop〉
〈prop key="delete*"〉PROPAGATION_REQUIRED,-AppBaseException〈/prop〉
〈prop key="getNextId"〉PROPAGATION_REQUIRED〈/prop〉
〈prop key="*"〉PROPAGATION_REQUIRED,readOnly〈/prop〉
〈/props〉
〈/property〉
你的IBATIS用法,會不會有問題,因為對ORACLE的大對象操作,在UPDATE之前是要有COMMIT(FALSE)的,你整個過程都沒有提交。在你 dao.getSqlMapClientTemplate().insert("insertReportWithEmptyData", report);
和后面的語句是一個事務(wù)中么,我只是有些懷疑,如果一切正常,我會嘗試用你的方法。
發(fā)現(xiàn)webwork的這個文件上傳攔截器的一個bug:
如果在xwork中配置了fileUpload的攔截器,那么沒有選擇文件就提交的話,會報空指針異常……然而我的form里還有別的數(shù)據(jù)要提交……想到webwork是開源的,喜之,改了一些webwork的源文件后重新編譯,放到j(luò)ar包里……可是問題又來了,改過之后即使選擇了要上傳的文件,后臺的action里也拿不到那個file了……郁悶
只好去拿文件的filepath,然后new 一個file(path);