?
? ????? PHP ??? ???? ??? ?? ??
對(duì)看模型數(shù)據(jù)輸出的用戶來說,返回一個(gè)HTML頁(yè)面并不總是最好的方法。 Spring簡(jiǎn)化了根據(jù)模型數(shù)據(jù)動(dòng)態(tài)輸出PDF文檔或Excel電子表格的工作。 這些文檔即最終視圖,它們將以適當(dāng)?shù)膬?nèi)容類型用流的形式從服務(wù)器輸出,并在客戶端PC相應(yīng)地啟動(dòng)PDF或電子表格瀏覽器(希望如此)。
為了使用Excel視圖,你需要把'poi'庫(kù)加到classpath中;使用PDF的話需要iText.jar。它們都已經(jīng)包含在Spring的主發(fā)行包里。
基于文檔的視圖幾乎與XSLT視圖的處理方式相同。 下面的內(nèi)容將在前文基礎(chǔ)上介紹,XSLT例子中的controller如何被用來渲染同一個(gè)的模型數(shù)據(jù),分別產(chǎn)生PDF或Excel輸出(輸出文檔可以用Open Office瀏覽和編輯)。
首先,我們修改view.properties(或等價(jià)的xml文件),增加兩種文檔類型的視圖定義。整個(gè)文件現(xiàn)在看起來是這個(gè)樣子:
home.class=xslt.HomePage home.stylesheetLocation=/WEB-INF/xsl/home.xslt home.root=words xl.class=excel.HomePage pdf.class=pdf.HomePage
如果你想在一個(gè)電子表格模板基礎(chǔ)上添加模型數(shù)據(jù),可以在視圖定義中為'url'屬性指定一個(gè)文件位置。
這里用的controller代碼,除了視圖名以外,其他的與XSLT例子中的完全一樣。 當(dāng)然,你可能有更聰明的做法,通過URL參數(shù)或其他方式選擇視圖名,這也證明了Spirng在控制器與視圖的解耦方面確實(shí)非常優(yōu)秀!
和在XSLT例子中一樣,我們需要從適當(dāng)?shù)某橄箢悢U(kuò)展一個(gè)具體類,以實(shí)現(xiàn)輸出文檔的行為。
對(duì)Excel來說,這意味著創(chuàng)建一個(gè)
org.springframework.web.servlet.view.document.AbstractExcelView
(使用POI)或
org.springframework.web.servlet.view.document.AbstractJExcelView
(使用JExcelApi)的子類, 并實(shí)現(xiàn)
buildExcelDocument
方法。
下面是一段使用POI生成Excel視圖的完整代碼,它從模型數(shù)據(jù)中取得詞語(yǔ)列表,把它顯示為電子表格中第一欄內(nèi)連續(xù)的行:
package excel; // imports omitted for brevity public class HomePage extends AbstractExcelView { protected void buildExcelDocument( Map model, HSSFWorkbook wb, HttpServletRequest req, HttpServletResponse resp) throws Exception { HSSFSheet sheet; HSSFRow sheetRow; HSSFCell cell; // Go to the first sheet // getSheetAt: only if wb is created from an existing document //sheet = wb.getSheetAt( 0 ); sheet = wb.createSheet("Spring"); sheet.setDefaultColumnWidth((short)12); // write a text at A1 cell = getCell( sheet, 0, 0 ); setText(cell,"Spring-Excel test"); List words = (List ) model.get("wordList"); for (int i=0; i < words.size(); i++) { cell = getCell( sheet, 2+i, 0 ); setText(cell, (String) words.get(i)); } } }
這是一個(gè)使用JExcelApi的版本,生成同樣的Excel文件:
package excel; // imports omitted for brevity public class HomePage extends AbstractExcelView { protected void buildExcelDocument(Map model, WritableWorkbook wb, HttpServletRequest request, HttpServletResponse response) throws Exception { WritableSheet sheet = wb.createSheet("Spring"); sheet.addCell(new Label(0, 0, "Spring-Excel test"); List words = (List)model.get("wordList"); for (int i = -; i < words.size(); i++) { sheet.addCell(new Label(2+i, 0, (String)words.get(i)); } } }
注意這些API間的差別。我們發(fā)現(xiàn)JExcelApi使用起來更直觀,而且在圖像處理方面更好。 但也發(fā)現(xiàn)使用JExcelApi處理大文件時(shí)存在內(nèi)存問題。
如果你現(xiàn)在修改controller的代碼,讓它返回名為
xl
的視圖(
return new ModelAndView("xl", map);
), 然后再次運(yùn)行你的應(yīng)用,你會(huì)發(fā)現(xiàn),當(dāng)你請(qǐng)求同樣的頁(yè)面時(shí),Excel電子表格被創(chuàng)建出來并自動(dòng)開始下載。
生成PDF版本的詞語(yǔ)列表就更簡(jiǎn)單了。 現(xiàn)在,你創(chuàng)建一個(gè)
org.springframework.web.servlet.view.document.AbstractPdfView
的子類,并實(shí)現(xiàn)
buildPdfDocument()
方法,如下:
package pdf; // imports omitted for brevity public class PDFPage extends AbstractPdfView { protected void buildPdfDocument( Map model, Document doc, PdfWriter writer, HttpServletRequest req, HttpServletResponse resp) throws Exception { List words = (List) model.get("wordList"); for (int i=0; i<words.size(); i++) doc.add( new Paragraph((String) words.get(i))); } }
同樣地,修改controller,讓它返回名為
pdf
的視圖(
return new ModelAndView("pdf", map);
), 運(yùn)行應(yīng)用并請(qǐng)求同樣的URL,這次將會(huì)打開一個(gè)PDF文檔,列出模型數(shù)據(jù)中的每個(gè)詞語(yǔ)。