lowagie(itext)老版本手绘PDF,包含页码、水印、图片、复选框、复杂行列合并等。

news2025/2/26 23:27:36

入口类:exportPdf

​
package xcsy.qms.webapi.service;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.common.utils.StringUtils;
import com.ibm.icu.text.RuleBasedNumberFormat;
import com.lowagie.text.*;
import com.lowagie.text.Font;
import com.lowagie.text.Rectangle;
import com.lowagie.text.pdf.*;
import kd.bos.dataentity.entity.DynamicObject;
import kd.bos.dataentity.entity.DynamicObjectCollection;
import kd.bos.logging.Log;
import kd.bos.logging.LogFactory;
import kd.bos.openapi.common.result.CustomApiResult;
import kd.bos.servicehelper.BusinessDataServiceHelper;
import org.jsoup.Jsoup;
import xcsy.zjy.webapi.utils.AddImageToEachPageHeader;
import xcsy.zjy.webapi.utils.CheckBoxCellEvent;
import xcsy.zjy.webapi.utils.CheckBoxCellNotEvent;
import xcsy.zjy.webapi.utils.PdfPageUtil;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @program: xcsy-cosmic
 * @description: 准入报告pdf导出实现
 * @author: lyw
 * @create: 2025-02-13 09:31
 **/

public class ReportsPDFService {

    private static final Log log = LogFactory.getLog(ReportsPDFService.class);

    // 定义全局的字体静态变量
    Font headFont;
    Font headFont2;
    Font contentFont;
    Font titleFont;
    Font titleFont2;
    Font titleFontW;

    SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日");

    public CustomApiResult<String> exportPdf(HttpServletRequest request, HttpServletResponse response) throws IOException {
        // 单据id
        String id = request.getParameter("id");
        DynamicObject accessReportsDO = BusinessDataServiceHelper.loadSingle(id, "eo45_access_reports");
        // 防止日志记录获取session异常
        request.getSession();
        // 设置编码格式
        response.setContentType("application/pdf;charset=UTF-8");
        response.setCharacterEncoding("utf-8");
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
        String fileName = URLEncoder.encode(accessReportsDO.getString("eo45_fac_name") + "联盟工厂质量专项评审报告" + dateFormat.format(new Date()), "UTF-8");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".pdf");
        download(response, accessReportsDO);
        return CustomApiResult.success("成功");
    }

    private void download(HttpServletResponse response, DynamicObject reportData) {
        // 最大宽度
        try {
            // 不同字体(这里定义为同一种字体:包含不同字号、不同style)
            BaseFont bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
            BaseFont bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
            headFont = new Font(bf, 18, Font.BOLD, new Color(0, 0, 0));
            headFont2 = new Font(bf, 14, Font.BOLD, new Color(0, 0, 0));
            titleFont = new Font(bf, 10, Font.BOLD, new Color(0, 103, 255));
            titleFont2 = new Font(bf, 12, Font.BOLD, new Color(0, 0, 0));
            titleFontW = new Font(bf, 12, Font.BOLD, new Color(251, 251, 251));
            contentFont = new Font(bfChinese, 10, Font.NORMAL, new Color(0, 0, 0));

            Document document = new Document(new RectangleReadOnly(842F, 595F));
            // 设置页边距
            document.setMargins(60, 60, 60, 30);
            PdfWriter writer = PdfWriter.getInstance(document, response.getOutputStream());
            // 添加页码
            writer.setPageEvent(new PdfPageUtil());
            // 每页表头添加水印(图片)
            writer.setPageEvent(new AddImageToEachPageHeader());
            // 打开生成的pdf文件
            document.open();
            // 标题1
            Paragraph paragraph = new Paragraph(reportData.getString("eo45_fac_name") + "联盟工厂质量专项评审报告", headFont);
            paragraph.setAlignment(1);
            document.add(paragraph);
            // 评审总结
            DynamicObjectCollection resultsDO = reportData.getDynamicObjectCollection("eo45_report_results");
            DynamicObject entryResults = resultsDO.get(0);
            // -------基本信息
            buildBasicInformation(document, entryResults);
            // -------审核目的
            buildAuditAim(document, entryResults);
            // -------审核类型
            buildAuditType(document, reportData);
            // -------审核范围
            buildAuditRange(document, entryResults);
            // -------审核内容
            buildAuditContent(document, entryResults);
            // -------审核方法
            buildAuditMethod(document, entryResults);
            // -------审核方背景资料
            buildAuditData(document, entryResults);
            // -------审核结论
            buildAuditResult(document, entryResults);
            // 标题2
            Paragraph paragraph2 = new Paragraph("质量专项评审“否决项”评分标准", headFont2);
            paragraph2.setAlignment(1);
            document.add(paragraph2);
            float[] widthsOne = {10f, 20f, 60f, 10f};
            PdfPTable tableOne = new PdfPTable(widthsOne);
            handleTableOne(reportData, tableOne);
            document.add(tableOne);
            // 标题3
            Paragraph paragraph3 = new Paragraph("分值汇总", headFont2);
            paragraph3.setAlignment(1);
            document.add(paragraph3);
            float[] widthsTwo = {60f, 20f, 20f};
            PdfPTable tableTwo = new PdfPTable(widthsTwo);
            handleTableTwo(reportData, tableTwo);
            document.add(tableTwo);
            // 标题4
            Paragraph paragraph4 = new Paragraph("联盟工厂质量专项评审表", headFont2);
            paragraph4.setAlignment(1);
            document.add(paragraph4);
            float[] widthsThree = {5f, 15f, 30f, 25f, 5f, 5f, 5f, 7f, 25f};
            PdfPTable tableThree = new PdfPTable(widthsThree);
            handleTableThree(reportData, tableThree);
            document.add(tableThree);
            // 关闭文档
            document.close();
        } catch (DocumentException e) {
            log.error("导出pdf失败DocumentException:{}", e);
        } catch (Exception e) {
            log.error("导出pdf失败Exception:{}", e);
        }
    }

    private void handleTableThree(DynamicObject reportData, PdfPTable table) {
        // 项目分类集合
        DynamicObjectCollection projectCollection = reportData.getDynamicObjectCollection("eo45_report_projects");
        // 按eo45_project_id分组
        Map<String, String> projectMap = new LinkedHashMap<>();
        // 获取项目,以项目id作为key,排除第一项否决项,按项目seq排序
        projectCollection.stream()
                .filter(e -> !"0".equals(e.getString("eo45_project_seq"))).sorted(Comparator.comparing(dynamicObject -> dynamicObject.getString("eo45_project_seq")))
                .forEach(e -> projectMap.put(e.getString("eo45_project_id"), e.getString("eo45_project")));
        // 段落在其上方留出的空间量
        table.setSpacingBefore(10f);
        // 设置表格宽度为100%
        // 设置表格宽度为100%
        table.setWidthPercentage(100.0F);
        table.setHeaderRows(2);
        table.getDefaultCell().setHorizontalAlignment(1);
        // 第一行
        PdfPCell titleCell1 = createCenteredCellForTable("条款编号", 30, new Color(40, 120, 255), titleFontW, "border", "center");
        titleCell1.setRowspan(2);
        table.addCell(titleCell1);
        PdfPCell titleCell2 = createCenteredCellForTable("条款性质", 0, new Color(40, 120, 255), titleFontW, "border", "center");
        titleCell2.setRowspan(2);
        table.addCell(titleCell2);
        PdfPCell titleCell3 = createCenteredCellForTable("审核条款标准", 0, new Color(40, 120, 255), titleFontW, "border", "center");
        titleCell3.setRowspan(2);
        table.addCell(titleCell3);
        PdfPCell titleCell4= createCenteredCellForTable("审核正面发现", 0, new Color(40, 120, 255), titleFontW, "border", "center");
        titleCell4.setRowspan(2);
        table.addCell(titleCell4);

        PdfPCell titleCell10 = createCenteredCellForTable("审核记录及说明", 0, new Color(40, 120, 255), titleFontW, "border", "center");
        titleCell10.setColspan(6);
        table.addCell(titleCell10);

        PdfPCell titleCell5 = createCenteredCellForTable("审核配分", 0, new Color(40, 120, 255), titleFontW, "border", "center");
        table.addCell(titleCell5);
        PdfPCell titleCell6 = createCenteredCellForTable("符合程度", 0, new Color(40, 120, 255), titleFontW, "border", "center");
        table.addCell(titleCell6);
        PdfPCell titleCell7 = createCenteredCellForTable("实际得分", 0, new Color(40, 120, 255), titleFontW, "border", "center");
        table.addCell(titleCell7);
        PdfPCell titleCell8 = createCenteredCellForTable("不符合类型", 0, new Color(40, 120, 255), titleFontW, "border", "center");
        table.addCell(titleCell8);
        PdfPCell titleCell9 = createCenteredCellForTable("问题描述", 0, new Color(40, 120, 255), titleFontW, "border", "center");
        table.addCell(titleCell9);

        int[] x = {0}; // 项目序号
        // 添加一级项目
        projectMap.forEach((projectId, projectName) -> {
            x[0]++;
            // 1转一
            RuleBasedNumberFormat formatter = new RuleBasedNumberFormat(Locale.CHINA, RuleBasedNumberFormat.SPELLOUT);
            String result = formatter.format(x[0]);
            // 项目总分
            BigDecimal projectScoreAll = projectCollection.stream()
                    .filter(e -> projectId.equals(e.getString("eo45_project_id")))
                    .map(e -> e.getBigDecimal("eo45_project_scoreall"))
                    .findFirst()
                    .orElse(BigDecimal.ZERO);
            PdfPCell projectCell = new PdfPCell(new Paragraph(result + "、" + projectName
                    + "(" + projectScoreAll.setScale(2, RoundingMode.HALF_UP)  + "分)", titleFont));
            projectCell.setColspan(9);
            tableCellStyle(projectCell, new Color(237, 239, 240), new Color(242, 247, 255), "border");
            table.addCell(projectCell);
            int y = 0; // 分类序号
            // 二级分类
            for (DynamicObject categorysDynamicObject : projectCollection) {
                if (projectId.equals(categorysDynamicObject.getString("eo45_project_id"))) {
                    y++;
                    PdfPCell cellClass = new PdfPCell(new Paragraph(x[0] + "." + y + " "
                            + categorysDynamicObject.getString("eo45_sort_name") + "(" + categorysDynamicObject.getBigDecimal("eo45_sort_scoreall").setScale(2, RoundingMode.HALF_UP)  + "分)", titleFont));
                    cellClass.setColspan(9);
                    tableCellStyle(cellClass, new Color(237, 239, 240), new Color(242, 247, 255), "border");
                    table.addCell(cellClass);
                    // 三级分类内容
                    DynamicObjectCollection contents = categorysDynamicObject.getDynamicObjectCollection("eo45_report_contents");
                    int z = 0; // 内容序号
                    for (DynamicObject content : contents) {
                        z++;
                        String ratio = ""; // 系数
                        // 单选题
                        JSONArray optionArray = JSONArray.parseArray(content.getString("eo45_option_json_tag"));
                        // 问题
                        JSONArray problemArray = JSONArray.parseArray(content.getString("eo45_problem_json_tag"));
                        // 合并行的数量
                        int rowspan = 1;
                        if (problemArray != null && !problemArray.isEmpty()) {
                            rowspan = problemArray.size();
                        }
                        if (optionArray != null && !optionArray.isEmpty()) {
                            for (int j = 0; j < optionArray.size(); j++) {
                                JSONObject option = optionArray.getJSONObject(j);
                                if (option.getInteger("choose") == 1) {
                                    if (!"N/A".equals(option.getString("scoreCoefficient"))
                                            && StringUtils.isNotEmpty(option.getString("scoreCoefficient"))) {
                                        double decimal = Double.parseDouble(option.getString("scoreCoefficient"));
                                        // 转换为百分比并四舍五入到最接近的整数
                                        int percentage = (int) Math.round(decimal * 100);
                                        ratio = percentage + "%";
                                    }
                                    break;
                                }
                            }
                        }
                        PdfPCell cell1 = new PdfPCell(new Paragraph(x[0] + "." + y + "." + z, contentFont));
                        cell1.setRowspan(rowspan);
                        PdfPCell cell2 = new PdfPCell(new Paragraph(content.getString("eo45_import_area"), contentFont));
                        cell2.setRowspan(rowspan);
                        String contentContext = "";
                        if (StringUtils.isNotBlank(content.getString("eo45_project_context"))) {
                            org.jsoup.nodes.Document documentResult = Jsoup.parse(content.getString("eo45_project_context"));
                            contentContext = documentResult.text();
                        }
                        PdfPCell cell3 = new PdfPCell(new Paragraph(contentContext, contentFont));
                        cell3.setRowspan(rowspan);
                        PdfPCell cell4 = new PdfPCell(new Paragraph(content.getString("eo45_content_suggestion"), contentFont));
                        cell4.setRowspan(rowspan);

                        PdfPCell cell5 = new PdfPCell(new Paragraph(String.valueOf(content.getBigDecimal("eo45_sum_score").setScale(2, RoundingMode.HALF_UP)), contentFont));
                        cell5.setRowspan(rowspan);
                        PdfPCell cell6 = new PdfPCell(new Paragraph(ratio, contentFont));
                        cell6.setRowspan(rowspan);
                        PdfPCell cell7 = new PdfPCell(new Paragraph(String.valueOf(content.getBigDecimal("eo45_content_score").setScale(2, RoundingMode.HALF_UP)), contentFont));
                        cell7.setRowspan(rowspan);

                        //单元格对齐方式水平、垂直
                        tableCellStyle(cell1, new Color(237, 239, 240), null, "border");
                        cell1.setFixedHeight(20);
                        tableCellStyle(cell2, new Color(237, 239, 240), null, "border");
                        tableCellStyle(cell3, new Color(237, 239, 240), null, "border");
                        tableCellStyle(cell4, new Color(237, 239, 240), null, "border");
                        tableCellStyle(cell5, new Color(237, 239, 240), null, "border");
                        tableCellStyle(cell6, new Color(237, 239, 240), null, "border");
                        tableCellStyle(cell7, new Color(237, 239, 240), null, "border");

                        table.addCell(cell1);
                        table.addCell(cell2);
                        table.addCell(cell3);
                        table.addCell(cell4);
                        table.addCell(cell5);
                        table.addCell(cell6);
                        table.addCell(cell7);

                        PdfPCell cell8, cell9;
                        if (problemArray != null && !problemArray.isEmpty()) {
                            for (int j = 0; j < problemArray.size(); j++) {
                                JSONObject problem = problemArray.getJSONObject(j);
                                String selectContent = "";
                                JSONArray options = JSONArray.parseArray(problem.getString("options"));
                                for (int k = 0; k < options.size(); k++) {
                                    JSONObject option = options.getJSONObject(k);
                                    if (option.getInteger("choose") == 1) {
                                        selectContent = option.getString("selectContent");
                                        break;
                                    }
                                }
                                cell8 = new PdfPCell(new Paragraph(selectContent, contentFont));
                                cell9 = new PdfPCell(new Paragraph(problem.getString("problem_desc"), contentFont));
                                tableCellStyle(cell8, new Color(237, 239, 240), null, "border");
                                tableCellStyle(cell9, new Color(237, 239, 240), null, "border");
                                table.addCell(cell8);
                                table.addCell(cell9);
                            }
                        } else {
                            cell8 = new PdfPCell(new Paragraph("", contentFont));
                            cell9 = new PdfPCell(new Paragraph("", contentFont));
                            tableCellStyle(cell8, new Color(237, 239, 240), null, "border");
                            tableCellStyle(cell9, new Color(237, 239, 240), null, "border");
                            table.addCell(cell8);
                            table.addCell(cell9);
                        }
                    }
                }
            }
        });
    }

    private void handleTableTwo(DynamicObject reportData, PdfPTable table) {
        // 项目分类集合
        DynamicObjectCollection projectCollection = reportData.getDynamicObjectCollection("eo45_report_projects");
        // 按eo45_project_id分组
        // Map<String, List<DynamicObject>> projectMap = projectCollection.stream().collect(Collectors.groupingBy(dynamicObject -> dynamicObject.getString("eo45_project_id")));
        Map<String, String> projectMap = new LinkedHashMap<>();
        // 获取项目,以项目id作为key,排除第一项否决项,按项目seq排序
        projectCollection.stream()
                .filter(e -> !"0".equals(e.getString("eo45_project_seq"))).sorted(Comparator.comparing(dynamicObject -> dynamicObject.getString("eo45_project_seq")))
                .forEach(e -> projectMap.put(e.getString("eo45_project_id"), e.getString("eo45_project")));
        // 段落在其上方留出的空间量
        table.setSpacingBefore(10f);
        // 距离下方空间
        table.setSpacingAfter(20f);
        // 设置表格宽度为100%
        table.setWidthPercentage(100.0F);
        table.setHeaderRows(1);
        table.getDefaultCell().setHorizontalAlignment(1);
        // 第一行
        table.addCell(createCenteredCellForTable("主要项目", 30, new Color(242, 247, 255), titleFont2, null, null));
        table.addCell(createCenteredCellForTable("项目配分", 0, new Color(242, 247, 255), titleFont2, null, null));
        table.addCell(createCenteredCellForTable("实际得分", 0, new Color(242, 247, 255), titleFont2, null, null));
        // 计数
        int[] projectSeq = {0};
        // 添加一级项目
        final BigDecimal[] allScore = {BigDecimal.ZERO}; // 审核分数合计
        final BigDecimal[] allGetScore = {BigDecimal.ZERO}; // 审核得分
        projectMap.forEach((projectId, projectName) -> {
            projectSeq[0]++;
            // 1转一
            RuleBasedNumberFormat formatter = new RuleBasedNumberFormat(Locale.CHINA, RuleBasedNumberFormat.SPELLOUT);
            String result = formatter.format(projectSeq[0]);
            PdfPCell cell1 = new PdfPCell(new Paragraph(result + "、" + projectName, contentFont));
            // 获取对应项目的总分和得分
            BigDecimal eo45ProjectScoreAll = projectCollection.stream()
                    .filter(e -> projectId.equals(e.getString("eo45_project_id")))
                    .map(e -> e.getBigDecimal("eo45_project_scoreall"))
                    .findFirst()
                    .orElse(BigDecimal.ZERO);
            allScore[0] = allScore[0].add(eo45ProjectScoreAll);
            BigDecimal eo45ProjectScore = projectCollection.stream()
                    .filter(e -> projectId.equals(e.getString("eo45_project_id")))
                    .map(e -> e.getBigDecimal("eo45_project_score"))
                    .findFirst()
                    .orElse(BigDecimal.ZERO);
            allGetScore[0] = allGetScore[0].add(eo45ProjectScore);
            PdfPCell cell2 = new PdfPCell(new Paragraph(String.valueOf(eo45ProjectScoreAll.setScale(2, RoundingMode.HALF_UP)), contentFont));
            PdfPCell cell3 = new PdfPCell(new Paragraph(String.valueOf(eo45ProjectScore.setScale(2, RoundingMode.HALF_UP)), contentFont));

            //单元格对齐方式水平、垂直
            tableCellStyle(cell1, new Color(237, 239, 240), new Color(242, 247, 255), null);
            cell1.setFixedHeight(20);
            tableCellStyle(cell2, new Color(237, 239, 240), new Color(242, 247, 255), null);
            tableCellStyle(cell3, new Color(237, 239, 240), new Color(242, 247, 255), null);

            table.addCell(cell1);
            table.addCell(cell2);
            table.addCell(cell3);
            // 项目下添加二级分类
            int sortSeq = 0;
            for (DynamicObject categorysDynamicObject : projectCollection) {
                if (projectId.equals(categorysDynamicObject.getString("eo45_project_id"))) {
                    sortSeq++;
                    PdfPCell cell4 = new PdfPCell(new Paragraph(projectSeq[0] + "." + sortSeq + " " + categorysDynamicObject.getString("eo45_sort_name"), contentFont));
                    PdfPCell cell5 = new PdfPCell(new Paragraph(String.valueOf(categorysDynamicObject.getBigDecimal("eo45_sort_scoreall").setScale(2, RoundingMode.HALF_UP)), contentFont));
                    PdfPCell cell6 = new PdfPCell(new Paragraph(String.valueOf(categorysDynamicObject.getBigDecimal("eo45_sort_score").setScale(2, RoundingMode.HALF_UP)), contentFont));

                    tableCellStyle(cell4, new Color(237, 239, 240), null, null);
                    cell4.setFixedHeight(20);
                    tableCellStyle(cell5, new Color(237, 239, 240), null, null);
                    tableCellStyle(cell6, new Color(237, 239, 240), null, null);

                    table.addCell(cell4);
                    table.addCell(cell5);
                    table.addCell(cell6);
                }
            }
        });
        // 添加分汇总
        PdfPCell cell4 = new PdfPCell(new Paragraph("审核分合计", titleFont));
        PdfPCell cell5 = new PdfPCell(new Paragraph(String.valueOf(allScore[0].setScale(2, RoundingMode.HALF_UP)), titleFont));
        PdfPCell cell6 = new PdfPCell(new Paragraph(String.valueOf(allGetScore[0].setScale(2, RoundingMode.HALF_UP)), titleFont));

        tableCellStyle(cell4, new Color(237, 239, 240), new Color(242, 247, 255), null);
        cell4.setFixedHeight(20);
        tableCellStyle(cell5, new Color(237, 239, 240), new Color(242, 247, 255), null);
        tableCellStyle(cell6, new Color(237, 239, 240), new Color(242, 247, 255), null);

        table.addCell(cell4);
        table.addCell(cell5);
        table.addCell(cell6);
    }

    private void handleTableOne(DynamicObject accessReportDO, PdfPTable table) {
        // 项目分类集合
        DynamicObjectCollection projectCollection = accessReportDO.getDynamicObjectCollection("eo45_report_projects");
        // 获取“否决项”数据
        DynamicObject oneProject = projectCollection.stream().filter(e -> "0".equals(e.getString("eo45_project_seq"))).collect(Collectors.toList()).get(0);
        DynamicObjectCollection contents = oneProject.getDynamicObjectCollection("eo45_report_contents");
        // 段落在其上方留出的空间量
        table.setSpacingBefore(10f);
        // 距离下方空间
        table.setSpacingAfter(20f);
        // 设置表格宽度为100%
        table.setWidthPercentage(100.0F);
        table.setHeaderRows(1);
        table.getDefaultCell().setHorizontalAlignment(1);
        // 第一行
        table.addCell(createCenteredCellForTable("序号", 30, new Color(242, 247, 255), titleFont2, null, null));
        table.addCell(createCenteredCellForTable("关键领域", 0, new Color(242, 247, 255), titleFont2, null, null));
        table.addCell(createCenteredCellForTable("检查项目内容", 0, new Color(242, 247, 255), titleFont2, null, null));
        table.addCell(createCenteredCellForTable("是/否", 0, new Color(242, 247, 255), titleFont2, null, null));
        // 数据
        for (int i = 0; i < contents.size(); i++) {
            PdfPCell cell1 = new PdfPCell(new Paragraph(String.valueOf(i + 1), contentFont));
            PdfPCell cell2 = new PdfPCell(new Paragraph(contents.get(i).getString("eo45_import_area"), contentFont));
            // 富文本处理
            String contentContext = "";
            if (StringUtils.isNotBlank(contents.get(i).getString("eo45_project_context"))) {
                org.jsoup.nodes.Document documentResult = Jsoup.parse(contents.get(i).getString("eo45_project_context"));
                contentContext = documentResult.text();
            }
            PdfPCell cell3 = new PdfPCell(new Paragraph(contentContext, contentFont));
            // 获取选项
            JSONArray optionJsonArray = JSONArray.parseArray(contents.get(i).getString("eo45_option_json_tag"));
            String selectContent = "";
            if (optionJsonArray != null && !optionJsonArray.isEmpty()) {
                for (int j = 0; j < optionJsonArray.size(); j++) {
                    JSONObject optionJson = optionJsonArray.getJSONObject(j);
                    if (optionJson.getInteger("choose") == 1) {
                        selectContent = optionJson.getString("options_content");
                        break;
                    }
                }
            }
            PdfPCell cell4 = new PdfPCell(new Paragraph(selectContent, contentFont));

            tableCellStyle(cell1, new Color(237, 239, 240), null, null);
            //单元格对齐方式水平、垂直
            cell1.setFixedHeight(20);
            tableCellStyle(cell2, new Color(237, 239, 240), null, null);
            tableCellStyle(cell3, new Color(237, 239, 240), null, null);
            tableCellStyle(cell4, new Color(237, 239, 240), null, null);

            table.addCell(cell1);
            table.addCell(cell2);
            table.addCell(cell3);
            table.addCell(cell4);
        }
    }

    private void buildAuditResult(Document document, DynamicObject entryResults) throws DocumentException {
        // 设置标题
        document.add(createTitle("审核结论"));
        // 设置两列
        float[] widths = {20f, 80f};
        PdfPTable table = new PdfPTable(widths);
        // 段落在其上方留出的空间量
        table.setSpacingBefore(5f);
        // 设置表格宽度为100%
        table.setWidthPercentage(100.0F);
        table.addCell(createCenteredCell("业务审核意见:", 15, null, contentFont));
        table.addCell(createCenteredCell(entryResults.getString("eo45_audit_conclusion_bus"), 0, null, contentFont));

        table.addCell(createCenteredCell("研发审核意见:", 15, null, contentFont));
        table.addCell(createCenteredCell(entryResults.getString("eo45_audit_conclusion_dev"), 0, null, contentFont));

        table.addCell(createCenteredCell("质量审核意见:", 15, null, contentFont));
        table.addCell(createCenteredCell(entryResults.getString("eo45_audit_obj"), 0, null, contentFont));

        table.addCell(createCenteredCell("数字化能力评估审核意见:", 15, null, contentFont));
        table.addCell(createCenteredCell(entryResults.getString("eo45_audit_conclusion_qu"), 0, null, contentFont));

        table.addCell(createCenteredCell("综合意见:", 15, null, contentFont));
        table.addCell(createCenteredCell(entryResults.getString("eo45_audit_conclusion_res"), 0, null, contentFont));
        document.add(table);
    }

    private void buildAuditData(Document document, DynamicObject entryResults) throws DocumentException {
        // 设置标题
        document.add(createTitle("审核方背景资料"));
        PdfPTable table = new PdfPTable(1);
        // 段落在其上方留出的空间量
        table.setSpacingBefore(5f);
        // 设置表格宽度为100%
        table.setWidthPercentage(100.0F);
        table.addCell(createCenteredCell(entryResults.getString("eo45_audit_information"), 0, null, contentFont));
        document.add(table);
    }

    private void buildAuditMethod(Document document, DynamicObject entryResults) throws DocumentException {
        // 设置标题
        document.add(createTitle("审核方法"));
        PdfPTable table = new PdfPTable(1);
        // 段落在其上方留出的空间量
        table.setSpacingBefore(5f);
        // 设置表格宽度为100%
        table.setWidthPercentage(100.0F);
        table.addCell(createCenteredCell(entryResults.getString("eo45_audit_method"), 0, null, contentFont));
        document.add(table);
    }

    private void buildAuditContent(Document document, DynamicObject entryResults) throws DocumentException {
        // 设置标题
        document.add(createTitle("审核内容"));
        PdfPTable table = new PdfPTable(1);
        // 段落在其上方留出的空间量
        table.setSpacingBefore(5f);
        // 设置表格宽度为100%
        table.setWidthPercentage(100.0F);
        table.addCell(createCenteredCell(entryResults.getString("eo45_audit_context"), 0, null, contentFont));
        document.add(table);
    }

    private void buildAuditRange(Document document, DynamicObject entryResults) throws DocumentException {
        // 设置标题
        document.add(createTitle("审核范围"));
        PdfPTable table = new PdfPTable(1);
        // 段落在其上方留出的空间量
        table.setSpacingBefore(5f);
        // 设置表格宽度为100%
        table.setWidthPercentage(100.0F);
        table.addCell(createCenteredCell(entryResults.getString("eo45_audit_scope"), 0, null, contentFont));
        document.add(table);
    }

    private void buildAuditType(Document document, DynamicObject data) throws DocumentException {
        // 设置标题
        document.add(createTitle("审核类型"));
        float[] widths = {2f, 8f, 2f, 8f, 2f, 8f, 70f};
        PdfPTable table = new PdfPTable(widths);
        // 段落在其上方留出的空间量
        table.setSpacingBefore(5f);
        // 设置表格宽度为100%
        table.setWidthPercentage(100.0F);
        PdfPCell cell = createCenteredCell("准入审核", 0, null, contentFont);
        PdfPCell cell2 = new PdfPCell();
        // 添加复选框绘制事件到单元格
        if ("0".equals(data.getString("eo45_report_type"))) {
            cell2.setCellEvent(new CheckBoxCellEvent());
        } else {
            cell2.setCellEvent(new CheckBoxCellNotEvent());
        }
        cell2.setHorizontalAlignment(PdfPCell.ALIGN_RIGHT);
        cell2.setVerticalAlignment(PdfPCell.ALIGN_MIDDLE);
        cell2.setBorder(Rectangle.NO_BORDER);
        table.addCell(cell2);
        table.addCell(cell);

        PdfPCell cell3 = createCenteredCell("年度审核", 0, null, contentFont);
        PdfPCell cell4 = new PdfPCell();
        // 添加复选框绘制事件到单元格
        if ("1".equals(data.getString("eo45_report_type"))) {
            cell4.setCellEvent(new CheckBoxCellEvent());
        } else {
            cell4.setCellEvent(new CheckBoxCellNotEvent());
        }
        cell4.setHorizontalAlignment(PdfPCell.ALIGN_RIGHT);
        cell4.setVerticalAlignment(PdfPCell.ALIGN_MIDDLE);
        cell4.setBorder(Rectangle.NO_BORDER);
        table.addCell(cell4);
        table.addCell(cell3);

        PdfPCell cell5 = createCenteredCell("跟踪审核", 0, null, contentFont);
        PdfPCell cell6 = new PdfPCell();
        // 添加复选框绘制事件到单元格
        if ("2".equals(data.getString("eo45_report_type"))) {
            cell6.setCellEvent(new CheckBoxCellEvent());
        } else {
            cell6.setCellEvent(new CheckBoxCellNotEvent());
        }
        cell6.setHorizontalAlignment(PdfPCell.ALIGN_RIGHT);
        cell6.setVerticalAlignment(PdfPCell.ALIGN_MIDDLE);
        cell6.setBorder(Rectangle.NO_BORDER);
        table.addCell(cell6);
        table.addCell(cell5);

        PdfPCell cell7 = new PdfPCell();
        cell7.setBorder(Rectangle.NO_BORDER);
        table.addCell(cell7);

        document.add(table);
    }

    private void buildAuditAim(Document document, DynamicObject entryResults) throws DocumentException {
        // 设置标题
        document.add(createTitle("审核目的"));
        PdfPTable table = new PdfPTable(1);
        // 段落在其上方留出的空间量
        table.setSpacingBefore(5f);
        // 设置表格宽度为100%
        table.setWidthPercentage(100.0F);
        table.addCell(createCenteredCell(entryResults.getString("eo45_audit_purpose"), 0, null, contentFont));
        document.add(table);
    }

    private void buildBasicInformation(Document document, DynamicObject entryResults) throws DocumentException {
        // 设置标题
        document.add(createTitle("基本信息"));
        // 设置两列
        float[] widths = {17f, 83f};
        PdfPTable table = new PdfPTable(widths);
        // 段落在其上方留出的空间量
        table.setSpacingBefore(5f);
        // 设置表格宽度为100%
        table.setWidthPercentage(100.0F);
        table.addCell(createCenteredCell("审核对象", 15, null, contentFont));
        table.addCell(createCenteredCell(entryResults.getString("eo45_audit_obj"), 0, null, contentFont));

        table.addCell(createCenteredCell("审核地址", 15, null, contentFont));
        table.addCell(createCenteredCell(entryResults.getString("eo45_audit_addr"), 0, null, contentFont));

        table.addCell(createCenteredCell("审核日期", 15, null, contentFont));
        table.addCell(createCenteredCell(format.format(entryResults.getDate("eo45_audit_date")), 0, null, contentFont));

        table.addCell(createCenteredCell("审核人员", 15, null, contentFont));
        table.addCell(createCenteredCell(entryResults.getString("eo45_audit_person"), 0, null, contentFont));

        table.addCell(createCenteredCell("被审核方人员", 15, null, contentFont));
        table.addCell(createCenteredCell(entryResults.getString("eo45_beaudited_person"), 0, null, contentFont));

        table.addCell(createCenteredCell("本次审核后评级", 15, null, contentFont));
        table.addCell(createCenteredCell(entryResults.getString("eo45_score") + "级", 0, null, contentFont));
        document.add(table);
    }

    /**
     * 标题样式
     *
     * @param value 标题
     * @return
     */
    public PdfPTable createTitle(String value) {
        PdfPTable table = new PdfPTable(1);
        // 段落在其上方留出的空间量
        table.setSpacingBefore(5f);
        if ("基本信息".equals(value)) {
            table.setSpacingBefore(15f);
        }
        table.setWidthPercentage(100.0F);
        table.addCell(createCenteredCell(value, 20, new Color(242, 247, 255), titleFont));
        return table;
    }

    /**
     * 创建cell基本内容
     *
     * @param value       值
     * @param fixedHeight 高度
     * @param color       背景色
     * @param font        字体样式
     * @return
     */
    public PdfPCell createCenteredCell(String value, float fixedHeight, Color color, Font font) {
        Paragraph paragraph = new Paragraph(value, font);
        // paragraph.setLeading(10);
        PdfPCell cell = new PdfPCell(paragraph);
        // 水平对齐
        cell.setHorizontalAlignment(PdfPCell.ALIGN_LEFT);
        // 垂直对齐
        // cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
        // 边框
        cell.setBorder(Rectangle.NO_BORDER);
        // 设置背景色
        if (color != null) {
            cell.setBackgroundColor(color);
        }
        // 设置单元格高度
        if (fixedHeight != 0) {
            cell.setFixedHeight(fixedHeight);
        }
        return cell;
    }

    /**
     * 表格表头
     *
     * @param value
     * @param fixedHeight
     * @param color
     * @param font
     * @return
     */
    private PdfPCell createCenteredCellForTable(String value, float fixedHeight, Color color, Font font, String border, String alignment) {
        PdfPCell cell = new PdfPCell(new Paragraph(value, font));
        cell.setHorizontalAlignment(Element.ALIGN_LEFT);
        if ("center".equals(alignment)) {
            cell.setHorizontalAlignment(Element.ALIGN_CENTER);
        }
        cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
        cell.setBorderColor(new Color(230, 230, 230));
        if (border == null) {
            cell.setBorder(Rectangle.TOP | Rectangle.BOTTOM);
        }
        // 设置背景色
        if (color != null) {
            cell.setBackgroundColor(color);
        }
        // 设置单元格高度
        if (fixedHeight != 0) {
            cell.setFixedHeight(fixedHeight);
        }
        return cell;
    }


    /**
     * 设置单元格样式
     *
     * @param cell
     */
    private void tableCellStyle(PdfPCell cell, Color borderColor, Color backgroundColor, String border) {
        cell.setHorizontalAlignment(Element.ALIGN_LEFT);
        cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
        // 只显示上下边框
        if (border == null) {
            cell.setBorder(Rectangle.TOP | Rectangle.BOTTOM);
        }
        // 边框颜色
        if (borderColor != null) {
            cell.setBorderColorTop(borderColor);
            cell.setBorderColorBottom(borderColor);
        }
        // 背景色
        if (backgroundColor != null) {
            cell.setBackgroundColor(backgroundColor);
        }
        cell.setBorderColor(new Color(230, 230, 230));
    }

}

​

 头部添加水印/图片工具类

package xcsy.zjy.webapi.utils;

import com.lowagie.text.Document;
import com.lowagie.text.DocumentException;
import com.lowagie.text.Image;
import com.lowagie.text.pdf.PdfPageEventHelper;
import com.lowagie.text.pdf.PdfWriter;
import kd.bos.logging.Log;
import kd.bos.logging.LogFactory;

import java.io.IOException;
import java.net.URL;

/**
 * @program: xcsy-cosmic
 * @description: pdf添加头部水印图片
 * @author: lyw
 * @create: 2025-02-17 16:51
 **/

public class AddImageToEachPageHeader extends PdfPageEventHelper {

    private static final Log log = LogFactory.getLog(AddImageToEachPageHeader.class);
    // 图片路径
    public static final String IMG = "img/logo.png";
    // 图片路径
    public static final String LINEIMG = "img/line.png";

    // 自定义页面事件监听器
    Image headerImage;
    Image lineImage;

    public AddImageToEachPageHeader() throws IOException, DocumentException {
        URL resourceUrl = AddImageToEachPageHeader.class.getClassLoader().getResource(IMG);
        assert resourceUrl != null;
        headerImage = Image.getInstance(resourceUrl);
        // scaleToFit按比例缩放图像、调整大小以适应您的需求
        headerImage.scaleToFit(50, 50);
        URL resourceUrl2 = AddImageToEachPageHeader.class.getClassLoader().getResource(LINEIMG);
        assert resourceUrl2 != null;
        lineImage = Image.getInstance(resourceUrl2);
    }

    @Override
    public void onEndPage(PdfWriter writer, Document document) {
        try {
            // 计算图片1放置的位置
            // float x = (document.right() - document.left()) / 2 + document.leftMargin() - headerImage.getScaledWidth() / 2; // 居中
            float x = document.leftMargin();
            // 适当调整距离顶部的距离
            float y = document.top() + headerImage.getScaledHeight() + 10;
            headerImage.setAbsolutePosition(x, y);
            writer.getDirectContent().addImage(headerImage);

            // 图2
            // 获取页面宽度
            float pageWidth = document.getPageSize().getWidth();
            float x2 = 0;
            // 适当调整距离顶部的距离
            float y2 = document.top() + headerImage.getScaledHeight();
            // scaleAbsolute直接设置图像的确切宽度和高度,不考虑原始宽高比。
            lineImage.scaleAbsolute(pageWidth, 10);
            lineImage.setAbsolutePosition(x2, y2);
            writer.getDirectContent().addImage(lineImage);
        } catch (DocumentException e) {
            log.error("pdf添加头部水印图片DocumentException:{}", e);
        }
    }

}

复选框(选中)绘制工具类

package xcsy.zjy.webapi.utils;

import com.lowagie.text.Rectangle;
import com.lowagie.text.pdf.PdfContentByte;
import com.lowagie.text.pdf.PdfPCell;
import com.lowagie.text.pdf.PdfPCellEvent;
import com.lowagie.text.pdf.PdfPTable;

import java.awt.*;

/**
 * @program: xcsy-cosmic
 * @description: pdf复选框
 * @author: lyw
 * @create: 2025-02-18 10:30
 **/

public class CheckBoxCellEvent implements PdfPCellEvent {
    @Override
    public void cellLayout(PdfPCell cell, Rectangle position, PdfContentByte[] canvases) {
        PdfContentByte canvas = canvases[PdfPTable.LINECANVAS];

        // 绘制复选框的位置和大小
        float x = position.getLeft() + 2; // X坐标,相对于单元格左下角
        float y = position.getBottom() + 2; // Y坐标,相对于单元格左下角
        float size = 10; // 复选框大小

        // 开始写入操作
        canvas.saveState();
        // 绘制复选框
        canvas.rectangle(x, y, size, size);
        canvas.setColorStroke(new Color( 190, 198, 205));
        canvas.stroke();

        // 确保勾选标记的起点、中点和终点位置合理,以形成一个清晰的√符号
        float rotatedMarkStartX = x + size - 2; // 原始markStartX关于x轴+size的对称点
        float rotatedMarkStartY = y + size - ((size / 2) - 2); // 原始markStartY关于y轴+size的对称点
        float rotatedMarkMidX = x + size - (size / 2); // 原始markMidX关于x轴+size的对称点
        float rotatedMarkMidY = y + 3; // 原始markMidY关于y轴+size的对称点
        float rotatedMarkEndX = x + 2; // 原始markEndX关于x轴+size的对称点
        float rotatedMarkEndY = y + size - 4; // 原始markEndY关于y轴+size的对称点

        canvas.moveTo(rotatedMarkStartX, rotatedMarkStartY); // 设置旋转后的起点
        canvas.lineTo(rotatedMarkMidX, rotatedMarkMidY); // 经过旋转后的中间点
        canvas.lineTo(rotatedMarkEndX, rotatedMarkEndY); // 结束于旋转后的右上角

        canvas.setColorStroke(new Color(0, 103, 255));
        canvas.setColorFill(new Color(0, 103, 255));

        canvas.stroke();
        // 结束写入操作
        canvas.restoreState();
    }
}

复选框(不选中)绘制工具类

package xcsy.zjy.webapi.utils;

import com.lowagie.text.Rectangle;
import com.lowagie.text.pdf.PdfContentByte;
import com.lowagie.text.pdf.PdfPCell;
import com.lowagie.text.pdf.PdfPCellEvent;
import com.lowagie.text.pdf.PdfPTable;

import java.awt.*;

/**
 * @program: xcsy-cosmic
 * @description: pdf复选框(不选中)
 * @author: lyw
 * @create: 2025-02-18 10:30
 **/

public class CheckBoxCellNotEvent implements PdfPCellEvent {
    @Override
    public void cellLayout(PdfPCell cell, Rectangle position, PdfContentByte[] canvases) {
        PdfContentByte canvas = canvases[PdfPTable.LINECANVAS];

        // 绘制复选框的位置和大小
        float x = position.getLeft() + 2; // X坐标,相对于单元格左下角
        float y = position.getBottom() + 2; // Y坐标,相对于单元格左下角
        float size = 10; // 复选框大小

        // 开始写入操作
        canvas.saveState();
        // 绘制复选框
        canvas.rectangle(x, y, size, size);
        canvas.setColorStroke(new Color( 190, 198, 205));
        canvas.stroke();

        // 结束写入操作
        canvas.restoreState();
    }
}

页码工具类

package xcsy.zjy.webapi.utils;

import com.lowagie.text.*;
import com.lowagie.text.pdf.*;

import java.io.IOException;

/**
 * @Author xx
 * @Date 2023/12/15 10:05
 * @Description: 导出pdf添加页数
 * @Version 1.0
 */
public class PdfPageUtil extends PdfPageEventHelper {

    /**
     * 页眉
     */
    //public String header = "itext测试页眉";

    /**
     * 文档字体大小,页脚页眉最好和文本大小一致
     */
    public int presentFontSize = 9;

    /**
     * 文档页面大小,最好前面传入,否则默认为A4纸张
     */
    public Rectangle pageSize = PageSize.A4;

    // 模板
    public PdfTemplate total;

    // 基础字体对象
    public BaseFont bf = null;

    // 利用基础字体生成的字体对象,一般用于生成中文文字
    public Font fontDetail = null;

    /**
     *
     *  无参构造方法.
     *
     */
    public PdfPageUtil() {

    }

    /**
     *
     *  构造方法.
     *
     * @param
     *
     * @param presentFontSize
     *            数据体字体大小
     * @param pageSize
     *            页面文档大小,A4,A5,A6横转翻转等Rectangle对象
     */
    public PdfPageUtil( int presentFontSize, Rectangle pageSize) {
        this.presentFontSize = presentFontSize;
        this.pageSize = pageSize;
    }

    public void setPresentFontSize(int presentFontSize) {
        this.presentFontSize = presentFontSize;
    }

    /**
     *
     * 文档打开时创建模板
     */
    @Override
    public void onOpenDocument(PdfWriter writer, Document document) {
        // 共 页 的矩形的长宽高
        total = writer.getDirectContent().createTemplate(50, 50);
    }

    /**
     *
     *关闭每页的时候,写入页眉,写入'第几页共'这几个字。
     */
    @Override
    public void onEndPage(PdfWriter writer, Document document) {
        this.addPage(writer, document);
    }

    //加分页
    public void addPage(PdfWriter writer, Document document){
        //设置分页页眉页脚字体
        try {
            if (bf == null) {
                bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", false);
            }
            if (fontDetail == null) {
                fontDetail = new Font(bf, presentFontSize, Font.NORMAL);// 数据体字体
            }
        } catch (DocumentException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 1.写入页眉
//        ColumnText.showTextAligned(writer.getDirectContent(),
//                Element.ALIGN_LEFT, new Phrase(header, fontDetail),
//                document.left(), document.top() + 20, 0);
        // 2.写入前半部分的 第 X页/共
        int pageS = writer.getPageNumber();
        //String foot1 = "第 " + pageS + " 页 /共";
        String foot1 = pageS  +"/";
        Phrase footer = new Phrase(foot1, fontDetail);

        // 3.计算前半部分的foot1的长度,后面好定位最后一部分的'Y页'这俩字的x轴坐标,字体长度也要计算进去 = len
        float len = bf.getWidthPoint(foot1, presentFontSize);

        // 4.拿到当前的PdfContentByte
        PdfContentByte cb = writer.getDirectContent();

        // 5.写入页脚1,x轴就是(右margin+左margin + right() -left()- len)/2.0F
        ColumnText
                .showTextAligned(
                        cb,
                        Element.ALIGN_CENTER,
                        footer,
                        (document.rightMargin() + document.right()
                                + document.leftMargin() - document.left() - len) / 2.0F ,
                        document.bottom() - 10, 0);
        cb.addTemplate(total, (document.rightMargin() + document.right()
                        + document.leftMargin() - document.left()) / 2.0F ,
                document.bottom() - 10); // 调节模版显示的位置

    }

//    //加水印
//    public void addWatermark(PdfWriter writer){
//        // 水印图片
//        Image image;
//        try {
//            image = Image.getInstance("./web/images/001.jpg");
//            PdfContentByte content = writer.getDirectContentUnder();
//            content.beginText();
//            // 开始写入水印
//            for(int k=0;k<5;k++){
//                for (int j = 0; j <4; j++) {
//                    image.setAbsolutePosition(150*j,170*k);
//                    content.addImage(image);
//                }
//            }
//            content.endText();
//        } catch (IOException | DocumentException e) {
//            // TODO Auto-generated catch block
//            e.printStackTrace();
//        }
//    }

    /**
     *
     * 关闭文档时,替换模板,完成整个页眉页脚组件
     */
    @Override
    public void onCloseDocument(PdfWriter writer, Document document) {
        // 关闭文档的时候,将模板替换成实际的 Y 值
        total.beginText();
        // 生成的模版的字体、颜色
        total.setFontAndSize(bf, presentFontSize);
        //页脚内容拼接  如  第1页/共2页
        //String foot2 = " " + (writer.getPageNumber()) + " 页";
        //页脚内容拼接  如  第1页/共2页
        String foot2 = String.valueOf(writer.getPageNumber() - 1);
        // 模版显示的内容
        total.showText(foot2);
        total.endText();
        total.closePath();
    }
}

最后大致效果图

静态图片文件存放位置项目下:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2306594.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

达梦有没有类似oerr的功能

在oracle 23ai的sqlplus中&#xff0c;直接看异常信息说明&#xff1a; 达梦没有此功能&#xff0c;但是可以造一个 cd /home/dmdba cat >err.sql<<eof set echo off set ver off set timing off set lineshow off set feedback off select * from V\$ERR_INFO wher…

实战-网安

面试感受:网安公司前端实习 今天我有幸面试了一家网络安全公司的前端开发实习岗位,整个过程让我受益匪浅,也让我对未来的职业发展有了更清晰的认识。 首先,面试官非常专业且友好,整个面试氛围轻松但不失严谨。面试一开始,面试官简单介绍了公司背景和团队文化,让我对公…

MybatisPlus-扩展功能-枚举处理器

在Mybatis里有一个叫TypeHandler的类型处理器&#xff0c;我们常见的PO当中的这些成员变量的数据类型&#xff0c;它都有对应的处理器&#xff0c;因此它就能自动实现这些Java数据类型与数据库类型的相互转换。 它里面还有一个叫EnumOrdinalTypeHandler的枚举处理器&#xff0…

力扣2454. 下一个更大元素 IV

力扣2454. 下一个更大元素 IV 题目 题目解析及思路 题目要求对于每个数&#xff0c;找到右边比它大的第二个数&#xff0c;并记录在ans数组中 如果是右边第一个大的&#xff0c;就用一个递减栈即可&#xff0c;栈顶元素如果<当前元素则弹出 第二个大数就要利用弹出的栈顶…

unity学习51:所有UI的父物体:canvas画布

目录 1 下载资源 1.1 在window / Asset store下下载一套免费的UI资源 1.2 下载&#xff0c;导入import 1.3 导入后在 project / Asset下面可以看到 2 画布canvas&#xff0c;UI的父物体 2.1 创建canvas 2.1.1 画布的下面是 event system是UI相关的事件系统 2.2 canvas…

Ollama部署与常用命令

Ollama是一款开源工具&#xff0c;其目标是简化大语言模型在本地环境的部署和使用。它支持多种流行的开源大语言模型&#xff0c;如 Llama 2、Qwen2.5等。 通过Ollama&#xff0c;用户无需具备深厚的技术背景&#xff0c;就能在普通的消费级硬件上快速搭建一个强大的语言处理环…

Visual Studio Code 远程开发方法

方法1 共享屏幕远程控制&#xff0c;如 to desk, 向日葵 &#xff0c;像素太差&#xff0c;放弃 方法2 内网穿透 ssh 第二个方法又很麻烦&#xff0c;尤其是对于 windows 电脑&#xff0c;要使用 ssh 还需要额外安装杂七杂八的东西&#xff1b;并且内网穿透服务提供商提供的…

C语言预编译

大家好&#xff0c;这里是小编的博客频道 小编的博客&#xff1a;就爱学编程 很高兴在CSDN这个大家庭与大家相识&#xff0c;希望能在这里与大家共同进步&#xff0c;共同收获更好的自己&#xff01;&#xff01;&#xff01; 本文目录 引言正文一、预处理的作用与流程&#xf…

汽车智能制造企业数字化转型SAP解决方案总结

一、项目实施概述 项目阶段划分&#xff1a; 蓝图设计阶段主数据管理方案各模块蓝图设计方案下一阶段工作计划 关键里程碑&#xff1a; 2022年6月6日&#xff1a;项目启动会2022年12月1日&#xff1a;系统上线 二、总体目标 通过SAP实施&#xff0c;构建研产供销协同、业财一…

flowable-ui 的会签功能实现

场景&#xff1a;在进行智慧保时通开发时&#xff0c;有个协作合同入围功能&#xff0c;这个功能的流程图里有个评审小组&#xff0c;这个评审小组就需要进行会签操作&#xff0c;会签完成后&#xff0c;需要依据是否有不通过的情况选择下一步走的流程 思考步骤&#xff1a; 首…

大连指令数据集的创建--数据收集与预处理_02

1.去哪儿爬虫 编程语言&#xff1a;Python爬虫框架&#xff1a;Selenium&#xff08;用于浏览器自动化&#xff09;解析库&#xff1a;BeautifulSoup&#xff08;用于解析HTML&#xff09; 2.爬虫策略 目标网站&#xff1a;去哪儿&#xff08;https://travel.qunar.com/trav…

STM32MP157A-FSMP1A单片机移植Linux系统SPI总线驱动

SPI总线驱动整体上与I2C总线驱动类型&#xff0c;差别主要在设备树和数据传输上&#xff0c;由于SPI是由4根线实现主从机的通信&#xff0c;在设备树上配置时需要对SPI进行设置。 原理图可知&#xff0c;数码管使用的SPI4对应了单片机上的PE11-->SPI4-NSS,PE12-->SPI4-S…

java医院多维度综合绩效考核源码,医院绩效管理系统,支持一键核算和批量操作,设有审核机制,允许数据修正

医院绩效考核管理系统&#xff0c;java医院绩效核算系统源码&#xff0c;采用多维度综合绩效考核的形式&#xff0c;针对院内实际情况分别对工作量、KPI指标、科研、教学、管理等进行全面考核。医院可结合实际需求&#xff0c;对考核方案中各维度进行灵活配置&#xff0c;对各维…

C语言学习笔记-初阶(13)scanf介绍

当我们有了变量&#xff0c;我们需要给变量输入值就可以使用 scanf 函数&#xff0c;如果需要将变量的值输出在屏幕上的时候可以使用 printf 函数&#xff0c;下面看⼀个例子&#xff1a; #include <stdio.h> int main() {int score 0;printf("请输⼊成绩:")…

如何让传统制造企业从0到1实现数字化突破?

随着全球制造业不断向智能化、数字化转型&#xff0c;传统制造企业面临着前所未有的机遇与挑战。数字化转型不仅是技术的革新&#xff0c;更是管理、文化、业务流程等全方位的变革。从零开始&#xff0c;如何带领一家传统制造企业走向数字化突破&#xff0c;是许多企业领导者面…

【HarmonyOS Next】鸿蒙应用公钥和证书MD5指纹的获取

【HarmonyOS Next】鸿蒙应用公钥和证书MD5指纹的获取 一、问题背景 政府的icp备案时&#xff0c;或者某些三方SDK以来的管理后台&#xff0c;都需要配置鸿蒙应用的公钥和证书MD5指纹 二、解决方案 专有名词解释&#xff1a; 华为AppGallery Connect简称 AGC平台&#xff0…

【原创工具】同文件夹PDF文件合并 By怜渠客

【原创工具】同文件夹PDF文件合并 By怜渠客 原贴&#xff1a;可批量合并多个文件夹内的pdf工具 - 吾爱破解 - 52pojie.cn 他这个存在一些问题&#xff0c;并非是软件内自主实现的PDF合并&#xff0c;而是调用的pdftk这一工具&#xff0c;但楼主并没有提供pdftk&#xff0c;而…

【红队利器】单文件一键结束火绒6.0

关于我们 4SecNet 团队专注于网络安全攻防研究&#xff0c;目前团队成员分布在国内多家顶级安全厂商的核心部门&#xff0c;包括安全研究领域、攻防实验室等&#xff0c;汇聚了行业内的顶尖技术力量。团队在病毒木马逆向分析、APT 追踪、破解技术、漏洞分析、红队工具开发等多个…

Linux中文件目录类指令

1、pwd指令 基本语法&#xff1a;pwd 功能&#xff1a;显示当前工作目录的绝对路径 1.相对路径访问和绝对路径访问 当前处于home目录下&#xff0c;访问a.txt文件 相对路径访问&#xff1a;kim/better/a.txt&#xff0c;从当前位置开始定位 绝对路径访问&#xff1a;/home…

开源模型应用落地-LangChain实用小技巧-获取token消耗(五)

一、前言 在当今的自然语言处理领域&#xff0c;LangChain 框架因其强大的功能和灵活性而备受关注。掌握一些实用的小技巧&#xff0c;能够让您在使用 LangChain 框架时更加得心应手&#xff0c;从而更高效地开发出优质的自然语言处理应用。 计算 Token 消耗对有效管理和优化语…