第一步:需要引入的jar包
<!--用于导出word文档-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<!-- 非spring-boot依赖 用于导出word文档-->
<!-- <dependency>-->
<!-- <groupId>org.freemarker</groupId>-->
<!-- <artifactId>freemarker</artifactId>-->
<!-- <version>2.3.28</version>-->
<!-- </dependency>-->
<!-- 导出 pdf -->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.13</version>
</dependency>
<dependency>
<groupId>com.itextpdf.tool</groupId>
<artifactId>xmlworker</artifactId>
<version>5.5.13</version>
</dependency>
<!-- 解决Linux下导出pdf,不显示中文问题-->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-asian</artifactId>
<version>5.2.0</version>
</dependency>
第二步:准备模板文件(当然,不使用模板在代码中拼也可以,但是有点麻烦)
模板实例文件:https://download.csdn.net/download/Copy_ing/13117006
2.1 word模板: 使用xml格式的模板文件
说明:首先准备一个word文档,将word的内容编写为你最终要的样子. 然后另存为xml格式的文件,接着在根据自己的需要,将xml文件中要动态替换的关键字替换为${关键字} 的格式. 最后将文件后缀修改为ftl
2.2 pdf模板: 使用html格式的模板文件(对html的格式要求,比较严格,一定要仔细检查.)
说明:首先也是创建一个word文件,编写成最终要导出的样子,然后另存为html格式的文件.然后同上.
模板文件放置位置:
例:
第三步:(上代码)
package com.gs.hiring.app.util;
import com.gs.hiring.app.vo.customer.resume.CustomerResumeInfoVO;
import com.itextpdf.text.BaseColor;
import com.itextpdf.text.Document;
import com.itextpdf.text.Font;
import com.itextpdf.text.FontProvider;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.tool.xml.XMLWorkerHelper;
import freemarker.template.Configuration;
import freemarker.template.Template;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author copying
* @date 2020/11/5 10:40
* 根据模板文件(.ftl)生成对应的word文档
*
* 使用说明: 官方文档:http://freemarker.foofun.cn/dgui_misc_userdefdir.html
* 1.首先准备一份指定格式的word文档.
* 2.将其中的参数 修改为指定格式: ${?} (? 字段名)
* 3.将word文档,另存为xml格式的文件.
* 4.修改文件后缀为.ftl
*
*/
@Slf4j
public class ResumeWordExportUtil {
private ResumeWordExportUtil(){
super();
}
private static ResumeWordExportUtil service = null;
public static ResumeWordExportUtil getInstance() {
if(service == null) {
synchronized(ResumeWordExportUtil.class){
if(service == null) {
service = new ResumeWordExportUtil();
}
}
}
return service;
}
/**
* 生成要导出的文件
* @param templateFilePath
* @param data
* @param response
* @param isCh
*/
public void createResumeFile(String templateFilePath, CustomerResumeInfoVO data,Integer type, HttpServletResponse response, boolean isCh) throws Exception {
String fileName;
if(isCh){
fileName=data.getChName()+" 简历";
}else {
fileName=data.getEnName()+" resume";
}
String fileType="doc";
if(Objects.nonNull(type)){
if(type==1){
fileType="pdf";
}
}
setResponseHeader(response,fileName,fileType);
OutputStream out=response.getOutputStream();
Writer responseOut = new OutputStreamWriter(out);
try{
Configuration configuration = new Configuration(Configuration.VERSION_2_3_28);
configuration.setClassForTemplateLoading(this.getClass(), "/templates");
Template template = configuration.getTemplate(templateFilePath, "UTF-8");
if(type==1){
Writer writerPdf=new StringWriter();
template.process(data, writerPdf);
String pdf=writerPdf.toString();
Document document=new Document();
PdfWriter pdfWriter =PdfWriter.getInstance(document,out);
FontProvider fontProvider=new ChinaFontProvide();
document.open();
XMLWorkerHelper.getInstance().parseXHtml(pdfWriter,document,new ByteArrayInputStream(pdf.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8,fontProvider);
document.close();
responseOut = new OutputStreamWriter(out);
}else {
//获取头像信息
if (isGetStandardPhoto(data.getStandardPhoto())) {
data.setStandardPhoto(image2Base64(data.getStandardPhoto()));
}
template.process(data, responseOut);
}
}catch (Exception e){
throw e;
} finally {
try {
responseOut.flush();
responseOut.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 提供中文
* 不用字体文件,显示中文的解决方法
*/
public static final class ChinaFontProvide implements FontProvider {
@Override
public Font getFont(String arg0, String arg1, boolean arg2, float arg3,
int arg4, BaseColor arg5) {
BaseFont bfChinese = null;
try {
bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
} catch (Exception e) {
e.printStackTrace();
}
return new Font(bfChinese, 10, Font.NORMAL);
}
@Override
public boolean isRegistered(String arg0) {
return false;
}
}
/**
* 判断是否获取头像
* @return boolean
*/
private boolean isGetStandardPhoto(String url){
if(Objects.nonNull(url) && !"".equals(url)){
//校验url格式
return url.startsWith("http://") || url.startsWith("https://");
}
return false;
}
/**
* 通过url获取图片
* @param imgUrl 图片地址
* @return 图片编码
*/
public String image2Base64(String imgUrl) {
URL url;
InputStream is = null;
ByteArrayOutputStream outStream = null;
HttpURLConnection httpUrl = null;
try{
url = new URL(imgUrl);
httpUrl = (HttpURLConnection) url.openConnection();
httpUrl.connect();
httpUrl.getInputStream();
is = httpUrl.getInputStream();
outStream = new ByteArrayOutputStream();
//创建一个Buffer字符串
byte[] buffer = new byte[1024];
//每次读取的字符串长度,如果为-1,代表全部读取完毕
int len;
//使用一个输入流从buffer里把数据读取出来
while( (len=is.read(buffer)) != -1 ){
//用输出流往buffer里写入数据,中间参数代表从哪个位置开始读,len代表读取的长度
outStream.write(buffer, 0, len);
}
// 对字节数组Base64编码
return encodeImage(outStream.toByteArray());
}catch (Exception e) {
e.printStackTrace();
}
finally{
if(is != null)
{
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(outStream != null)
{
try {
outStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(httpUrl != null)
{
httpUrl.disconnect();
}
}
return imgUrl;
}
/**
* 图片转字符串
* @param image 图片
* @return 编码
*/
public static String encodeImage(byte[] image){
return replaceEnter(Base64.getEncoder().encodeToString(image));
}
public static String replaceEnter(String str){
String reg ="[\n-\r]";
Pattern p = Pattern.compile(reg);
Matcher m = p.matcher(str);
return m.replaceAll("");
}
private void setResponseHeader(HttpServletResponse response, String fileName,String fileType) {
try {
response.reset();
// 设置生成的文件类型
response.setContentType("application/ms"+fileType);
// 设置文件头编码方式和文件名
response.setCharacterEncoding("UTF-8");
// 在浏览器中测试生效,postman中文件名为response,无法修改
response.setHeader("Content-disposition", "attachment;filename="
.concat(String.valueOf(URLEncoder.encode(fileName + "."+fileType, "UTF-8"))));
// 此设置,可保证web端可以取到文件名
response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
} catch (Exception ex) {
ex.printStackTrace();
}
}
/**
* 把路径的\替换成/
* @param path 原地址
* @return 处理后的地址
*/
private String pathReplace(String path) {
while(path != null && path.contains("\\")) {
path = path.replace("\\", "/");
}
return path;
}
}
遇到的问题:
1.直接生成的html文件格式不严谨,导致itext无法解析.
解决方案:1.html标签必须要,一一对应,有开始,有结束.例:<tr></tr> 2.只有一行的标签必须有结束符号.例:<br/> <meta />
2.freemarker 动态赋值时,要进行属性检查 . 具体语法请参考官方文档: http://freemarker.foofun.cn/dgui_misc_userdefdir.html
3.linux环境,导出的pdf文件不显示中文(本地导出pdf显示中文,到服务器上就不显示了) 解决方案: 由于没有设置字体文件导致,在上面代码中已经解决.
4.导出word时,无法显示图片(freemarker不支持超链接). 解决方法:在代码中获取图片,转换为Base64位编码,直接放到xml中.
注:要是有什么问题,或对你有所帮助,欢迎点赞\评论.