十二、生成縮略圖
當用戶上傳了圖片後,必須生成縮略圖以便用戶能快速浏覽。我們不需借助第三方軟件,JDK標准庫就包含了圖像處理的API。我們把一張圖片按比例縮放到120X120大小,以下是關鍵代碼:
public static void createPrevIEwImage(String srcFile, String destFile) {
try {
File fi = new File(srcFile); // src
File fo = new File(destFile); // dest
BufferedImage bis = ImageIO.read(fi);
int w = bis.getWidth();
int h = bis.getHeight();
double scale = (double)w/h;
int nw = IMAGE_SIZE; // final int IMAGE_SIZE = 120;
int nh = (nw * h) / w;
if( nh>IMAGE_SIZE ) {
nh = IMAGE_SIZE;
nw = (nh * w) / h;
}
double sx = (double)nw / w;
double sy = (double)nh / h;
transform.setToScale(sx,sy);
AffineTransformOp ato = new AffineTransformOp(transform, null);
BufferedImage bid = new BufferedImage(nw, nh, BufferedImage.TYPE_3BYTE_BGR);
ato.filter(bis,bid);
ImageIO.write(bid, "jpeg", fo);
} catch(Exception e) {
e.printStackTrace();
throw new RuntimeException("Failed in create prevIEw image. Error: " + e.getMessage());
}
}
十三、實現RSS
RSS是一個標准的XML文件,Rss閱讀器可以讀取這個XML文件獲得文章的信息,使用戶可以通過Rss閱讀器而非浏覽器閱讀Blog,我們只要動態生成這個XML文件便可以了。RSSLibJ是一個專門讀取和生成RSS的小巧實用的Java庫,大小僅25k,可以從http://sourceforge.Net/projects/rsslibj/下載rsslibj-1_0RC2.jar和它需要的EXMLjar兩個文件,然後復制到web/WEB-INF/lib/下。
使用RSSLibJ異常簡單,我們先設置好HttpServletResponse的Header,然後通過RSSLibJ輸出XML即可:
Channel channel = new Channel();
channel.setDescription(account.getDescription());
baseUrl = baseUrl.substring(0, n);
channel.setLink("http://server-name/home.c?accountId=" + accountId);
channel.setTitle(account.getTitle());
List articles = facade.getArticles(accountId, account.getMaxPerPage(), 1);
Iterator it = articles.iterator();
while(it.hasNext()) {
Article article = (Article)it.next();
channel.addItem("http://server-name/article.c?articleId=" + article.getArticleId(),
article.getSummary(), article.getTitle()
);
}
// 輸出XML:
response.setContentType("text/XML");
PrintWriter pw = response.getWriter();
pw.print(channel.getFeed("rss"));
pw.close();
十四、實現全文搜索
全文搜索能大大方便用戶快速找到他們希望的文章,為blog增加一個全文搜索功能是非常必要的。然而,全文搜索不等於SQL的LIKE語句,因為關系數據庫的設計並不是為全文搜索設計的,數據庫索引對全文搜索無效,在一個幾百萬條記錄中檢索LIKE '%A%'可能會耗時幾分鐘,這是不可接受的。幸運的是,我們能使用免費並且開源的純Java實現的Lucene全文搜索引擎,Lucene可以非常容易地集成到我們的blog中。
Lucene不提供直接對文件,數據庫的索引,只提供一個高性能的引擎,但接口卻出人意料地簡單。我們只需要關心以下幾個簡單的接口:
Document:代表Lucene數據庫的一條記錄,也代表搜索的一條結果。
Field:一個Document包含一個或多個FIEld,類似關系數據庫的字段。
IndexWriter:用於創建新的索引,也就是向數據庫添加新的可搜索的大段字符串。
Analyzer:將字符串拆分成單詞(Token),不同的文本對應不同的Analyzer,如HtmlAnalyzer,PDFAnalyzer。
Query:封裝一個查詢,用於解析用戶輸入。例如,將“bea blog”解析為“同時包含bea和blog的文章”。
Searcher:搜索一個Query,結果將以Hits返回。
Hits:封裝一個搜索結果,包含Document集合,能非常容易地輸出結果。
下一步,我們需要為Article表的content字段建立全文索引。首先為Lucene新建一個數據庫,請注意這個數據庫是Lucene專用的,我們不能也不必知道它的內部結構。Lucene的每個數據庫對應一個目錄,只需要指定目錄即可:
String indexDir = "C:/search/blog";
IndexWriter indexWriter = new IndexWriter(indexDir, new StandardAnalyzer(), true);
indexWriter.close();
然後添加文章,讓Lucene對其索引:
String title = "文章標題"
// 從數據庫讀取
String content = "文章內容"
// 從數據庫讀取
// 打開索引:
IndexWriter indexWriter = new IndexWriter(indexDir, new StandardAnalyzer(), false);
// 添加一個新記錄:
Document doc = new Document();
doc.add(FIEld.KeyWord("title", title));
doc.add(FIEld.Text("content", content));
// 建立索引:
indexWriter.addDocument(doc);
// 關閉:
indexWriter.close();
要搜索文章非常簡單,然後添加文章,讓對其索引:
String title = "文章標題" // 從數據庫讀取
String content = "文章內容" // 從數據庫讀取
// 打開索引:
IndexWriter indexWriter = new IndexWriter(indexDir, new StandardAnalyzer(), false);
// 添加一個新記錄:
Document doc = new Document();
doc.add(FIEld.KeyWord("title", title));
doc.add(FIEld.Text("content", content));
// 建立索引:
indexWriter.addDocument(doc);
// 關閉:
indexWriter.close();
要搜索文章:
Searcher searcher = new IndexSearcher(dir);
Query query = QueryParser.parse(keyWord, "content", new StandardAnalyzer());
Hits hits = searcher.search(query);
if(hits != null){
for(int i = 0;i < hits.length(); i++){
Document doc = hits.doc(i);
System.out.println("found in " + doc.get("title"));
System.out.println(doc.get("content"));
}
}
searcher.close();
我們設計一個LuceneSearcher類封裝全文搜索功能,由於必須鎖定數據庫所在目錄,我們把數據庫設定在/WEB-INF/search/下,確保用戶不能訪問,並且在配置文件中初始化目錄:
/WEB-INF/search/
十五、發送Email
Blog用戶可以讓系統將來訪用戶的留言發送到注冊的Email地址,為了避免使用SMTP發信服務器,我們自己手動編寫一個SendMail組件,直接通過SMTP協議將Email發送到用戶信箱。
SendMail組件只需配置好DNS服務器的IP地址,即可向指定的Email信箱發送郵件。並且,SendMail使用緩沖隊列和多線程在後台發送Email,不會中斷正常的Web服務。具體代碼請看SendMail.Java。
十六、測試
服務器配置為:P4 1.4G,512M DDR,100M Ethernet,Windows XP Professional SP2。
測試服務器分別為WebLogic Server 8.1,Tomcat 4.1/5.0,Resin 2.1.1。
測試數據庫為MS SQL Server 2000 SP3。
十七、中文支持
測試發現,中文不能在頁面中正常顯示,為了支持中文,首先在web.XML加入Filter,用於將輸入編碼設置為gb2312:
encodingFilter
org.crystalblog.web.filter.EncodingFilter
encoding
gb2312
encodingFilter
/*
然後用文本工具搜索所有的.htm,.Html,.propertIEs文件,將“iso-8859-1”替換為“gb2312”,現在頁面中文已經能正常顯示,但是Lucene仍不能正常解析中文,原因是標准的StandardA?nalyzer只能解析英文,可以從網上下載一個支持中文的Analyzer。
十八、總結
Spring的確是一個優秀的J2EE(J2EE培訓 )框架,通過Spring強大的集成和配置能力,我們能輕松設計出靈活的多層J2EE應用而無需復雜的EJB組件支持。