根据数据生成自定义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>
posted @ 2026-06-26 17:12  青喺半掩眉砂  阅读(6)  评论(0)    收藏  举报