前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java生成PDF

Java生成PDF

作者头像
木左
发布2022-09-23 10:56:30
1.4K0
发布2022-09-23 10:56:30
举报

本文主要介绍Java生成PDF

如题,在日常的项目开发中,我们会遇到需要通过Java代码生成pdf,本文主要介绍的是通过velocity模板生产pdf。

我们利用springboot可以快速开发项目,因为本文是采用的eclipse作为开发工具,直接打开官网进行项目的配置下载。下载下来的基本结构是如下图:

接下来我们修改pom.xml文件,引入需要的相关包。

代码语言:javascript
复制
<!-- velocity相关jar包 -->
    <dependency>
        <groupId>org.apache.velocity</groupId>
        <artifactId>velocity</artifactId>
        <version>1.7</version>
    </dependency>
    <dependency>
        <groupId>org.apache.velocity.tools</groupId>
        <artifactId>velocity-tools</artifactId>
        <version>2.0-alpha1</version>
    </dependency>
    <dependency>
        <groupId>org.xhtmlrenderer</groupId>
        <artifactId>core-renderer</artifactId>
        <version>R8</version>
    </dependency>
    <!-- 集成接口文档 -->
    <dependency>
        <groupId>com.github.xiaoymin</groupId>
        <artifactId>knife4j-spring-boot-starter</artifactId>
        <version>2.0.7</version>
    </dependency>

配置完后我们就可以进入到正题了,为了方便演示,我们不再进行数据库连接查数据操作,而是直接采用接口传入参数值进行动态的变化以实现不同的值的展示。

我们先创建User对象,用于接收我们的接口数据。

代码语言:javascript
复制
import java.util.Date;

import org.springframework.format.annotation.DateTimeFormat;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;

@ApiModel(value = "用户信息")
public class User {
    @ApiModelProperty(value="用户姓名", position = 1, required = true, example = "木左")
    private String name;
    @ApiModelProperty(value="性别", position = 1, required = true, example = "1", notes = "性别静态字典 1 男 2 女", allowableValues = "1,2")
    private int sex;
    @ApiModelProperty(value = "手机号", position = 2, required = true, example = "15530651234")
    private String mobile;
    @ApiModelProperty(value = "地址", position = 3, required = true, example = "北京市昌平区XXXX")
    private String address;
    @ApiModelProperty(value = "注册时间", position = 4, required= true, example = "2020-12-27 10:49:50" ,notes ="格式 yyyy-MM-dd HH:mm:ss", dataType="Date")
    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
    private Date registerTime;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getMobile() {
        return mobile;
    }
    public void setMobile(String mobile) {
        this.mobile = mobile;
    }
    public String getAddress() {
        return address;
    }
    public void setAddress(String address) {
        this.address = address;
    }
    public Date getRegisterTime() {
        return registerTime;
    }
    public void setRegisterTime(Date registerTime) {
        this.registerTime = registerTime;
    }
    public int getSex() {
        return sex;
    }
    public void setSex(int sex) {
        this.sex = sex;
    }


}

接下来我们直接配置好Knife4jConfiguration,如果你的包路径和我的不一致,记得修改扫描包路径。

代码语言:javascript
复制
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;

@Configuration
@EnableSwagger2WebMvc
public class Knife4jConfiguration {

    @Bean(value = "defaultApi2")
    public Docket defaultApi2() {
        Docket docket=new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(new ApiInfoBuilder()
                        .description("# 测试生成PDF")
                        .termsOfServiceUrl("http://localhost/")
                        .version("1.0")
                        .build())
                //分组名称
                .groupName("测试生成PDF")
                .select()
                //这里指定Controller扫描包路径
                .apis(RequestHandlerSelectors.basePackage("com.muzuo.pdf.control"))
                .paths(PathSelectors.any())
                .build();
        return docket;
    }
}

然后我们定义一个服务接口,用于生成我们的PDF,简单一点就是传入接口接收的User对象,然后返回一个boolean用于给前端提示成功还是失败。

代码语言:javascript
复制
import com.muzuo.pdf.entity.User;

public interface IPdfService {
    /**
     * 生成PDF
     * @Title: createPdf
     * @Description: TODO(这里用一句话描述这个方法的作用)
     * @param @param user
     * @param @return    参数
     * @return boolean    返回类型
     * @throws
     */
    boolean createPdf(User user);
}

剩下就是定义一个control了,如下

代码语言:javascript
复制
import io.swagger.annotations.Api;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.muzuo.pdf.entity.User;
import com.muzuo.pdf.service.IPdfService;
/**
 * 
 * @ClassName: IndexControl
 * @Description: TODO(这里用一句话描述这个类的作用)
 * @author muzuo
 * @date 2020年12月27日
 *
 */
@Api("测试生成PDF")
@Controller
public class IndexControl {
    @Autowired
    IPdfService pdfService;


    @PostMapping("/index")
    @ResponseBody
    public boolean index(User user){
        return pdfService.createPdf(user);
    }
}

接下来就是我们的实现了,具体如下:

代码语言:javascript
复制
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.tools.generic.DateTool;
import org.apache.velocity.tools.generic.MathTool;
import org.apache.velocity.tools.generic.NumberTool;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.xhtmlrenderer.pdf.ITextFontResolver;
import org.xhtmlrenderer.pdf.ITextRenderer;

import com.lowagie.text.pdf.BaseFont;
import com.muzuo.pdf.entity.User;
import com.muzuo.pdf.service.IPdfService;
import com.muzuo.pdf.util.DictionaryUtil;

@Service
public class PdfServiceImpl implements IPdfService{

    @Value("${pdf.PDFtemplatePath}")
    private String PDFtemplatePath;
    @Value("${pdf.pdfFilePath}")
    private String pdfFilePath;

    @Override
    public boolean createPdf(User user) {
        try {
            Properties properties = new Properties();
            // 设置velocity的模版路径
            properties.setProperty(VelocityEngine.FILE_RESOURCE_LOADER_PATH, PDFtemplatePath);
            // 设置编码
            properties.setProperty(VelocityEngine.INPUT_ENCODING, "UTF-8");
            properties.setProperty(VelocityEngine.OUTPUT_ENCODING, "UTF-8");
            VelocityEngine ve = new VelocityEngine();
            ve.init(properties);
            // 获取PDF模板 可以有自己的规则 用于取不同的模板
            Template t = ve.getTemplate("template.vm", "UTF-8");
            // 取得velocity的上下文context
            VelocityContext context = new VelocityContext();
            // 给context添加方法 用于页面调用
            getContext(context);
            // 将数据添加到模板中 建议使用map 这样可以兼容多个模块
            Map<String, Object> dataMap = new HashMap<String, Object>();
            dataMap.put("name", user.getName());
            dataMap.put("sex", user.getSex());
            dataMap.put("mobile", user.getMobile());
            dataMap.put("address", user.getAddress());
            dataMap.put("registerTime", user.getRegisterTime());

            context.put("dataMap", dataMap);
            // 输出流
            StringWriter writer = new StringWriter();
            t.merge(context, writer);

            java.io.File filePath = new java.io.File(pdfFilePath);
            if (!filePath.exists()) {
                filePath.mkdir();
            }
            String fileName = user.getName() + ".pdf";
            String outputFile = filePath +File.separator+ fileName;
            OutputStream os = new FileOutputStream(outputFile);
            ITextRenderer renderer = new ITextRenderer();
            ITextFontResolver fontResolver = renderer.getFontResolver();
            fontResolver.addFont(PDFtemplatePath + "/font/simsun.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
            renderer.setDocumentFromString(writer.toString());
            renderer.layout();
            renderer.createPDF(os);
            os.close();
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    private void getContext(VelocityContext context) {
        context.put("number", new NumberTool());
        context.put("math", new MathTool());
        context.put("date", new DateTool());
        //自定义方法 可扩展
        context.put("dictionaryUtil", new DictionaryUtil());
    }

}

其中参数PDFtemplatePath和pdfFilePath参数在application.properties配置,如下

代码语言:javascript
复制
server.port=8090

spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT+8

#修改为你本地项目的路径哦
pdf.PDFtemplatePath=E://newHzbank/Pdf-Demo/template/
#修改为放生成Pdf的路径
pdf.pdfFilePath=D://pdfFile

还有其他代码省略,有片段代码没有完成可以运行的例子都是耍流氓(末尾给出飞机票直达)。

让我们看看跑起来是什么样子,运行后效果图。

看下PDF的样子

看着还是可以的。赶快收藏下,自己用的时候直接“拿来主义”就可以了。

飞机票-》https://gitee.com/mu-zuo/java-generation-pdf

运行后访问 http://localhost:8090/doc.html 端口是8090哦!!!

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-01-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Java技术人生 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档