將一個(gè)字符串存入數(shù)據(jù)庫并顯示出來是一項(xiàng)簡(jiǎn)單任務(wù),當(dāng)字符串長(zhǎng)度較短(新聞級(jí)別)時(shí)確實(shí)如此.
然而量變引起質(zhì)變,當(dāng)字符串長(zhǎng)度增加到一定程度(小說級(jí)別)時(shí),原有的對(duì)簡(jiǎn)短字符串的處理流程就需要做出一些變化了.下文將討論這些變化的細(xì)節(jié).
一.Web系統(tǒng)的基本情況以下是某Web系統(tǒng)的基本情況:
前臺(tái)JS框架:
jQuery1.7.2 它確實(shí)貼心,比Dojo強(qiáng),write less do more真不是空話
前后臺(tái)信息傳遞方式:全部為
Ajax異步處理 拒絕form提交
控制器:
Spring3 MVC 很好 SpringMVC終將動(dòng)搖Struts1/2的低位
Mapping:
Hibernate3.2(C),SpringDAO(RUD)
后臺(tái)DB:
MySql5.2 它確實(shí)小巧方便,如果Oracle DB2跑在我的T410上那就開不了別的程序了
二.長(zhǎng)文本向后臺(tái)的傳遞Web前臺(tái)向后臺(tái)傳遞數(shù)據(jù)的方式有g(shù)et和post兩種,它們之間有一些差別.就本文涉及的場(chǎng)景來說,差別主要在數(shù)據(jù)量的大小上,GET方式對(duì)傳輸?shù)臄?shù)據(jù)有大小限制,通常不能大于2KB;而使用POST方式傳遞的數(shù)據(jù)量比GET方式大得多,理論上不受限制.因此我采用了POST方式.
傳遞代碼如下:
var url='wisdom/add.do';
$.post(
url,
{title:encodeURIComponent($(
"#title").val()),concept:encodeURIComponent(
$("#concept").val())},
function(data,textStatus){
var status=$(data).find("status").text();
if(status=="ok"){
...
}
else{
var text=$(data).find("text").text();
alert(text);
}
}
); 以上代碼中,concept就是在textarea中的長(zhǎng)文本,理論上長(zhǎng)度是無限的,但實(shí)際應(yīng)用中會(huì)受到數(shù)據(jù)庫字段的限制.
三.服務(wù)器的設(shè)置POST提交有長(zhǎng)度限制,當(dāng)超過時(shí)將會(huì)出錯(cuò),可以配置
maxPostSize參數(shù)來改變大小。<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" maxPostSize="0"/>
當(dāng)設(shè)置為零時(shí),就沒有長(zhǎng)度限制了.
四.長(zhǎng)文本在DB中的存儲(chǔ)首先需要考慮的數(shù)據(jù)庫的字段,一般的varchar肯定是不夠了;clob/blob容量是夠,但查詢時(shí)需要取出來轉(zhuǎn)化一下,而這樣速度上就受限了;一向比較貼心的MySql提供了一個(gè)LONGTEXT類型,它可以容納4294967295byte的文字,而在使用上又如同文本一樣,這成了我的首選,在后來的實(shí)際測(cè)試中,我發(fā)現(xiàn)它存儲(chǔ)80萬個(gè)漢字是沒有問題的,100萬也行,這就已經(jīng)滿足我的需求了,因此更大的測(cè)試沒有再進(jìn)行.
這個(gè)Web系統(tǒng)CRUD處理中,C是通過Hinernate完成的,因此在hbm.xml中進(jìn)行設(shè)置就好了.
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.ibm.heyang.domain">
<class name="Wisdom" table="collections_wisdom">
<id name="id" column="ID" >
<generator class="increment"/>
</id>
<property name="title" column="title" not-null="true"/>
<property name="concept" type="text">
<column name="concept" not-null="true" length = "16777216" />
</property>
<property name="conceptLength" column="conceptLength" />
<property name="addUserId" column="addUserId" />
<property name="modifyTime" column="modifyTime"/>
</class>
</hibernate-mapping>
以上粗體部分就是大文本字段的設(shè)置細(xì)節(jié).
由于Hibernate是采用PreparedStatement,因此concept不需要進(jìn)行轉(zhuǎn)義和其它特殊處理.這給檢索也帶來了不少方便.
五.長(zhǎng)文本的檢索由于插入數(shù)據(jù)庫的文本就是原文,所以檢索就是常規(guī)的檢索,無須贅述.
六.長(zhǎng)文本向前臺(tái)的傳遞前的包裝在這個(gè)Web系統(tǒng)中,后臺(tái)向前臺(tái)傳遞的數(shù)據(jù)是以XML的型式往回傳的,前臺(tái)JS得到后再解析出來.
但長(zhǎng)文本有一個(gè)特殊的地方就是內(nèi)容無限制,比如違反XML規(guī)則的字符如<>等,這里就需要把它放在CDATA塊里包起來后再向前傳遞.
如下:
StringBuilder sb=new StringBuilder();
sb.append("<title><![CDATA[");
sb.append(StringUtils.isBlank(title)?"-":title);
sb.append("]]></title>");
sb.append("<concept><![CDATA[");
sb.append(concept);
sb.append("]]></concept>");
如果不這樣處理一下,前臺(tái)js就可能解析XML出錯(cuò).
七.長(zhǎng)文本的顯示將長(zhǎng)文本顯示給用戶看可以采用textarea顯示和網(wǎng)頁顯示,如果是前者那就沒有特殊處理,直接放進(jìn)去就行了,文本格式和存儲(chǔ)前會(huì)一樣,只是用戶看起來不方便,需要用滾動(dòng)條拖來拖去;而網(wǎng)頁方式就好多了,用戶舒適度好很多,但要求我們進(jìn)行一些特殊的處理.
首先是CSS設(shè)置,這是為了保證文本不把DIV撐開,設(shè)置如下:
#concept{
width:900px;
max-width:900px;
min-width:900px;
display:inline-block;
padding-top:10px;
color:#7a7a7a;
font-size:14px;
font-weight:normal;
text-align:left;
word-wrap: break-word;
word-break: normal;
-moz-binding: url('./wordwrap.xml#wordwrap');/*FF only*/
word-break:break-all;
white-space: moz-pre-wrap;
}
其次,需要對(duì)文本處理一下,這樣做的目的是把<>轉(zhuǎn)義,另外把\n轉(zhuǎn)化成<br>,空格轉(zhuǎn)化成 等,如果不這樣做,文字會(huì)亂,閱讀起來很覺不便.
以下是轉(zhuǎn)化函數(shù):
function makeText2Html(originalText){
originalText=originalText.replace("<","<");
originalText=originalText.replace(">",">");
originalText=originalText.replace(/\n/g,"<br/>");
originalText=originalText.replace(/\t/g," ");
originalText=originalText.replace(" "," ");
return originalText;
}
以下是把XML中的長(zhǎng)文本放到頁面中:
$("#concept").html(getFormatedText($(data).find("concept").text()));
如果IE ONly的話,也可以把文本用<pre>標(biāo)簽包起來,這樣就不用makeText2Html的輔助了.
以上就是對(duì)長(zhǎng)文本的存儲(chǔ)和顯示的一些處理,由于作者水平有限,上文只是我的孔見,不當(dāng)之處還請(qǐng)指出.