“ 本文主要介绍Java生成PDF”
如题,在日常的项目开发中,我们会遇到需要通过Java代码生成pdf,本文主要介绍的是通过velocity模板生产pdf。
我们利用springboot可以快速开发项目,因为本文是采用的eclipse作为开发工具,直接打开官网进行项目的配置下载。下载下来的基本结构是如下图:
接下来我们修改pom.xml文件,引入需要的相关包。
org.apache.velocity velocity 1.7 org.apache.velocity.tools velocity-tools 2.0-alpha1 org.xhtmlrenderer core-renderer R8 com.github.xiaoymin knife4j-spring-boot-starter 2.0.7
配置完后我们就可以进入到正题了,为了方便演示,我们不再进行数据库连接查数据操作,而是直接采用接口传入参数值进行动态的变化以实现不同的值的展示。
我们先创建User对象,用于接收我们的接口数据。
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,如果你的包路径和我的不一致,记得修改扫描包路径。
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@EnableSwagger2WebMvcpublic 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用于给前端提示成功还是失败。
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了,如下
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")@Controllerpublic class IndexControl { @Autowired IPdfService pdfService; @PostMapping("/index") @ResponseBody public boolean index(User user){ return pdfService.createPdf(user); }}
接下来就是我们的实现了,具体如下:
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;@Servicepublic 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 dataMap = new HashMap(); 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配置,如下
server.port=8090spring.jackson.date-format=yyyy-MM-dd HH:mm:ssspring.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哦!!!
欢迎搜索微信公众号“木左侃技术人生”,掌握第一时间阅读的机会。
记得关注哦,关注木左不迷路,木左带你上高速!