Spring MVC 學習筆記 PDF/Excel格式輸出


Spring mvc 中對於輸出格式為pdf和xsl的view,提供了兩個abstract的view類供繼承分別為AbstractPdfView和AbstractExcelView。 Pdf格式輸出 對於pdf格式的輸出,spring 缺省提供的模板類為AbstractPdfView,並利用iText來實現pdf的輸出。但此類只支持iText 2.x的版本,而目前iText最新的版本是5.x,為支持最新版本的iText類庫,需要根據AbstractPdfView的內容依樣畫葫蘆自己實現一個PdfView模板類。

public abstract class AbstractIText5PdfView extends AbstractView {

public AbstractIText5PdfView() {
setContentType("application/pdf");
}

@Override
protected boolean generatesDownloadContent() {
return true;
}

@Override
protected final void renderMergedOutputModel(Map<String, Object> model,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
ByteArrayOutputStream baos = createTemporaryOutputStream();
Document document = newDocument();
PdfWriter writer = newWriter(document, baos);
prepareWriter(model, writer, request);
buildPdfMetadata(model, document, request);
document.open();
buildPdfDocument(model, document, writer, request, response);
document.close();
writeToResponse(response, baos);
}

protected Document newDocument() {
return new Document(PageSize.A4);
}

protected PdfWriter newWriter(Document document, OutputStream os)
throws DocumentException {
return PdfWriter.getInstance(document, os);
}

protected void prepareWriter(Map<String, Object> model, PdfWriter writer,
HttpServletRequest request) throws DocumentException {

writer.setViewerPreferences(getViewerPreferences());
}

protected int getViewerPreferences() {
return PdfWriter.ALLOW_PRINTING | PdfWriter.PageLayoutSinglePage;
}

protected void buildPdfMetadata(Map<String, Object> model,
Document document, HttpServletRequest request) {
}

protected abstract void buildPdfDocument(Map<String, Object> model,
Document document, PdfWriter writer, HttpServletRequest request,
HttpServletResponse response) throws Exception;

}

修改pom.xml,增加對iText 5 的類庫引用。

        <dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-asian</artifactId>
<version>5.1.0</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.1.0</version>
</dependency>

繼承AbstractIText5PdfView ,實現自己的pdf輸出實現類

public class Pdfview extends AbstractIText5PdfView {
@Override
protected void buildPdfDocument(Map<String, Object> model,
Document document, PdfWriter writer, HttpServletRequest request,
HttpServletResponse response) throws Exception {
Paragraph header = new Paragraph(new Chunk("PDF 輸出測試",
getChineseFont(24)));
document.add(header);
document.add(new Paragraph("測試",getChineseFont(12)));
}

private static final Font getChineseFont(float size) {
Font FontChinese = null;
try {
BaseFont bfChinese = BaseFont.createFont("STSong-Light",
"UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
FontChinese = new Font(bfChinese, size, Font.NORMAL);
} catch (DocumentException de) {
System.err.println(de.getMessage());
} catch (IOException ioe) {
System.err.println(ioe.getMessage());
}
return FontChinese;
}
}

修改MultiAction controll類,增加對pdf輸出的handler method測試代碼

    @RequestMapping("/pdf")
public String helloPDF(){
return "helloPDF";
}

這里我們將使用ResourceBundleViewResolver來作為pdf view的ViewResolver,修改servlet context xml配置文件如下

    <bean class="org.springframework.web.servlet.view.ResourceBundleViewResolver"
p:basename
="views" p:order="2" />

表示spring mvc將在classpath根目錄下查找名為views.properties的配置文件來根據view name匹配對應的view實現類。 views.properties中的配置如下 helloPDF.(class)=net.zhepu.web.view.Pdfview 其中helloPDF與之前handler method返回的viewName相匹配,(class)表示此行配置是要將viewName和view實現類關聯。 最后訪問url http://localhost:8080/springmvc/pdf 以查看輸出的pdf文件
Excel格式輸出 Spring mvc利用POI或jExcel來實現對excel輸出的支持,如果使用POI需要繼承AbstractExcelView類,如果使用jExcel則需要繼承AbstractJExcelView類。這里以POI為例。 首先修改pom.xml,增加對POI的引用。

        <!-- excel export support -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.7</version>
</dependency>
<!-- excel export support -->

再增加一個繼承自AbstractExcelView的實現類,來實際輸出excel

    protected void buildExcelDocument(Map<String, Object> model,
HSSFWorkbook workbook, HttpServletRequest request,
HttpServletResponse response) throws Exception {
HSSFSheet sheet;
HSSFCell cell;
sheet = workbook.createSheet("Spring");
sheet.setDefaultColumnWidth((short) 12);
// write a text at A1
cell = getCell(sheet, 0, 0);
setText(cell, "Spring-Excel 測試");
}

修改MultiAction controll類,增加對excel輸出的handler method測試代碼

    @RequestMapping("/excel")
public String helloExcel(){
return "excel";
}

同樣可以使用ResourceBundleViewResolver來實現view name和view class的關聯,但這里我們使用XmlViewResolver來實現。 修改servlet context xml配置文件,增加如下配置

    <!-- excel output setting using XmlViewResolver -->
<bean id="excelViewResolver" class="org.springframework.web.servlet.view.XmlViewResolver">
<property name="order" value="3" />
<property name="location" value="classpath:views.xml" />
</bean>

以上配置表示XmlViewResolver將在views.xml中查找viewname和view class的對應關系。Views.xml配置文件實際上就是一個標准的spring bean的配置文件。內容如下

<bean name="excel" class="net.zhepu.web.view.ExcelView" />

這樣將bean name “excel”與view實現類相關聯。 最后訪問url http://localhost:8080/springmvc/excel 查看excel輸出內容。
使用XmlViewResolver 和ResourceBundleViewResolver可能存在的問題 使用XmlViewReslover和ResourceBundleViewResolver后,訪問sample工程的首頁面helloWorld會發現頁面出現報錯信息 Bean named 'helloworld' must be of type [org.springframework.web.servlet.View], but was actually of type [net.zhepu.web.Helloworld] ,原因是這兩個viewResolver本質上都是在配置文件中定義一個spring bean,並將bean name 和view name相關聯來實現view mapping。因此實際上只要context中存在對應名字的bean name,spring 就可以根據相應的viewName找到匹配的view bean來生成視圖。而這也導致類似如下的配置出現問題。

    <bean class="org.springframework.web.servlet.view.ResourceBundleViewResolver"
p:basename
="views" p:order="1" />

<bean id="viewResolver"
class
="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>

對應的controller代碼如下

@Controller("controllerHelloWorld")
@RequestMapping("/helloworld")
public class Helloworld {

@RequestMapping(method=RequestMethod.GET)
public ModelAndView hello() {
ModelAndView mv = new ModelAndView();
mv.setViewName("helloworld");
return mv;
}
}

此時訪問/helloworld原意是要返回對應/WEB-INF/helloworld.jsp, 但spring mvc在解析viewname時,根據配置文件中的order順序,先找到ResourceBundleViewResolver來解析viewname,且發現此時context中存在bean name 為 helloWorld的bean,就試圖使用helloWorld這個bean來解析view,因此出現了上述的報錯。 因此在使用ResourceBundleViewResolver或XmlViewResolver時需要注意返回的viewname不要和當前工程中已經定義的beanName存在沖突。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM