根据数据生成自定义pdf文档
根据数据生成自定义pdf文档
一、pdf工具类
package com.ruoyi.school.util;
import cn.hutool.core.map.MapUtil;
import com.itextpdf.html2pdf.ConverterProperties;
import com.itextpdf.html2pdf.HtmlConverter;
import com.itextpdf.html2pdf.resolver.font.DefaultFontProvider;
import com.itextpdf.io.font.PdfEncodings;
import com.itextpdf.io.image.ImageData;
import com.itextpdf.io.image.ImageDataFactory;
import com.itextpdf.kernel.colors.ColorConstants;
import com.itextpdf.kernel.colors.DeviceRgb;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.geom.PageSize;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.action.PdfAction;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.Style;
import com.itextpdf.layout.borders.Border;
import com.itextpdf.layout.element.*;
import com.itextpdf.layout.font.FontProvider;
import com.itextpdf.layout.property.AreaBreakType;
import com.itextpdf.layout.property.TextAlignment;
import com.itextpdf.layout.property.UnitValue;
import com.itextpdf.layout.property.VerticalAlignment;
import com.ruoyi.common.constant.SystemConfigConstants;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.RedisKeyUtil;
import com.ruoyi.common.utils.RedisUtils;
import com.ruoyi.school.domain.vo.*;
import com.ruoyi.school.domain.dto.*;
import com.ruoyi.school.service.IClassRecordDetailService;
import com.ruoyi.school.service.IClassRecordService;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.time.LocalDate;
import java.util.*;
import java.util.List;
/**
* @ClassName: pdfUtils
* @Description:
* @Author: 无泪之城-gzy
* @Date: 2024/11/5 10:46
*/
@Slf4j
@Component
public class PdfUtil {
@Value("${ruoyi.profile}")
private String filePath;
@Autowired
private RedisUtils redisUtils;
@Autowired
private IClassRecordDetailService classRecordDetailService;
@Autowired
private IClassRecordService classRecordService;
/**
* 创建阅读理解PDF文件
*
* @param response
* @param vo
* @throws IOException
*/
public void articleCreatePdf(HttpServletResponse response, ArticleDownloadVO vo) throws IOException {
String pdfPath = filePath + "/template/template.pdf";
// 加载中文字体
String fontPath = filePath + "/ttf/syht.ttf";
String ipaFontPath = filePath + "/ttf/DoulosSIL-Regular.ttf";
String fileName = "阅读理解习题";
if (vo.getTitle() != null) {
fileName = "阅读-" + vo.getTitle();
}
//文件名需要这样写,不能在setHeader直接写中文名,否则下载的文件名字为空,只有后缀
response.setCharacterEncoding("utf-8");
fileName = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".pdf");
try {
OutputStream out = response.getOutputStream();
PdfWriter writer = new PdfWriter(out);
PdfDocument pdf = new PdfDocument(writer);
Document document = new Document(pdf);
PdfFont chineseFont = PdfFontFactory.createFont(fontPath, PdfEncodings.IDENTITY_H, true);
PdfFont ipaFont = PdfFontFactory.createFont(ipaFontPath, PdfEncodings.IDENTITY_H, true);
//添加课程
if (vo.getCourseName() != null) {
Paragraph titleParagraph = new Paragraph(vo.getCourseName())
.setFont(chineseFont)
.setFontSize(15)
.setTextAlignment(TextAlignment.CENTER)//设置段落对齐方式为居中
.setBold();
document.add(titleParagraph);
}
//添加学习时间
if (vo.getBeginTime() != null && vo.getEndTime() != null && vo.getStudentName() != null) {
Paragraph titleParagraph = new Paragraph("学习时间: " + vo.getBeginTime() + "~" + vo.getEndTime() + " 学生姓名: " + vo.getStudentName())
.setFont(chineseFont)
.setFontSize(10)
.setTextAlignment(TextAlignment.CENTER)//设置段落对齐方式为居中
.setBold();
document.add(titleParagraph);
}
//添加标题,并使用中文字体
if (vo.getTitle() != null) {
Paragraph titleParagraph = new Paragraph(vo.getTitle())
.setFont(chineseFont)
.setFontSize(15)
.setTextAlignment(TextAlignment.CENTER)//设置段落对齐方式为居中
.setBold();
document.add(titleParagraph);
}
//添加来源
if (vo.getSource() != null) {
Paragraph titleParagraph = new Paragraph("(" + vo.getSource() + ")")
.setFont(chineseFont)
.setFontSize(10)
.setTextAlignment(TextAlignment.CENTER)//设置段落对齐方式为居中
.setBold();
document.add(titleParagraph);
}
//添加原文标题
Paragraph article = new Paragraph("【原文】:")
.setFont(chineseFont)
.setFontSize(15)
.setBold();
document.add(article);
//1.【原文内容】
document.add(new Paragraph(vo.getKnowledge()).setFontSize(10).setFont(chineseFont).setBold().setFirstLineIndent(20f));
//换行
document.add(new Paragraph("\n"));
//2.【习题】
Paragraph question = new Paragraph("【习题】:")
.setFont(chineseFont)
.setFontSize(15)
.setBold();
document.add(question);
// 遍历习题和答案列表,并添加到PDF中
if (vo.getArticleExerciseList() != null && !vo.getArticleExerciseList().isEmpty()) {
for (ArticleExerciseDownloadVO articleExerciseVO : vo.getArticleExerciseList()) {
// 添加问题
document.add(new Paragraph(articleExerciseVO.getNum() + "." + articleExerciseVO.getTitle() + "(" + articleExerciseVO.getAnswerType() + ")").setFontSize(12).setFont(chineseFont).setBold());
// 添加习题选项-todo 注意这里,习题选项有可能是图片,需要判断下
if (articleExerciseVO.getArticleExerciseOptionList() != null) {
for (ArticleExerciseOptionDownloadVO articleExerciseOptionVO : articleExerciseVO.getArticleExerciseOptionList()) {
document.add(new Paragraph(articleExerciseOptionVO.getXtOption() + "、" + articleExerciseOptionVO.getEnMsg()).setFontSize(10).setFont(chineseFont).setBold());
}
}
}
}
//3.【重点词汇】
if (vo.getArticleKeyWordList() != null) {
document.add(new Paragraph("\n"));//换行
Paragraph keyWord = new Paragraph("【重点词汇】:")
.setFont(chineseFont)
.setFontSize(15)
.setBold();
document.add(keyWord);
int keyWordNum = 1;
for (NewArticleKeyWordDTO newArticleKeyWordDTO : vo.getArticleKeyWordList()) {
//合并单词中文内容和音标内容到一行显示(音标和中文的字体不同)
Paragraph paragraph = new Paragraph();
paragraph.add(new Text(keyWordNum + ". " + newArticleKeyWordDTO.getWord() + " ")
.setFontSize(12)
.setFont(chineseFont)
.setBold());
paragraph.add(new Text(newArticleKeyWordDTO.getIpa() + " ")
.setFontSize(12)
.setFont(ipaFont)
.setBold());
paragraph.add(new Text("释义:" + newArticleKeyWordDTO.getZh() + " ")
.setFontSize(12)
.setFont(chineseFont)
.setBold());
document.add(paragraph);
document.add(new Paragraph("单词所属原文:" + newArticleKeyWordDTO.getOriginalSentence()).setFontSize(10).setFont(chineseFont).setBold());
document.add(new Paragraph("单词所属原文翻译:" + newArticleKeyWordDTO.getOriginalSentenceTranslation()).setFontSize(10).setFont(chineseFont).setBold());
keyWordNum++;
}
}
//4.【变形词汇】
if (vo.getArticleYxWordList() != null) {
document.add(new Paragraph("\n"));//换行
Paragraph bxWord = new Paragraph("【变形词汇】:")
.setFont(chineseFont)
.setFontSize(15)
.setBold();
document.add(bxWord);
int yxWordNum = 1;
for (NewArticleYxWordDTO newArticleYxWordDTO : vo.getArticleYxWordList()) {
Paragraph paragraph = new Paragraph();
paragraph.add(new Text(yxWordNum + ". " + newArticleYxWordDTO.getWord() + " ")
.setFontSize(12)
.setFont(chineseFont)
.setBold());
paragraph.add(new Text(newArticleYxWordDTO.getIpa() + " ")
.setFontSize(12)
.setFont(ipaFont)
.setBold());
paragraph.add(new Text("释义:" + newArticleYxWordDTO.getZh() + " ")
.setFontSize(12)
.setFont(chineseFont)
.setBold());
document.add(paragraph);
if (newArticleYxWordDTO.getArticleBxWordList() != null) {
int bxWordNum = 1;
Paragraph bxTitle = new Paragraph("变形:")
.setFont(chineseFont)
.setFontSize(12)
.setBold();
document.add(bxTitle);
for (NewArticleBxWordDTO newArticleBxWordDTO : newArticleYxWordDTO.getArticleBxWordList()) {
Paragraph bxWordParagraph = new Paragraph();
bxWordParagraph.add(new Text(bxWordNum + ". " + newArticleBxWordDTO.getWord() + " ")
.setFontSize(12)
.setFont(chineseFont)
.setBold());
bxWordParagraph.add(new Text(newArticleBxWordDTO.getIpa() + " ")
.setFontSize(12)
.setFont(ipaFont)
.setBold());
bxWordParagraph.add(new Text("释义:" + newArticleBxWordDTO.getZh() + " ")
.setFontSize(12)
.setFont(chineseFont)
.setBold());
document.add(bxWordParagraph);
bxWordNum++;
}
}
yxWordNum++;
}
}
//5.【长难句】
if (vo.getArticleSentenceList() != null) {
document.add(new Paragraph("\n"));//换行
Paragraph sentence = new Paragraph("【长难句】:")
.setFont(chineseFont)
.setFontSize(15)
.setBold();
document.add(sentence);
int sentenceNum = 1;
for (NewArticleSentenceDTO newArticleSentenceDTO : vo.getArticleSentenceList()) {
document.add(new Paragraph(sentenceNum + ". " + newArticleSentenceDTO.getSentence()).setFontSize(12).setFont(chineseFont).setBold());
document.add(new Paragraph("翻译:" + newArticleSentenceDTO.getSentenceZh()).setFontSize(12).setFont(chineseFont).setBold());
if (newArticleSentenceDTO.getSentenceList() != null) {
List<NewArticleSentenceAssociationDTO> zgSentenceList = new ArrayList<>();
List<NewArticleSentenceAssociationDTO> cjSentenceList = new ArrayList<>();
List<NewArticleSentenceAssociationDTO> phraseList = new ArrayList<>();
List<NewArticleSentenceAssociationDTO> tenseList = new ArrayList<>();
for (NewArticleSentenceAssociationDTO newArticleSentenceAssociationDTO : newArticleSentenceDTO.getSentenceList()) {
switch (newArticleSentenceAssociationDTO.getType()) {
case 0:
zgSentenceList.add(newArticleSentenceAssociationDTO);
break;
case 1:
cjSentenceList.add(newArticleSentenceAssociationDTO);
break;
case 2:
phraseList.add(newArticleSentenceAssociationDTO);
break;
case 3:
tenseList.add(newArticleSentenceAssociationDTO);
break;
}
}
if (zgSentenceList != null) {
document.add(new Paragraph("———————————————————————主干———————————————————————")
.setFont(chineseFont)
.setFontSize(12)
.setBold());
int zgSentenceNum = 1;
for (NewArticleSentenceAssociationDTO newArticleSentenceAssociationDTO : zgSentenceList) {
document.add(new Paragraph(zgSentenceNum + ". " + newArticleSentenceAssociationDTO.getSentence()).setFontSize(12).setFont(chineseFont).setBold());
document.add(new Paragraph("拆解: " + newArticleSentenceAssociationDTO.getSentenceBreakdown()).setFontSize(12).setFont(chineseFont).setBold());
document.add(new Paragraph("解析: " + newArticleSentenceAssociationDTO.getSentenceZh()).setFontSize(12).setFont(chineseFont).setBold());
zgSentenceNum++;
}
}
if (cjSentenceList != null) {
document.add(new Paragraph("———————————————————————从句———————————————————————")
.setFont(chineseFont)
.setFontSize(12)
.setBold());
int cjSentenceNum = 1;
for (NewArticleSentenceAssociationDTO newArticleSentenceAssociationDTO : cjSentenceList) {
document.add(new Paragraph(cjSentenceNum + ". " + newArticleSentenceAssociationDTO.getSentence()).setFontSize(12).setFont(chineseFont).setBold());
document.add(new Paragraph("拆解: " + newArticleSentenceAssociationDTO.getSentenceBreakdown()).setFontSize(12).setFont(chineseFont).setBold());
document.add(new Paragraph("解析: " + newArticleSentenceAssociationDTO.getSentenceZh()).setFontSize(12).setFont(chineseFont).setBold());
cjSentenceNum++;
}
}
if (phraseList != null) {
document.add(new Paragraph("———————————————————————词组———————————————————————")
.setFont(chineseFont)
.setFontSize(12)
.setBold());
int phraseNum = 1;
for (NewArticleSentenceAssociationDTO newArticleSentenceAssociationDTO : phraseList) {
document.add(new Paragraph(phraseNum + ". " + newArticleSentenceAssociationDTO.getPhrase() + " 翻译:" + newArticleSentenceAssociationDTO.getPhraseZh()).setFontSize(12).setFont(chineseFont).setBold());
phraseNum++;
}
}
if (tenseList != null) {
document.add(new Paragraph("———————————————————————时态———————————————————————")
.setFont(chineseFont)
.setFontSize(12)
.setBold());
int tenseNum = 1;
for (NewArticleSentenceAssociationDTO newArticleSentenceAssociationDTO : tenseList) {
document.add(new Paragraph(tenseNum + ". " + newArticleSentenceAssociationDTO.getTense()).setFontSize(12).setFont(chineseFont).setBold());
tenseNum++;
}
}
}
sentenceNum++;
}
}
//6.【重点语法】
if (vo.getArticleGrammarList() != null) {
document.add(new Paragraph("\n"));//换行
document.add(new Paragraph("【重点语法】:")
.setFont(chineseFont)
.setFontSize(15)
.setBold());
int grammarNum = 1;
for (NewArticleGrammarDTO newArticleGrammarDTO : vo.getArticleGrammarList()) {
document.add(new Paragraph(grammarNum + ". " + newArticleGrammarDTO.getGrammar()).setFontSize(12).setFont(chineseFont).setBold());
document.add(new Paragraph(" 解析:" + newArticleGrammarDTO.getGrammarZh()).setFontSize(12).setFont(chineseFont).setBold());
grammarNum++;
}
}
//7.【生词】
if (vo.getRareWordsList() != null) {
document.add(new Paragraph("\n"));//换行
Paragraph keyWord = new Paragraph("【生词】:")
.setFont(chineseFont)
.setFontSize(15)
.setBold();
document.add(keyWord);
int keyWordNum = 1;
for (NewRareWordsVO newRareWordsVO : vo.getRareWordsList()) {
//合并单词中文内容和音标内容到一行显示(音标和中文的字体不同)
Paragraph paragraph = new Paragraph();
paragraph.add(new Text(keyWordNum + ". " + newRareWordsVO.getWord() + " ")
.setFontSize(12)
.setFont(chineseFont)
.setBold());
paragraph.add(new Text(newRareWordsVO.getIpa() + " ")
.setFontSize(12)
.setFont(ipaFont)
.setBold());
paragraph.add(new Text("释义:" + newRareWordsVO.getZh() + " ")
.setFontSize(12)
.setFont(chineseFont)
.setBold());
document.add(paragraph);
document.add(new Paragraph("单词所属原文:" + newRareWordsVO.getOriginalSentence()).setFontSize(10).setFont(chineseFont).setBold());
document.add(new Paragraph("单词所属原文翻译:" + newRareWordsVO.getOriginalSentenceTranslation()).setFontSize(10).setFont(chineseFont).setBold());
keyWordNum++;
}
}
// 加载图片
// 假设图片位于项目的资源目录中
// String imagePath = filePath+"/upload/2024/11/27/IMG2_20241127183326A001.png";
// ImageData imageData = ImageDataFactory.create(imagePath);
// // 创建图片对象
// Image image = new Image(imageData);
// // 可选:设置图片的大小、位置等属性
// image.scaleToFit(100, 100); // 例如,将图片缩放到100x100大小
// // image.setFixedPosition(100, 500); // 例如,将图片固定在页面的特定位置
// // 将图片添加到文档中
// document.add(image);
document.close();
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 创建完型PDF文件
*
* @param response
* @param vo
* @throws IOException
*/
public void gestaltCreatePdf(HttpServletResponse response, GestaltDownloadVO vo) throws IOException {
String pdfPath = filePath + "/template/template.pdf";
// 加载中文字体
String fontPath = filePath + "/ttf/syht.ttf";
String ipaFontPath = filePath + "/ttf/DoulosSIL-Regular.ttf";
String fileName = "完型填空习题";
if (vo.getTitle() != null) {
fileName = "完型-" + vo.getTitle();
}
//文件名需要这样写,不能在setHeader直接写中文名,否则下载的文件名字为空,只有后缀
response.setCharacterEncoding("utf-8");
fileName = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".pdf");
try {
OutputStream out = response.getOutputStream();
PdfWriter writer = new PdfWriter(out);
PdfDocument pdf = new PdfDocument(writer);
Document document = new Document(pdf);
PdfFont chineseFont = PdfFontFactory.createFont(fontPath, PdfEncodings.IDENTITY_H, true);
PdfFont ipaFont = PdfFontFactory.createFont(ipaFontPath, PdfEncodings.IDENTITY_H, true);
//添加标题,并使用中文字体
if (vo.getTitle() != null) {
Paragraph titleParagraph = new Paragraph(vo.getTitle())
.setFont(chineseFont)
.setFontSize(15)
.setTextAlignment(TextAlignment.CENTER)//设置段落对齐方式为居中
.setBold();
document.add(titleParagraph);
}
//添加课程名称,并使用中文字体
if (vo.getCourseName() != null) {
Paragraph titleParagraph = new Paragraph(vo.getCourseName())
.setFont(chineseFont)
.setFontSize(15)
.setTextAlignment(TextAlignment.CENTER)//设置段落对齐方式为居中
.setBold();
document.add(titleParagraph);
}
//添加学习时间
if (vo.getBeginTime() != null && vo.getEndTime() != null && vo.getStudentName() != null) {
Paragraph titleParagraph = new Paragraph("学习时间: " + vo.getBeginTime() + "~" + vo.getEndTime() + " 学生姓名: " + vo.getStudentName())
.setFont(chineseFont)
.setFontSize(10)
.setTextAlignment(TextAlignment.CENTER)//设置段落对齐方式为居中
.setBold();
document.add(titleParagraph);
}
//添加来源
if (vo.getSource() != null) {
Paragraph titleParagraph = new Paragraph("(" + vo.getSource() + ")")
.setFont(chineseFont)
.setFontSize(10)
.setTextAlignment(TextAlignment.CENTER)//设置段落对齐方式为居中
.setBold();
document.add(titleParagraph);
}
//添加原文标题
Paragraph article = new Paragraph("原文:")
.setFont(chineseFont)
.setFontSize(15)
.setBold();
document.add(article);
//添加原文内容
document.add(new Paragraph(vo.getKnowledge()).setFontSize(10).setFont(chineseFont).setBold().setFirstLineIndent(20f));
//换行
document.add(new Paragraph("\n"));
//添加习题标题
Paragraph question = new Paragraph("习题:")
.setFont(chineseFont)
.setFontSize(15)
.setBold();
document.add(question);
// 遍历习题和答案列表,并添加到PDF中
if (vo.getGestaltExerciseList() != null && !vo.getGestaltExerciseList().isEmpty()) {
for (GestaltExerciseDownloadVO gestaltExerciseVO : vo.getGestaltExerciseList()) {
// 添加序号
String num = gestaltExerciseVO.getNum() + ". ";
// 添加习题选项
List<String> stringList = new ArrayList<>();
if (gestaltExerciseVO.getGestaltExerciseOptionList() != null) {
for (GestaltExerciseOptionDownloadVO gestaltExerciseOptionVO : gestaltExerciseVO.getGestaltExerciseOptionList()) {
String option = "";
if (gestaltExerciseOptionVO.getXtOption().equals("A")) {
option = num + gestaltExerciseOptionVO.getXtOption() + "、" + gestaltExerciseOptionVO.getEnMsg();
} else {
option = gestaltExerciseOptionVO.getXtOption() + "、" + gestaltExerciseOptionVO.getEnMsg();
}
stringList.add(option);
}
}
Paragraph paragraph = new Paragraph();
for (String s : stringList) {
paragraph.add(s + " ");
}
document.add(paragraph.setFontSize(10).setFont(chineseFont).setBold());
}
}
//3.【重点词汇】
if (vo.getGestaltKeyWordList() != null) {
document.add(new Paragraph("\n"));//换行
Paragraph keyWord = new Paragraph("【重点词汇】:")
.setFont(chineseFont)
.setFontSize(15)
.setBold();
document.add(keyWord);
int keyWordNum = 1;
for (NewGestaltKeyWordDTO newGestaltKeyWordDTO : vo.getGestaltKeyWordList()) {
//合并单词中文内容和音标内容到一行显示(音标和中文的字体不同)
Paragraph paragraph = new Paragraph();
paragraph.add(new Text(keyWordNum + ". " + newGestaltKeyWordDTO.getWord() + " ")
.setFontSize(12)
.setFont(chineseFont)
.setBold());
paragraph.add(new Text(newGestaltKeyWordDTO.getIpa() + " ")
.setFontSize(12)
.setFont(ipaFont)
.setBold());
paragraph.add(new Text("释义:" + newGestaltKeyWordDTO.getZh() + " ")
.setFontSize(12)
.setFont(chineseFont)
.setBold());
document.add(paragraph);
document.add(new Paragraph("单词所属原文:" + newGestaltKeyWordDTO.getOriginalSentence()).setFontSize(10).setFont(chineseFont).setBold());
document.add(new Paragraph("单词所属原文翻译:" + newGestaltKeyWordDTO.getOriginalSentenceTranslation()).setFontSize(10).setFont(chineseFont).setBold());
keyWordNum++;
}
}
//4.【变形词汇】
if (vo.getGestaltYxWordList() != null) {
document.add(new Paragraph("\n"));//换行
Paragraph bxWord = new Paragraph("【变形词汇】:")
.setFont(chineseFont)
.setFontSize(15)
.setBold();
document.add(bxWord);
int yxWordNum = 1;
for (NewGestaltYxWordDTO newGestaltYxWordDTO : vo.getGestaltYxWordList()) {
Paragraph paragraph = new Paragraph();
paragraph.add(new Text(yxWordNum + ". " + newGestaltYxWordDTO.getWord() + " ")
.setFontSize(12)
.setFont(chineseFont)
.setBold());
paragraph.add(new Text(newGestaltYxWordDTO.getIpa() + " ")
.setFontSize(12)
.setFont(ipaFont)
.setBold());
paragraph.add(new Text("释义:" + newGestaltYxWordDTO.getZh() + " ")
.setFontSize(12)
.setFont(chineseFont)
.setBold());
document.add(paragraph);
if (newGestaltYxWordDTO.getGestaltBxWordList() != null) {
int bxWordNum = 1;
Paragraph bxTitle = new Paragraph("变形:")
.setFont(chineseFont)
.setFontSize(12)
.setBold();
document.add(bxTitle);
for (NewGestaltBxWordDTO newGestaltBxWordDTO : newGestaltYxWordDTO.getGestaltBxWordList()) {
Paragraph bxWordParagraph = new Paragraph();
bxWordParagraph.add(new Text(bxWordNum + ". " + newGestaltBxWordDTO.getWord() + " ")
.setFontSize(12)
.setFont(chineseFont)
.setBold());
bxWordParagraph.add(new Text(newGestaltBxWordDTO.getIpa() + " ")
.setFontSize(12)
.setFont(ipaFont)
.setBold());
bxWordParagraph.add(new Text("释义:" + newGestaltBxWordDTO.getZh() + " ")
.setFontSize(12)
.setFont(chineseFont)
.setBold());
bxWordParagraph.add(new Text("时态:" + newGestaltBxWordDTO.getTense() + " ")
.setFontSize(12)
.setFont(chineseFont)
.setBold());
document.add(bxWordParagraph);
bxWordNum++;
}
}
yxWordNum++;
}
}
//5.【长难句】
if (vo.getGestaltSentenceList() != null) {
document.add(new Paragraph("\n"));//换行
Paragraph sentence = new Paragraph("【长难句】:")
.setFont(chineseFont)
.setFontSize(15)
.setBold();
document.add(sentence);
int sentenceNum = 1;
for (NewGestaltSentenceDTO newGestaltSentenceDTO : vo.getGestaltSentenceList()) {
document.add(new Paragraph(sentenceNum + ". " + newGestaltSentenceDTO.getSentence()).setFontSize(12).setFont(chineseFont).setBold());
document.add(new Paragraph("翻译:" + newGestaltSentenceDTO.getSentenceZh()).setFontSize(12).setFont(chineseFont).setBold());
if (newGestaltSentenceDTO.getSentenceList() != null) {
List<NewGestaltSentenceAssociationDTO> zgSentenceList = new ArrayList<>();
List<NewGestaltSentenceAssociationDTO> cjSentenceList = new ArrayList<>();
List<NewGestaltSentenceAssociationDTO> phraseList = new ArrayList<>();
List<NewGestaltSentenceAssociationDTO> tenseList = new ArrayList<>();
for (NewGestaltSentenceAssociationDTO newGestaltSentenceAssociationDTO : newGestaltSentenceDTO.getSentenceList()) {
switch (newGestaltSentenceAssociationDTO.getType()) {
case 0:
zgSentenceList.add(newGestaltSentenceAssociationDTO);
break;
case 1:
cjSentenceList.add(newGestaltSentenceAssociationDTO);
break;
case 2:
phraseList.add(newGestaltSentenceAssociationDTO);
break;
case 3:
tenseList.add(newGestaltSentenceAssociationDTO);
break;
}
}
if (zgSentenceList != null) {
document.add(new Paragraph("———————————————————————主干———————————————————————")
.setFont(chineseFont)
.setFontSize(12)
.setBold());
int zgSentenceNum = 1;
for (NewGestaltSentenceAssociationDTO newGestaltSentenceAssociationDTO : zgSentenceList) {
document.add(new Paragraph(zgSentenceNum + ". " + newGestaltSentenceAssociationDTO.getSentence()).setFontSize(12).setFont(chineseFont).setBold());
document.add(new Paragraph("拆解: " + newGestaltSentenceAssociationDTO.getSentenceBreakdown()).setFontSize(12).setFont(chineseFont).setBold());
document.add(new Paragraph("解析: " + newGestaltSentenceAssociationDTO.getSentenceZh()).setFontSize(12).setFont(chineseFont).setBold());
zgSentenceNum++;
}
}
if (cjSentenceList != null) {
document.add(new Paragraph("———————————————————————从句———————————————————————")
.setFont(chineseFont)
.setFontSize(12)
.setBold());
int cjSentenceNum = 1;
for (NewGestaltSentenceAssociationDTO newGestaltSentenceAssociationDTO : cjSentenceList) {
document.add(new Paragraph(cjSentenceNum + ". " + newGestaltSentenceAssociationDTO.getSentence()).setFontSize(12).setFont(chineseFont).setBold());
document.add(new Paragraph("拆解: " + newGestaltSentenceAssociationDTO.getSentenceBreakdown()).setFontSize(12).setFont(chineseFont).setBold());
document.add(new Paragraph("解析: " + newGestaltSentenceAssociationDTO.getSentenceZh()).setFontSize(12).setFont(chineseFont).setBold());
cjSentenceNum++;
}
}
if (phraseList != null) {
document.add(new Paragraph("———————————————————————词组———————————————————————")
.setFont(chineseFont)
.setFontSize(12)
.setBold());
int phraseNum = 1;
for (NewGestaltSentenceAssociationDTO newGestaltSentenceAssociationDTO : phraseList) {
document.add(new Paragraph(phraseNum + ". " + newGestaltSentenceAssociationDTO.getPhrase() + " 翻译:" + newGestaltSentenceAssociationDTO.getPhraseZh()).setFontSize(12).setFont(chineseFont).setBold());
phraseNum++;
}
}
if (tenseList != null) {
document.add(new Paragraph("———————————————————————时态———————————————————————")
.setFont(chineseFont)
.setFontSize(12)
.setBold());
int tenseNum = 1;
for (NewGestaltSentenceAssociationDTO newGestaltSentenceAssociationDTO : tenseList) {
document.add(new Paragraph(tenseNum + ". " + newGestaltSentenceAssociationDTO.getTense()).setFontSize(12).setFont(chineseFont).setBold());
tenseNum++;
}
}
}
sentenceNum++;
}
}
//6.【重点语法】
if (vo.getGestaltGrammarList() != null) {
document.add(new Paragraph("\n"));//换行
document.add(new Paragraph("【重点语法】:")
.setFont(chineseFont)
.setFontSize(15)
.setBold());
int grammarNum = 1;
for (NewGestaltGrammarDTO newGestaltGrammarDTO : vo.getGestaltGrammarList()) {
document.add(new Paragraph(grammarNum + ". " + newGestaltGrammarDTO.getGrammar()).setFontSize(12).setFont(chineseFont).setBold());
document.add(new Paragraph(" 解析:" + newGestaltGrammarDTO.getGrammarZh()).setFontSize(12).setFont(chineseFont).setBold());
grammarNum++;
}
}
// 加载图片
// 假设图片位于项目的资源目录中
// String imagePath = filePath+"/upload/2024/11/27/IMG2_20241127183326A001.png";
// ImageData imageData = ImageDataFactory.create(imagePath);
// // 创建图片对象
// Image image = new Image(imageData);
// // 可选:设置图片的大小、位置等属性
// image.scaleToFit(100, 100); // 例如,将图片缩放到100x100大小
// // image.setFixedPosition(100, 500); // 例如,将图片固定在页面的特定位置
// // 将图片添加到文档中
// document.add(image);
document.close();
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 创建单词识记PDF文件
*
* @param response
* @param vo
*/
public void wordCreatePdf(HttpServletResponse response, WordDownloadVO vo) throws Exception {
// 加载中文字体
String fontPath = filePath + "/ttf/syht.ttf";
// 加载音标字体
String ipaFontPath = filePath + "/ttf/DoulosSIL-Regular.ttf";
String fileName = "单词识记";
if (vo.getCourseName() != null && vo.getCourseName() != "") {
fileName = "单词识记-" + vo.getCourseName();
}
//文件名需要这样写,不能在setHeader直接写中文名,否则下载的文件名字为空,只有后缀
response.setCharacterEncoding("utf-8");
fileName = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".pdf");
try {
OutputStream out = response.getOutputStream();
PdfWriter writer = new PdfWriter(out);
PdfDocument pdf = new PdfDocument(writer);
Document document = new Document(pdf);
PdfFont chineseFont = PdfFontFactory.createFont(fontPath, PdfEncodings.IDENTITY_H, true);
PdfFont ipaFont = PdfFontFactory.createFont(ipaFontPath, PdfEncodings.IDENTITY_H, true);
//添加标题,并使用中文字体
if (vo.getCourseName() != null) {
Paragraph titleParagraph = new Paragraph(vo.getCourseName())
.setFont(chineseFont)
.setFontSize(15)
.setTextAlignment(TextAlignment.CENTER)//设置段落对齐方式为居中
.setBold();
document.add(titleParagraph);
}
//添加学习时间
if (vo.getBeginTime() != null && vo.getEndTime() != null && vo.getStudentName() != null) {
Paragraph titleParagraph = new Paragraph("学习时间: " + vo.getBeginTime() + "~" + vo.getEndTime() + " 学生姓名: " + vo.getStudentName())
.setFont(chineseFont)
.setFontSize(10)
.setTextAlignment(TextAlignment.CENTER)//设置段落对齐方式为居中
.setBold();
document.add(titleParagraph);
}
//【第二部分】
//设计日期表格
// 创建复习计划表格(固定列宽比例 1:3:2)
Table reviewTable = new Table(new float[]{30f, 25f, 25f, 25f, 25f, 25f, 25f, 25f, 25f, 25f, 25f})
.useAllAvailableWidth()
.setTextAlignment(TextAlignment.CENTER)
.setFixedLayout();
// 定义表头样式
Style headerStyle = new Style()
.setFont(chineseFont)
.setFontSize(10)
.setTextAlignment(TextAlignment.CENTER)
.setBold()
.setPadding(5);
// 定义单元格样式
Style dateCellStyle = new Style()
.setFont(chineseFont)
.setFontSize(10)
.setTextAlignment(TextAlignment.CENTER)
.setVerticalAlignment(VerticalAlignment.MIDDLE) // 垂直居中(关键!)
.setBold()
.setPadding(5);
// 添加表头-
reviewTable.addHeaderCell(new Cell().add(new Paragraph("第几天").addStyle(headerStyle)));
reviewTable.addHeaderCell(new Cell().add(new Paragraph("1").addStyle(headerStyle)));
reviewTable.addHeaderCell(new Cell().add(new Paragraph("2").addStyle(headerStyle)));
reviewTable.addHeaderCell(new Cell().add(new Paragraph("3").addStyle(headerStyle)));
reviewTable.addHeaderCell(new Cell().add(new Paragraph("5").addStyle(headerStyle)));
reviewTable.addHeaderCell(new Cell().add(new Paragraph("7").addStyle(headerStyle)));
reviewTable.addHeaderCell(new Cell().add(new Paragraph("9").addStyle(headerStyle)));
reviewTable.addHeaderCell(new Cell().add(new Paragraph("12").addStyle(headerStyle)));
reviewTable.addHeaderCell(new Cell().add(new Paragraph("14").addStyle(headerStyle)));
reviewTable.addHeaderCell(new Cell().add(new Paragraph("17").addStyle(headerStyle)));
reviewTable.addHeaderCell(new Cell().add(new Paragraph("21").addStyle(headerStyle)));
// 添加数据行
reviewTable.addCell(new Cell().add(new Paragraph("复习日期").addStyle(headerStyle)));
if (vo.getAntiForgetDateList() != null && !vo.getAntiForgetDateList().isEmpty()) {
for (int i = 0; i < vo.getAntiForgetDateList().size(); i++) {
String date = vo.getAntiForgetDateList().get(i);
reviewTable.addCell(new Cell().setVerticalAlignment(VerticalAlignment.MIDDLE).add(new Paragraph(date).addStyle(dateCellStyle)));
}
}
reviewTable.addCell(new Cell().add(new Paragraph("遗忘词数").addStyle(headerStyle)));
for (int i = 0; i < 10; i++) {
String data = "";
reviewTable.addCell(new Cell().add(new Paragraph(data).addStyle(dateCellStyle)));
}
document.add(new Paragraph("单词复习计划表").setFont(chineseFont).setBold().setFontSize(12));
document.add(reviewTable);
//添加标题
Paragraph title = new Paragraph("今日识记: " + vo.getWordTotal() + " 正确: " + vo.getRightTotal() + " 遗忘: " + vo.getWrongTotal())
.setFont(chineseFont)
.setFontSize(10)
.setTextAlignment(TextAlignment.LEFT)//设置段落对齐方式为左对齐
.setBold();
document.add(title);
if (vo.getWordList() != null) {
//【第一部分】
// 创建表格并设置列宽比例(1:2:2)
// Table table = new Table(new float[]{8f, 46f, 46f})
Table table = new Table(new float[]{25f, 25f, 25f,25f,25f,25f})
.useAllAvailableWidth()
.setTextAlignment(TextAlignment.LEFT)
.setFixedLayout(); // 关键:强制固定布局,确保比例生效
// 定义单元格样式
Style cellStyle = new Style()
.setFont(chineseFont)
.setFontSize(12)
.setBold()
.setTextAlignment(TextAlignment.CENTER)
.setPadding(5); // 添加内边距使表格更美观
// 遍历单词列表
for (int i = 0; i < vo.getWordList().size(); i += 3) {
WordDownloadListVO wordVO = vo.getWordList().get(i);
Cell wordCell = new Cell();
Cell infoCell = new Cell();
//同行第二个单词
Cell wordCell2 = new Cell();
Cell infoCell2 = new Cell();
//同行第三个单词
Cell wordCell3 = new Cell();
Cell infoCell3 = new Cell();
switch (vo.getPrintType()) {
case 0://打印中文
wordCell.add(new Paragraph("").addStyle(cellStyle));
if (wordVO.getZh()!=null){
infoCell.add(new Paragraph().add(new Paragraph(wordVO.getZh()).setFont(chineseFont).setFontSize(12).setBold()).setTextAlignment(TextAlignment.CENTER));
}
table.addCell(wordCell);
table.addCell(infoCell);
if (i+1<vo.getWordList().size()){
WordDownloadListVO wordVO2 =vo.getWordList().get(i+1);
wordCell2.add(new Paragraph("").addStyle(cellStyle));
if (wordVO2.getZh()!=null){
infoCell2.add(new Paragraph().add(new Paragraph(wordVO2.getZh()).setFont(chineseFont).setFontSize(12).setBold()).setTextAlignment(TextAlignment.CENTER));
}
table.addCell(wordCell2);
table.addCell(infoCell2);
}
if (i+2<vo.getWordList().size()){
WordDownloadListVO wordVO3 = vo.getWordList().get(i+2);
wordCell3.add(new Paragraph("").addStyle(cellStyle));
if (wordVO3.getZh()!=null){
infoCell3.add(new Paragraph().add(new Paragraph(wordVO3.getZh()).setFont(chineseFont).setFontSize(12).setBold()).setTextAlignment(TextAlignment.CENTER));
}
table.addCell(wordCell3);
table.addCell(infoCell3);
}
break;
case 1://打印英文
wordCell.add(new Paragraph(wordVO.getWord()).addStyle(cellStyle));
infoCell.add(new Paragraph().add(new Paragraph("").setFont(chineseFont).setFontSize(12).setBold()).setTextAlignment(TextAlignment.CENTER));
table.addCell(wordCell);
table.addCell(infoCell);
if (i+1<vo.getWordList().size()){
WordDownloadListVO wordVO2 =vo.getWordList().get(i+1);
wordCell2.add(new Paragraph(wordVO2.getWord()).addStyle(cellStyle));
infoCell2.add(new Paragraph().add(new Paragraph("").setFont(chineseFont).setFontSize(12).setBold()).setTextAlignment(TextAlignment.CENTER));
table.addCell(wordCell2);
table.addCell(infoCell2);
}
if (i+2<vo.getWordList().size()){
WordDownloadListVO wordVO3 = vo.getWordList().get(i+2);
wordCell3.add(new Paragraph(wordVO3.getWord()).addStyle(cellStyle));
infoCell3.add(new Paragraph().add(new Paragraph("").setFont(chineseFont).setFontSize(12).setBold()).setTextAlignment(TextAlignment.CENTER));
table.addCell(wordCell3);
table.addCell(infoCell3);
}
break;
case 2://打印中英文
wordCell.add(new Paragraph(wordVO.getWord()).addStyle(cellStyle));
if (wordVO.getZh()!=null){
infoCell.add(new Paragraph().add(new Paragraph(wordVO.getZh()).setFont(chineseFont).setFontSize(12).setBold()).setTextAlignment(TextAlignment.CENTER));
}
table.addCell(wordCell);
table.addCell(infoCell);
if (i+1<vo.getWordList().size()){
WordDownloadListVO wordVO2 =vo.getWordList().get(i+1);
wordCell2.add(new Paragraph(wordVO2.getWord()).addStyle(cellStyle));
if (wordVO2.getZh()!=null){
infoCell2.add(new Paragraph().add(new Paragraph(wordVO2.getZh()).setFont(chineseFont).setFontSize(12).setBold()).setTextAlignment(TextAlignment.CENTER));
}
table.addCell(wordCell2);
table.addCell(infoCell2);
}
if (i+2<vo.getWordList().size()){
WordDownloadListVO wordVO3 = vo.getWordList().get(i+2);
wordCell3.add(new Paragraph(wordVO3.getWord()).addStyle(cellStyle));
if (wordVO3.getZh()!=null){
infoCell3.add(new Paragraph().add(new Paragraph(wordVO3.getZh()).setFont(chineseFont).setFontSize(12).setBold()).setTextAlignment(TextAlignment.CENTER));
}
table.addCell(wordCell3);
table.addCell(infoCell3);
}
break;
case 3://打印音标
wordCell.add(new Paragraph(wordVO.getWord()).addStyle(cellStyle));
String ipa ="";
if (wordVO.getIpa()!=null){
ipa=wordVO.getIpa();
infoCell.add(new Paragraph().add(new Text(ipa).setFont(ipaFont).setFontSize(12).setBold()).setTextAlignment(TextAlignment.CENTER));
}
table.addCell(wordCell);
table.addCell(infoCell);
if (i+1<vo.getWordList().size()){
WordDownloadListVO wordVO2 =vo.getWordList().get(i+1);
wordCell2.add(new Paragraph(wordVO2.getWord()).addStyle(cellStyle));
if (wordVO2.getIpa()!=null){
ipa=wordVO2.getIpa();
infoCell2.add(new Paragraph().add(new Text(ipa).setFont(ipaFont).setFontSize(12).setBold()).setTextAlignment(TextAlignment.CENTER));
}
table.addCell(wordCell2);
table.addCell(infoCell2);
}
if (i+2<vo.getWordList().size()){
WordDownloadListVO wordVO3 = vo.getWordList().get(i+2);
wordCell3.add(new Paragraph(wordVO3.getWord()).addStyle(cellStyle));
if (wordVO3.getIpa()!=null){
ipa=wordVO3.getIpa();
infoCell3.add(new Paragraph().add(new Text(ipa).setFont(ipaFont).setFontSize(12).setBold()).setTextAlignment(TextAlignment.CENTER));
}
table.addCell(wordCell3);
table.addCell(infoCell3);
}
break;
}
}
// 将表格添加到文档
document.add(table);
}
document.close();
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 创建听力PDF文件
*
* @param response
* @param vo
* @throws IOException
*/
public void hearingCreatePdf(HttpServletResponse response, NewHearingDownloadVO vo) throws IOException {
String pdfPath = filePath + "/template/template.pdf";
// 加载中文字体
String fontPath = filePath + "/ttf/syht.ttf";
String fileName = "听力训练习题";
if (vo.getTitle() != null) {
fileName = "听力训练-" + vo.getTitle();
}
//文件名需要这样写,不能在setHeader直接写中文名,否则下载的文件名字为空,只有后缀
response.setCharacterEncoding("utf-8");
fileName = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".pdf");
try {
OutputStream out = response.getOutputStream();
PdfWriter writer = new PdfWriter(out);
PdfDocument pdf = new PdfDocument(writer);
Document document = new Document(pdf);
PdfFont chineseFont = PdfFontFactory.createFont(fontPath, PdfEncodings.IDENTITY_H, true);
//添加标题,并使用中文字体
if (vo.getTitle() != null) {
Paragraph titleParagraph = new Paragraph(vo.getTitle())
.setFont(chineseFont)
.setFontSize(15)
.setTextAlignment(TextAlignment.CENTER)//设置段落对齐方式为居中
.setBold();
document.add(titleParagraph);
}
//添加课程名称,并使用中文字体
if (vo.getCourseName() != null) {
Paragraph titleParagraph = new Paragraph(vo.getCourseName())
.setFont(chineseFont)
.setFontSize(15)
.setTextAlignment(TextAlignment.CENTER)//设置段落对齐方式为居中
.setBold();
document.add(titleParagraph);
}
//添加学习时间
if (vo.getBeginTime() != null && vo.getEndTime() != null && vo.getStudentName() != null) {
Paragraph titleParagraph = new Paragraph("学习时间: " + vo.getBeginTime() + "~" + vo.getEndTime() + " 学生姓名: " + vo.getStudentName())
.setFont(chineseFont)
.setFontSize(10)
.setTextAlignment(TextAlignment.CENTER)//设置段落对齐方式为居中
.setBold();
document.add(titleParagraph);
}
//添加来源
if (vo.getSource() != null) {
Paragraph titleParagraph = new Paragraph("(" + vo.getSource() + ")")
.setFont(chineseFont)
.setFontSize(10)
.setTextAlignment(TextAlignment.CENTER)//设置段落对齐方式为居中
.setBold();
document.add(titleParagraph);
}
//换行
document.add(new Paragraph("\n"));
//【点击这里收听音频】
Text clickableText = new Text("点击这里收听音频")
.setFont(chineseFont)
.setFontSize(15)
.setUnderline()
.setFontColor(new DeviceRgb(0, 0, 255))
.setBold();
// 创建指向音频文件的动作
String baseUrl = redisUtils.getY(RedisKeyUtil.getApiUrl());
String audio = vo.getAudio();
String audioUrl=baseUrl+audio;
clickableText.setAction(PdfAction.createURI(audioUrl));
// 创建段落并添加到文档
Paragraph audioLink = new Paragraph()
.add(clickableText)
.setTextAlignment(TextAlignment.CENTER);
document.add(audioLink);
//使用浏览器打开即可下载音频到本地
if (vo.getSource() != null) {
Paragraph titleParagraph = new Paragraph("(" + "使用浏览器打开即可下载音频到本地" + ")")
.setFont(chineseFont)
.setFontSize(8)
.setTextAlignment(TextAlignment.CENTER)//设置段落对齐方式为居中
.setBold();
document.add(titleParagraph);
}
//添加习题标题
Paragraph question = new Paragraph("习题:")
.setFont(chineseFont)
.setFontSize(15)
.setBold();
document.add(question);
// 遍历习题和答案列表,并添加到PDF中
if (vo.getHearingExerciseList() != null && !vo.getHearingExerciseList().isEmpty()) {
for (NewHearingExerciseDTO newHearingExerciseDTO : vo.getHearingExerciseList()) {
// 添加序号
String num = newHearingExerciseDTO.getNum() + ". ";
String title = newHearingExerciseDTO.getTitle();
Paragraph paragraph = new Paragraph();
paragraph.add(num + title);
document.add(paragraph.setFontSize(10).setFont(chineseFont).setBold());
switch (newHearingExerciseDTO.getOptionType()) {
case 0://文本内容
// 添加习题选项
List<String> stringList = new ArrayList<>();
if (newHearingExerciseDTO.getHearingExerciseOptionList() != null) {
for (NewHearingExerciseOptionDTO dto : newHearingExerciseDTO.getHearingExerciseOptionList()) {
String option = dto.getXtOption() + "、" + dto.getEnMsg();
stringList.add(option);
}
}
Paragraph optionParagraph = new Paragraph();
for (String s : stringList) {
optionParagraph.add(s + " ");
}
document.add(optionParagraph.setFontSize(10).setFont(chineseFont).setBold());
break;
case 1://图片内容
if (newHearingExerciseDTO.getHearingExerciseOptionList() != null) {
// 计算每个选项的目标宽度(假设每行最多显示4个选项)
int maxOptionsPerRow = 6;
float optionWidth = 100f / maxOptionsPerRow;
// 创建流动表格,允许自动换行
Table table = new Table(UnitValue.createPercentArray(maxOptionsPerRow));
table.setWidth(UnitValue.createPercentValue(100));
table.setKeepTogether(false); // 允许表格跨页
for (NewHearingExerciseOptionDTO dto : newHearingExerciseDTO.getHearingExerciseOptionList()) {
// 创建每个选项的内部表格(1行2列:文本+图片)
Table innerTable = new Table(UnitValue.createPercentArray(new float[]{20, 80}));
innerTable.setWidth(UnitValue.createPercentValue(100));
// 创建选项文本单元格
Cell textCell = new Cell();
textCell.setBorder(Border.NO_BORDER);
textCell.setTextAlignment(TextAlignment.RIGHT);
textCell.setVerticalAlignment(VerticalAlignment.MIDDLE);
Paragraph optionText = new Paragraph(dto.getXtOption() + "、");
optionText.setFontSize(10);
optionText.setFont(chineseFont);
textCell.add(optionText);
// 创建图片单元格
Cell imageCell = new Cell();
imageCell.setBorder(Border.NO_BORDER);
imageCell.setPaddingLeft(3);
imageCell.setVerticalAlignment(VerticalAlignment.MIDDLE);
// 加载图片
String enMsg = dto.getEnMsg().replace("/profile", "");
String imagePath = filePath + enMsg;
ImageData imageData = ImageDataFactory.create(imagePath);
Image image = new Image(imageData);
// 动态调整图片大小,防止过大
float maxImageWidth = 72 * 0.8f; // 假设最大宽度为0.8英寸(72dpi)
float originalWidth = image.getImageWidth();
float originalHeight = image.getImageHeight();
if (originalWidth > maxImageWidth) {
float scale = maxImageWidth / originalWidth;
image.scale(scale, scale);
} else {
image.scaleToFit(50, 50);
}
imageCell.add(image);
// 将文本和图片单元格添加到内部表格
innerTable.addCell(textCell);
innerTable.addCell(imageCell);
// 创建主表格单元格并添加内部表格
Cell mainCell = new Cell();
mainCell.setBorder(Border.NO_BORDER);
mainCell.setPadding(3); // 选项之间的间距
mainCell.add(innerTable);
// 将主单元格添加到主表格
table.addCell(mainCell);
}
// 将表格添加到文档
document.add(table);
}
break;
}
}
}
document.close();
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 创建超级语法PDF文件
*
* @param response
* @param vo
*/
public void syntaxCreatePdf(HttpServletResponse response, SyntaxDownloadVO vo, Long classRecordId) throws Exception {
// 加载中文字体
String fontPath = filePath + "/ttf/syht.ttf";
// 加载音标字体(预留,实际暂不使用)
String ipaFontPath = filePath + "/ttf/DoulosSIL-Regular.ttf";
// 调整文件名
String fileName = "超级语法学习报告";
if (vo.getCourseName() != null && !vo.getCourseName().trim().isEmpty()) {
fileName = "超级语法学习报告-" + vo.getCourseName();
}
// 设置响应头,处理中文文件名
response.setCharacterEncoding("utf-8");
fileName = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".pdf");
try (OutputStream out = response.getOutputStream()) {
// 初始化PDF文档
PdfWriter writer = new PdfWriter(out);
PdfDocument pdf = new PdfDocument(writer);
Document document = new Document(pdf, PageSize.A4); // 横向布局
// 加载字体
PdfFont chineseFont = PdfFontFactory.createFont(fontPath, PdfEncodings.IDENTITY_H, true);
// 添加标题区域
Paragraph mainTitle = new Paragraph("超级语法学习报告")
.setFont(chineseFont)
.setFontSize(20)
.setTextAlignment(TextAlignment.CENTER)
.setBold()
.setMarginBottom(10);
document.add(mainTitle);
// 课程信息区域
if (vo.getCourseName() != null) {
Paragraph courseTitle = new Paragraph(vo.getCourseName())
.setFont(chineseFont)
.setFontSize(16)
.setTextAlignment(TextAlignment.CENTER)
.setItalic()
.setMarginBottom(20);
document.add(courseTitle);
}
// 学习基本信息行
Paragraph infoParagraph = new Paragraph()
.setFont(chineseFont)
.setFontSize(12)
.setTextAlignment(TextAlignment.CENTER)
.setMarginBottom(15);
if (vo.getStudentName() != null) {
infoParagraph.add(new Text("学生姓名: " + vo.getStudentName()).setBold())
.add(new Text(" "));
}
if (vo.getBeginTime() != null && vo.getEndTime() != null) {
infoParagraph.add(new Text("学习时段: " + vo.getBeginTime() + " ~ " + vo.getEndTime()).setBold());
}
document.add(infoParagraph);
// 学习统计卡片
Table statsTable = new Table(new float[]{1, 1, 1})
.useAllAvailableWidth()
.setMarginBottom(20);
// 统计数据单元格样式
Style statsStyle = new Style()
.setFont(chineseFont)
.setTextAlignment(TextAlignment.CENTER)
.setPadding(10);
// 添加统计信息
statsTable.addCell(new Cell().add(new Paragraph("总语法点").addStyle(statsStyle).setFontSize(12))
.add(new Paragraph(vo.getSyntaxTotal() == null ? "0" : vo.getSyntaxTotal().toString())
.addStyle(statsStyle).setFontSize(16).setBold()));
statsTable.addCell(new Cell().add(new Paragraph("掌握语法点").addStyle(statsStyle).setFontSize(12))
.add(new Paragraph(vo.getRightTotal() == null ? "0" : vo.getRightTotal().toString())
.addStyle(statsStyle).setFontSize(16).setBold().setFontColor(ColorConstants.GREEN)));
statsTable.addCell(new Cell().add(new Paragraph("待巩固语法点").addStyle(statsStyle).setFontSize(12))
.add(new Paragraph(vo.getWrongTotal() == null ? "0" : vo.getWrongTotal().toString())
.addStyle(statsStyle).setFontSize(16).setBold().setFontColor(ColorConstants.RED)));
document.add(statsTable);
// 语法复习计划表
document.add(new Paragraph("语法复习计划")
.setFont(chineseFont)
.setFontSize(14)
.setBold()
.setMarginBottom(10)
.setUnderline());
// 复习计划表格
Table reviewTable = new Table(new float[]{15, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10})
.useAllAvailableWidth()
.setTextAlignment(TextAlignment.CENTER)
.setFixedLayout()
.setMarginBottom(20);
// 表头样式
Style headerStyle = new Style()
.setFont(chineseFont)
.setFontSize(10)
.setBold()
.setBackgroundColor(ColorConstants.LIGHT_GRAY)
.setPadding(5);
// 内容样式
Style dateCellStyle = new Style()
.setFont(chineseFont)
.setFontSize(10)
.setPadding(5);
// 添加复习计划表头
reviewTable.addHeaderCell(new Cell().add(new Paragraph("复习节点").addStyle(headerStyle)));
reviewTable.addHeaderCell(new Cell().add(new Paragraph("第1天").addStyle(headerStyle)));
reviewTable.addHeaderCell(new Cell().add(new Paragraph("第2天").addStyle(headerStyle)));
reviewTable.addHeaderCell(new Cell().add(new Paragraph("第3天").addStyle(headerStyle)));
reviewTable.addHeaderCell(new Cell().add(new Paragraph("第5天").addStyle(headerStyle)));
reviewTable.addHeaderCell(new Cell().add(new Paragraph("第7天").addStyle(headerStyle)));
reviewTable.addHeaderCell(new Cell().add(new Paragraph("第9天").addStyle(headerStyle)));
reviewTable.addHeaderCell(new Cell().add(new Paragraph("第12天").addStyle(headerStyle)));
reviewTable.addHeaderCell(new Cell().add(new Paragraph("第14天").addStyle(headerStyle)));
reviewTable.addHeaderCell(new Cell().add(new Paragraph("第17天").addStyle(headerStyle)));
reviewTable.addHeaderCell(new Cell().add(new Paragraph("第21天").addStyle(headerStyle)));
// 添加复习日期
reviewTable.addCell(new Cell().add(new Paragraph("复习日期").addStyle(headerStyle)));
if (vo.getAntiForgetDateList() != null && !vo.getAntiForgetDateList().isEmpty()) {
int dateCount = vo.getAntiForgetDateList().size();
for (int i = 0; i < 10; i++) {
String date = (i < dateCount) ? vo.getAntiForgetDateList().get(i) : "待安排";
reviewTable.addCell(new Cell().add(new Paragraph(date)
.addStyle(dateCellStyle)
.setFontColor((i < dateCount) ? ColorConstants.BLACK : ColorConstants.GRAY)));
}
} else {
for (int i = 0; i < 10; i++) {
reviewTable.addCell(new Cell().add(new Paragraph("待安排").addStyle(dateCellStyle).setFontColor(ColorConstants.GRAY)));
}
}
// 需复习语法点行
reviewTable.addCell(new Cell().add(new Paragraph("需复习语法点").addStyle(headerStyle)));
int wrongTotal = vo.getWrongTotal() == null ? 0 : vo.getWrongTotal();
int dailyAvg = wrongTotal > 0 ? (int) Math.ceil((double) wrongTotal / 10) : 0;
for (int i = 0; i < 10; i++) {
String countText = (wrongTotal > 0) ? String.valueOf(Math.min(dailyAvg, wrongTotal)) : "";
if (wrongTotal > 0) wrongTotal -= dailyAvg;
reviewTable.addCell(new Cell().add(new Paragraph(countText).addStyle(dateCellStyle)));
}
document.add(reviewTable);
// -------------------- 关键修改:处理HTML富文本 --------------------
ClassRecordDetailDto detailDto = classRecordDetailService.detailByClassRecordId(classRecordId);
if (detailDto != null && detailDto.getSyntaxHandoutList() != null && !detailDto.getSyntaxHandoutList().isEmpty()) {
// 添加语法讲义标题
document.add(new Paragraph("语法讲义内容")
.setFont(chineseFont)
.setFontSize(14)
.setBold()
.setMarginTop(20)
.setMarginBottom(10)
.setUnderline());
// 配置HTML转换属性(确保样式和字体正常)
ConverterProperties converterProperties = new ConverterProperties();
FontProvider fontProvider = new DefaultFontProvider(false, false, false);
// 加载中文字体(必须,否则中文乱码)
try {
PdfFont chinesePdfFont = PdfFontFactory.createFont(fontPath, PdfEncodings.IDENTITY_H, true);
fontProvider.addFont(chinesePdfFont.getFontProgram());
// 添加系统字体作为备选
fontProvider.addSystemFonts();
} catch (IOException e) {
log.error("加载字体失败", e);
}
converterProperties.setFontProvider(fontProvider);
// 设置基础URL,处理相对路径资源
converterProperties.setBaseUri("");
// 遍历讲义列表,解析HTML内容
for (SyntaxHandoutDto handout : detailDto.getSyntaxHandoutList()) {
// 添加讲义标题
document.add(new Paragraph(handout.getName())
.setFont(chineseFont)
.setFontSize(13)
.setBold()
.setMarginTop(15)
.setMarginBottom(5));
// 处理HTML内容
if (handout.getContent() != null && !handout.getContent().isEmpty()) {
try {
// 预处理HTML:替换转义符
String htmlContent = handout.getContent()
.replaceAll("\\\\\"", "\"")
.replaceAll("\\\\n", "\n")
.replaceAll("\\\\r", "");
// 确保HTML格式正确
if (!htmlContent.trim().startsWith("<html")) {
htmlContent = "<html><body>" + htmlContent + "</body></html>";
}
// 将HTML转换为iText元素并添加到文档
List<IElement> elements = HtmlConverter.convertToElements(htmlContent, converterProperties);
// 遍历转换后的元素,添加到PDF文档
for (IElement element : elements) {
if (element instanceof IBlockElement) {
// 处理块级元素
document.add((IBlockElement) element);
} else if (element instanceof Image) {
// 处理图片
document.add((Image) element);
}
}
} catch (Exception e) {
// 转换失败时显示错误信息
document.add(new Paragraph("讲义内容解析失败: " + e.getMessage())
.setFont(chineseFont)
.setFontColor(ColorConstants.RED)
.setMarginTop(5));
log.error("HTML转PDF失败", e);
}
} else {
document.add(new Paragraph("该讲义暂无内容")
.setFont(chineseFont)
.setFontColor(ColorConstants.GRAY)
.setMarginTop(5));
}
// 讲义之间添加分页
document.add(new AreaBreak());
}
}
// -------------------- HTML处理结束 --------------------
// -------------------- 新增:处理语法试题 --------------------
if (detailDto != null && detailDto.getSyntaxQuDtoList() != null && !detailDto.getSyntaxQuDtoList().isEmpty()) {
// 添加语法试题标题
document.add(new Paragraph("语法试题内容")
.setFont(chineseFont)
.setFontSize(14)
.setBold()
.setMarginTop(20)
.setMarginBottom(10)
.setUnderline());
// 遍历试题列表
int questionNumber = 1;
for (SyntaxQuDto question : detailDto.getSyntaxQuDtoList()) {
// 试题编号和标题
Paragraph questionTitle = new Paragraph(questionNumber + ". " + question.getTitle())
.setFont(chineseFont)
.setFontSize(12)
.setBold()
.setMarginTop(10)
.setMarginBottom(5);
document.add(questionTitle);
// 试题解析(如果有)
if (question.getAnalysis() != null && !question.getAnalysis().isEmpty()) {
Paragraph analysis = new Paragraph("解析:" + question.getAnalysis())
.setFont(chineseFont)
.setFontSize(11)
.setItalic()
.setMarginBottom(5)
.setFontColor(ColorConstants.DARK_GRAY);
document.add(analysis);
}
// 选项表格
Table optionsTable = new Table(new float[]{1, 9})
.useAllAvailableWidth()
.setMarginBottom(8);
// 选项样式
Style optionStyle = new Style()
.setFont(chineseFont)
.setFontSize(11)
.setPadding(3);
// 添加选项
if (question.getOptionA() != null) {
optionsTable.addCell(new Cell().add(new Paragraph("A").addStyle(optionStyle).setBold()));
optionsTable.addCell(new Cell().add(new Paragraph(question.getOptionA()).addStyle(optionStyle)));
}
if (question.getOptionB() != null) {
optionsTable.addCell(new Cell().add(new Paragraph("B").addStyle(optionStyle).setBold()));
optionsTable.addCell(new Cell().add(new Paragraph(question.getOptionB()).addStyle(optionStyle)));
}
if (question.getOptionC() != null) {
optionsTable.addCell(new Cell().add(new Paragraph("C").addStyle(optionStyle).setBold()));
optionsTable.addCell(new Cell().add(new Paragraph(question.getOptionC()).addStyle(optionStyle)));
}
if (question.getOptionD() != null) {
optionsTable.addCell(new Cell().add(new Paragraph("D").addStyle(optionStyle).setBold()));
optionsTable.addCell(new Cell().add(new Paragraph(question.getOptionD()).addStyle(optionStyle)));
}
document.add(optionsTable);
// 答案和学生作答情况
Paragraph answerInfo = new Paragraph()
.setFont(chineseFont)
.setFontSize(11)
.setMarginBottom(5);
answerInfo.add(new Text("正确答案:").setBold())
.add(new Text(question.getRightKey() != null ? question.getRightKey() : "未设置").setFontColor(ColorConstants.GREEN).setBold())
.add(new Text(" "));
if (question.getAnswerKey() != null) {
answerInfo.add(new Text("学生答案:").setBold())
.add(new Text(question.getAnswerKey()));
// 标记答案是否正确
if (question.getRightKey() != null && question.getAnswerKey().equals(question.getRightKey())) {
answerInfo.add(new Text(" (正确)").setFontColor(ColorConstants.GREEN));
} else {
answerInfo.add(new Text(" (错误)").setFontColor(ColorConstants.RED));
}
} else {
answerInfo.add(new Text("学生未作答").setFontColor(ColorConstants.GRAY));
}
document.add(answerInfo);
// 每5题添加一个分页
if (questionNumber % 5 == 0) {
document.add(new AreaBreak());
}
questionNumber++;
}
} else {
// 无试题时的提示
document.add(new Paragraph("暂无语法试题数据")
.setFont(chineseFont)
.setFontSize(12)
.setTextAlignment(TextAlignment.CENTER)
.setMargin(10)
.setFontColor(ColorConstants.GRAY));
}
// -------------------- 语法试题处理结束 --------------------
document.close();
out.flush();
} catch (Exception e) {
log.error("生成超级语法PDF失败", e);
throw new Exception("生成PDF失败: " + e.getMessage());
}
}
}
二、controller
/**
* 【后台/H5-单词识记-pdf下载】
*
* @param response
* @param dto
* @return
* @throws Exception
*/
@PostMapping("/wordDownload")
@ApiOperation("后台/H5-单词识记-pdf下载")
public AjaxResult wordDownload(HttpServletResponse response, @RequestBody WordDownloadDTO dto) throws Exception {
newApiService.wordDownload(response, dto);
return AjaxResult.success();
}
三、Impl
/**
* 后台/H5-单词识记-pdf下载
*
* @param response
* @param dto
*/
@Override
public void wordDownload(HttpServletResponse response, WordDownloadDTO dto) throws Exception {
WordDownloadVO wordDownloadVO = classRecordMapper.getWordDownloadVO(dto.getClassRecordId());
if (wordDownloadVO == null) {
throw new BusinessException("数据不存在!");
}
wordDownloadVO.setPrintType(dto.getPrintType());
//直接查询学后检测的单词
List<WordDownloadListVO> wordList = Collections.emptyList();
// wordList = classRecordMapper.getAfterWordList(dto.getClassRecordId());
// if (!wordList.isEmpty()) {
// wordDownloadVO.setWordList(wordList);
// System.out.println("单词列表数据" + wordList);
// }
//直接查询学前检测错误串单词-gzy-2025.8.28(李慧)
ClassRecord classRecord = classRecordMapper.selectById(dto.getClassRecordId());
String wrongWordIds = classRecord.getWrongWordIds();
List<Long> ids = new ArrayList<>();
if (wrongWordIds != null && !wrongWordIds.trim().isEmpty()) {
ids = Arrays.stream(wrongWordIds.split(","))
.map(String::trim)
.filter(str -> !str.isEmpty()) // 过滤空字符串
.map(str -> {
try {
return Long.parseLong(str);
} catch (NumberFormatException e) {
// 可以记录日志或进行其他处理
System.err.println("无法转换为Long类型: " + str);
return null;
}
})
.filter(Objects::nonNull) // 过滤转换失败的null值
.collect(Collectors.toList());
wordList = classRecordMapper.getWordListData(ids);
wordDownloadVO.setWordList(wordList);
wordDownloadVO.setWordTotal(wordList.size());
System.out.println("单词列表数据" + wordList);
}
//复习日期list
List<String> antiForgetDateList = classRecordMapper.getAntiForgetDateList(dto.getClassRecordId());
if (!antiForgetDateList.isEmpty()) {
wordDownloadVO.setAntiForgetDateList(antiForgetDateList);
System.out.println("复习日期list" + antiForgetDateList);
}
pdfUtil.wordCreatePdf(response, wordDownloadVO);
}
四、WordDownloadVO
package com.ruoyi.school.domain.vo;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
/**
* @Description 后台/H5-单词识记-pdf下载数据
* @ClassName WordDownloadVO
* @Author gzy
* @Date 2025/5/27 17:00
* @Version 1.0
**/
@Data
public class WordDownloadVO implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty("课程名称")
private String courseName;
@ApiModelProperty("学生名称")
private String studentName;
@ApiModelProperty("开始时间")
private String beginTime;
@ApiModelProperty("结束时间")
private String endTime;
@ApiModelProperty("单词总数")
private Integer wordTotal;
@ApiModelProperty("正确数-(绿色)")
private Integer rightTotal;
@ApiModelProperty("错误数-(红色)")
private Integer wrongTotal;
@ApiModelProperty("学前检测单词list")
private List<WordDownloadListVO> wordList;
@ApiModelProperty("打印类型:0-打印中文,1-打印英文,2-打印中英文,3-打印音标")
private Integer printType;
@ApiModelProperty("复习日期list")
private List<String> antiForgetDateList;
}
五、maven依赖
<!--引入 iText 的 HTML 转 PDF 依赖-->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>kernel</artifactId>
<version>7.2.5</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>html2pdf</artifactId>
<version>3.0.5</version>
</dependency>
<!--okhttp3-->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
</dependency>
<!--itextpdf-->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext7-core</artifactId>
<type>pom</type>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>kernel</artifactId>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>layout</artifactId>
</dependency>
<!-- 阿里JSON解析器 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
<!-- excel工具 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
</dependency>
本文来自博客园,作者:青喺半掩眉砂,转载请注明原文链接:https://www.cnblogs.com/xiaoguo-java/p/20845785

浙公网安备 33010602011771号