引入依赖
<!-- https://mvnrepository.com/artifact/com.itextpdf/itext7-core -->
<!--这是iText PDF库的核心组件,提供了一套API来创建、编辑和操作PDF文档-->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext7-core</artifactId>
<version>7.2.6</version>
<type>pom</type>
</dependency>
<!-- https://mvnrepository.com/artifact/com.itextpdf/html2pdf -->
<!--这个依赖是iText PDF的一个扩展,专门用于将HTML内容转换为PDF-->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>html2pdf</artifactId>
<version>4.0.5</version>
</dependency>
<!--Freemarker用于动态生成文本输出,如HTML、XML或其他任何格式的文本-->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.31</version>
</dependency>
2个实体类
package com.jf.modules.model.vo;
import com.jf.modules.model.Assess;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @Author yu.chen1
* @Description
* @Data 2024/5/14 16:39
**/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ConceptAllVo{
/**
* 场景描述
*/
private String sceneDescribe;
/**
* 业务痛点
*/
private String painPoints;
/**
* Ai能力
*/
private String aiAbility;
/**
* 概念名称
*/
private String conceptName;
/**
* AI代理的角色
*/
private String who;
/**
*解决方案
*/
private String solution;
/**
* 目标
*/
private String value;
/**
* 评估
*/
private Assess assess;
}
package com.jf.modules.model.vo;
import com.jf.modules.model.Assess;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @Author yu.chen1
* @Description
* @Data 2024/5/14 16:39
**/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ConceptAllVo{
/**
* 场景描述
*/
private String sceneDescribe;
/**
* 业务痛点
*/
private String painPoints;
/**
* Ai能力
*/
private String aiAbility;
/**
* 概念名称
*/
private String conceptName;
/**
* AI代理的角色
*/
private String who;
/**
*解决方案
*/
private String solution;
/**
* 目标
*/
private String value;
/**
* 评估
*/
private Assess assess;
}
util类
package com.jf.common.utils;
import com.itextpdf.html2pdf.ConverterProperties;
import com.itextpdf.html2pdf.HtmlConverter;
import com.itextpdf.html2pdf.resolver.font.DefaultFontProvider;
import com.itextpdf.layout.font.FontProvider;
import com.jf.modules.model.Assess;
import com.jf.modules.model.vo.ConceptAllVo;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
import java.io.OutputStream;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
/**
* @Author yu.chen1
* @Description
* @Data 2024/5/13 10:33
**/
@Slf4j
public class FileTypeConvertUtil {
/**
* html转Pdf并导出
* @param conceptAllVo
* @param response
* @return
* @throws Exception
*/
public static OutputStream downloadPdf(ConceptAllVo conceptAllVo,HttpServletResponse response) throws Exception {
Assess assess = conceptAllVo.getAssess();
//为html模板替换的数据(将${}转成传过来的数据)
Map<String, Object> dataModel = new HashMap<>();
dataModel.put("sceneDescribe", conceptAllVo.getSceneDescribe());
dataModel.put("painPoints", conceptAllVo.getPainPoints());
dataModel.put("aiAbility", conceptAllVo.getAiAbility());
dataModel.put("conceptName", conceptAllVo.getConceptName());
dataModel.put("who", conceptAllVo.getWho());
dataModel.put("solution", conceptAllVo.getSolution());
dataModel.put("value", conceptAllVo.getValue());
dataModel.put("totalPoints", assess.getTotalPoints());
dataModel.put("costReduction", assess.getCostReduction());
dataModel.put("revenueEnhancement", assess.getRevenueEnhancement());
dataModel.put("topicInfluence", assess.getTopicInfluence());
dataModel.put("inputControllability", assess.getInputControllability());
dataModel.put("teamExcitement", assess.getTeamExcitement());
dataModel.put("realizableDegree", assess.getRealizableDegree());
// 设置响应字符编码为UTF-8
response.setCharacterEncoding("UTF-8");
// 设置响应内容类型
response.setContentType("application/pdf");
// 设置响应头
String encodedFileName = null;
try {
encodedFileName = URLEncoder.encode("创意卡片.pdf", "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
response.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + encodedFileName);
//将html转换为pdf
String htmlOutput = htmlToPdf(dataModel);
//从response获取最终输出流
OutputStream outputStream = response.getOutputStream();
// ConverterProperties是Apache POI库中的一个类,主要用于处理Excel、Word等Microsoft Office文档中的数据类型转换。
ConverterProperties properties = new ConverterProperties();
//设置字体
FontProvider fontProvider = new DefaultFontProvider(true, true, true);
properties.setFontProvider(fontProvider);
// 将html转换为pdf
HtmlConverter.convertToPdf(htmlOutput, outputStream, properties);
outputStream.close();
return outputStream;
}
/**
* 加载指定html模板并将数据填入html模板
* @param dataModel
* @return
* @throws TemplateException
* @throws IOException
*/
public static String htmlToPdf(Map dataModel) throws TemplateException, IOException {
// 初始化配置对象,设置模板加载的类和路径
Configuration cfg = new Configuration(Configuration.VERSION_2_3_31);
cfg.setClassForTemplateLoading(FileTypeConvertUtil.class, "/");
// 加载指定的模板文件
Template template = cfg.getTemplate("test.html");
// 使用StringWriter来收集模板处理后的结果
StringWriter writer = new StringWriter();
// 处理模板和数据模型,将结果写入到StringWriter中
template.process(dataModel, writer);
// 获取并返回处理后的HTML字符串
return writer.toString();
}
}
controller层
@RestController
@RequestMapping
public class AigcPromptWordsController {
/**
* 下载PDF
* @param response
* @param conceptAllVo
*/
@PostMapping(value = "/downloadPDF")
public void downloadPDF(HttpServletResponse response,@RequestBody ConceptAllVo conceptAllVo){
try {
FileTypeConvertUtil.downloadPdf(conceptAllVo,response);
} catch (Exception e) {
e.printStackTrace();
}
}
}
前端html模板
<!DOCTYPE html>
<html lang=en>
<head>
<meta charset=UTF-8>
<meta name=viewport content=width=device-width, initial-scale=1.0>
<title>Download PDF</title>
<style>
body {
font-family: '黑体', SimHei, STHeiti, sans-serif;
line-height: 0.6;
}
.container {
display: grid;
grid-template-columns: 1fr 1fr; /* 创建两列 */
grid-template-rows: auto auto auto; /* 创建三行 */
gap: 10px; /* 设置单元格之间的间隔 */
}
.item {
padding: 5px;
margin-bottom: 5px;
}
h1, h2, h3 {
color: #333;
}
p {
color: #666;
line-height: 1.6;
word-wrap: break-word;
overflow-wrap: break-word;
}
</style>
</head>
<body>
<h3>场景描述</h3>
<p>${sceneDescribe}</p>
<h3>面临的业务痛点</h3>
<p>${painPoints}</p>
<h3>使用AI能力</h3>
<p>${aiAbility}</p>
<h3>概念名称</h3>
<p>${conceptName}</p>
<h3>代理角色</h3>
<p>${who}</p>
<h3>解决方案</h3>
<p>${solution}</p>
<h3>目标</h3>
<p>${value}</p>
<div style="display: flex; align-items: center;">
<h3 style="flex: 1 0 50%;">评论</h3>
<p style="flex: 1 0 50%; text-align: left;">总分:${totalPoints}</p>
</div>
<div class=container>
<div class=item style="display:inline-block; font-size: 16px; color: #666;">对成本(人力/获客/运营等):${costReduction}</div>
<div class=item style="display:inline-block; font-size: 16px; color: #666;">对收益(流量/转化/效率)的提升:${revenueEnhancement}</div>
<div class=item style="display:inline-block; font-size: 16px; color: #666;"> 该概念可产生的话题影响力:${topicInfluence}</div>
<div class=item style="display:inline-block; font-size: 16px; color: #666;">投入(开发、迁移、培训等)是否可控:${inputControllability}</div>
<div class=item style="display:inline-block; font-size: 16px; color: #666;">团队对这个概念感到兴奋的程度:${teamExcitement}</div>
<div class=item style="display:inline-block; font-size: 16px; color: #666;">该概念可实现的程度:${realizableDegree}</div>
</div>
</body>
</html>