Spring:自定义PDF视图

前言

        在Spring中视图分为逻辑视图和非逻辑视图。逻辑视图是需要视图解析器(ViewResolver)去定位解析的,如:JstlView等。而非逻辑视图则不需要定位视图的物理位置,它只需要直接将数据模型进行渲染展示给用户即可,如:MappingJackson2JsonView(它会将数据模型渲染为Json数据集返回给用户),以及本文中使用的AbstractPdfView。

注:本文是基于上一篇文章中的项目(实战:在SpringBoot中使用MongoDB)基础上进行开发的(偷个懒~),主要实现功能是从MongoDB中读取数据,并将数据写入PDF中,最后返回给用户。

一、在pom.xml中加入PDF依赖 

        <!-- PDF依赖包 -->
        <dependency>
            <groupId>org.xhtmlrenderer</groupId>
            <artifactId>core-renderer</artifactId>
            <version>R8</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itextpdf</artifactId>
            <version>5.5.12</version>
        </dependency>

这样项目就导入了关于PDF的包。在Spring中只需要继承AbstractPdfView抽象类,并实现抽象方法即可完成PDF视图的配置。但是我们一般不仅仅只需要一种格式的PDF视图,而为了适应不同业务需求,我们一般先定义导出的接口。

二、定义PDF导出接口

package com.scb.mongodemo.service;

import com.lowagie.text.Document;
import com.lowagie.text.pdf.PdfWriter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;

public interface PdfExportService {
    void make(Map<String, Object> map, Document document,
                     PdfWriter pdfWriter, HttpServletRequest httpServletRequest,
                     HttpServletResponse httpServletResponse);
}

可以看到,PdfExportService就是个普通的接口类,里面有个make方法,此方法的参数与AbstractPdfView的抽象类相同。接下来,我们就可以继承AbstractPdfView抽象来配置PDF视图了。

三、继承AbstractPdfView

package com.scb.mongodemo.service;

import com.lowagie.text.*;
import com.lowagie.text.pdf.PdfWriter;
import org.springframework.web.servlet.view.document.AbstractPdfView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;

public class PdfView extends AbstractPdfView {
    private PdfExportService pdfExportService=null;

    public PdfView(PdfExportService pdfExportService){
        this.pdfExportService=pdfExportService;
    }
    @Override
    protected void buildPdfDocument(Map<String, Object> map, Document document,
                                    PdfWriter pdfWriter, HttpServletRequest httpServletRequest,
                                    HttpServletResponse httpServletResponse) throws Exception {
        pdfExportService.make(map,document,pdfWriter,httpServletRequest,httpServletResponse);
    }
}

从上诉代码可以看到,我们是通过调用PDF导出接口类PdfExportService的make方法来执行buildPdfDocument方法的。这样做的好处就是,可以通过创建PdfExportService接口的子类,并通过依赖注入的方式实现不同的PDF细节。

四、控制层

package com.scb.mongodemo.controller;

import com.lowagie.text.*;
import com.lowagie.text.Font;
import com.lowagie.text.pdf.PdfPCell;
import com.lowagie.text.pdf.PdfPTable;
import com.scb.mongodemo.entity.Role;
import com.scb.mongodemo.entity.User;
import com.scb.mongodemo.repository.UserRepository;
import com.scb.mongodemo.service.PdfExportService;
import com.scb.mongodemo.service.PdfView;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.View;

import java.awt.*;
import java.util.*;
import java.util.List;

@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    UserRepository userRepository;

    /**
     * 这是上章的内容,与本章无关可以注释掉
     * 
    @GetMapping("/{userName}")
    public List<User> findByUserName(@PathVariable String userName) {
        return userRepository.findByUserNameLike(userName);
    }

    @PostMapping("/initUsers")
    public List<User> initUsers(){
        List<User> saveUsers=new ArrayList<>();
        for (int i=1;i<=10;i++){
            User user=new User();
            user.setId((long)i);
            user.setUserName("user_name_"+i);
            user.setNote("user_note_"+i);

            Role role=new Role();
            role.setId((long)i);
            role.setRoleName("role_name_"+i);
            role.setNote("role_note_"+i);
            List<Role> roles=new ArrayList<>();
            roles.add(role);
            user.setRoles(roles);

            saveUsers.add(userRepository.save(user));
        }
        return saveUsers;
    }
     */

    @GetMapping("/export/pdf")
    public ModelAndView exportPdf(String userName){
        List<User> userList=userRepository.findByUserNameLike(userName);
        View view=new PdfView(exportService());
        ModelAndView mv=new ModelAndView();
        mv.setView(view);
        mv.addObject("userList",userList);
        return mv;
    }

    @SuppressWarnings("unchecked")
    private PdfExportService exportService(){
        //使用Lambda表达式自定义导出
        return (model,document,writer,request,response)->{
            try{
                document.setPageSize(PageSize.A4);
                document.addTitle("User Info");
                //换行
                document.add(new Chunk("\n"));
                //创建表格,3列
                PdfPTable table=new PdfPTable(3);
                Font f8=new Font();
                f8.setColor(Color.BLUE);
                f8.setStyle(Font.BOLD);
                //单元格
                PdfPCell cell=new PdfPCell(new Paragraph("id",f8));
                cell.setHorizontalAlignment(Element.ALIGN_CENTER);
                table.addCell(cell);
                cell=new PdfPCell(new Paragraph("user_name",f8));
                cell.setHorizontalAlignment(Element.ALIGN_CENTER);
                table.addCell(cell);
                cell=new PdfPCell(new Paragraph("note",f8));
                cell.setHorizontalAlignment(Element.ALIGN_CENTER);
                table.addCell(cell);
                List<User> userList=(List<User>)model.get("userList");
                Font font=new Font();
                font.setColor(Color.BLACK);
                //获取数据模型中的userList,并填入表格
                for (User user:userList){
                    document.add(new Chunk("\n"));
                    cell=new PdfPCell(new Paragraph(user.getId()+"",font));
                    cell.setHorizontalAlignment(Element.ALIGN_CENTER);
                    table.addCell(cell);
                    cell=new PdfPCell(new Paragraph(user.getUserName(),font));
                    cell.setHorizontalAlignment(Element.ALIGN_CENTER);
                    table.addCell(cell);
                    cell=new PdfPCell(new Paragraph(user.getNote(),font));
                    cell.setHorizontalAlignment(Element.ALIGN_CENTER);
                    table.addCell(cell);
                }
                //在文档中加入表格
                document.add(table);
            }catch (DocumentException e){
                e.printStackTrace();
            }
        };
    }
}

exportPdf方法:先查询后台数据得到用户列表,在放入模型和视图(ModelAndView)中,接着设置了一个视图(PdfView)。PdfView通过调用下面的exportService方法来初始化的。对于exportService方法中的具体内容且听我下文在说。

五、运行结果

我们浏览器访问http://localhost:8080/user/export/pdf?userName=user_name,可以得到以下结果:

可以看到,自定义的PDF视图已经成功渲染出来了。

六、exportService方法详解

在exportService方法中,我们是通过使用iText的相关方法来生成PDF的。

iText是著名开放源码的站点sourceforge一个项目,是用于生成PDF文档的一个java类库。通过iText不仅可以生成PDF或rtf的文档,而且可以将XML、Html文件转化为PDF文件。详细教程如下:

简单入门:iText入门学习        深入学习:itext7学习汇总

七、后记

上诉代码中,我们不仅需要写PDF的模板还要写入数据。而生成PDF模板是相当繁琐的,那么我们能不能通过导入一个PDF文件,然后只要往该文件中写入数据就可以了呢?当然可以,详见以下教程:

SpringMVC使用PDF模板生成PDF文件

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值