java导出pdf(水印、页眉、表格、背景样式、页脚、饼图、柱图)

这里写自定义目录标题

controller层

java 复制代码
@PostMapping("/queryRiskReport1")
    public Object queryRiskReport1(@RequestBody RiskBo riskBo)throws Exception {
        String corpKey = riskBo.getCorpKey();
        String reportNo = "18073201";
        String beginDate=riskBo.getBeginDate();
        String endDate=riskBo.getEndDate();
        SysUser user = SecurityUtils.getLoginUser().getUser();
        String deptName = user.getDept().getDeptName();
        ChangeRiskIntoVo changeRiskIntoVo = new ChangeRiskIntoVo();
        String ancestors = user.getDept().getAncestors();
        if(ancestors.contains(",")){
            String[] split = ancestors.split(",");
            changeRiskIntoVo.setDeptPid(split[0]);
        }else{
            changeRiskIntoVo.setDeptPid(ancestors);
        }
        changeRiskIntoVo.setCorpKey(corpKey);
        Boolean aBoolean = riskHistoryInfoService.queryAuth(changeRiskIntoVo);

        String queryDate = DateUtils.getLastYears(1) + "至"+ DateUtils.getLastYears(0);//查询数据期限
        String currentTime = DateUtils.getDateFormatter(new Date());
        long currentTimeMillis = System.currentTimeMillis();
        String path = pdfResourceFolder + "risk_report" + File.separator;
        String pdfTemp = tempPdfFolder + "risk_report" + File.separator;
        File file = new File(path);
        if (!file.exists()) file.mkdirs();
        File file1 = new File(pdfTemp);
        if (!file1.exists()) file1.mkdirs();
        String pathUrl = path + user.getUserId() + "-" + currentTimeMillis + ".PDF";
        String tmpPath1 = pdfTemp + user.getUserId() + "-" + currentTimeMillis + "1.PDF";
        String tmpPath2 = pdfTemp + user.getUserId() + "-" + currentTimeMillis + "2.PDF";
        String tmpPath3 = pdfTemp + user.getUserId() + "-" + currentTimeMillis + "3.PDF";
        String tmpPath4 = pdfTemp + user.getUserId() + "-" + currentTimeMillis + "4.PDF";
        RiskReportTemplate1 t=new RiskReportTemplate1();
        String htmlStr= t.createReportTemplate(riskReportService.queryRiskReport1(corpKey,beginDate,endDate), queryDate, user.getUserName(), deptName, reportNo,aBoolean,beginDate,endDate).toString();
        PdfUtils.htmp2pdf("客户风险分析报告", htmlStr,tmpPath1, false, false);
        ReportUtils2.addImageWatermark(tmpPath1, tmpPath2, 1, 0);
        ReportUtils2.pdf_yemei(deptName, tmpPath2, tmpPath3);
        t.waterMark(tmpPath3,tmpPath4, user.getUserName(), currentTime, user.getDept().getDeptName());
        t.addPageNum(tmpPath4, pathUrl);
        return Result.success(pathUrl);
    }

pdf模板RiskReportTemplate1(页脚、水印)

java 复制代码
package com.ruoyi.business.bankInterface.controller.risk.model1;

import com.alibaba.fastjson2.JSONObject;
import com.itextpdf.text.*;
import com.itextpdf.text.Image;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.*;
import com.ruoyi.business.bankInterface.ConstantConfig;
import com.ruoyi.business.bankInterface.controller.risk.PdfUtils;
import com.ruoyi.business.bankInterface.controller.risk.utils.ReportUtils2;
import com.ruoyi.business.bankInterface.controller.tax.utils.DateUtils;
import com.ruoyi.business.bankInterface.controller.tax.utils.pdf.PdfNumPageEventTax;
import lombok.extern.slf4j.Slf4j;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceRGB;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;

import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.Font;
import java.awt.image.BufferedImage;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.Date;

@Slf4j
public class RiskReportTemplate1 {

    public static void main(String[]args)throws IOException {
        StringBuffer buffer = new StringBuffer();
        BufferedReader bf = new BufferedReader(new FileReader("D:\\test\\RiskReport1.json"));
        String s = null;
        while((s = bf.readLine()) != null){ buffer.append(s.trim()); } bf.close();
        RiskModel2 model = JSONObject.parseObject(buffer.toString(),RiskModel2.class);
        RiskReportTemplate1 t=new RiskReportTemplate1();
        String htmlStr= t.createReportTemplate(model, "2021-01-01 "+"至"+" 2024-01-31", "周伯通","中国银行苏州分行","18073201",true,"","").toString();

        PdfUtils.htmp2pdf("njfh", htmlStr,"D:\\test\\2123456789001.pdf", false, false);
        ReportUtils2.addImageWatermark("D:\\test\\2123456789001.pdf", "D:\\test\\2123456789002.pdf", 1, 0);
        ReportUtils2.pdf_yemei("中国银行苏州分行", "D:\\test\\2123456789002.pdf", "D:\\test\\2123456789.pdf");
        waterMark("D:\\test\\2123456789.pdf","D:\\test\\21234567891.pdf", "测试用户", "2024-03-29", "中国银行");
        addPageNum("D:\\test\\21234567891.pdf", "D:\\test\\212345678915.pdf");
    }


    /** 征信报告-征信报告模板生成 */
    public StringBuffer createReportTemplate(RiskModel2 riskModel2, String authDate, String person, String bankName, String reportNo,Boolean aBoolean,String beginDate,String endDate
    ) {
        String begin = authDate.split("至")[0];
        String end = authDate.split("至")[1];
        StringBuffer template = new StringBuffer();
        template.append("<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" /><title>客户风险分析报告</title></head>");
        template.append("<body><div>");
        //获取当前时间
        String curentDateStr = DateUtils.getDateFormatter(new Date());
        //首页
        template.append(getFirstHtml(riskModel2.getK1().getQymc(), riskModel2.getK1().getTyshxydm(),curentDateStr, authDate, bankName, person, reportNo,beginDate,endDate));
        /** 1.企业概览 */
        template.append(ReportUtils2.title("企业概览", 1));
        /** 1.1.基本信息 */
        template.append(K1.getHtml(riskModel2.getK1()));
        /** 1.2.企业信用评分 */
        template.append(K1.score(riskModel2.getK1().getScore()));
        /** 2.公司治理 */
        template.append(ReportUtils2.title("公司治理", 1));
        template.append(K3.getHtml1(riskModel2.getK3List()));
        template.append(ReportUtils2.title("风险信息", 1));
        template.append(K4.getHtml1(riskModel2.getK4List()));
        template.append(K5.getHtml(riskModel2.getK5List()));
        /** 3.1.经营风险 */
        template.append(K4.getHtml2(riskModel2.getK4_1List()));
        /** 3.1.1.经营资质 */
        template.append(K3.getHtml2(riskModel2.getK3_1List()));
        /** 3.1.2.运营风险 */
        template.append(K6.getHtml1(riskModel2.getK6List(),aBoolean));
        /** 3.1.3.司法风险 */
        template.append(K7.getHtml(riskModel2.getK7List(), riskModel2.getK7_1List(),aBoolean));
        /** 3.1.4.行政处罚 */
        template.append(K8.getHtml(riskModel2.getK8List(),aBoolean));
        /** 3.2.财务风险 */
        template.append(K4.getHtml3(riskModel2.getK4_2List()));
        /** 3.2.1.偿债能力 */
        template.append(K6.getHtml2(riskModel2.getK6_1List(), "偿债能力", "本风险监测时段中,暂未监测到本企业存在异常。",aBoolean));
        /** 3.2.2.盈利能力 */
        template.append(K6.getHtml2(riskModel2.getK6_2List(), "盈利能力", "本风险监测时段中,暂未监测到本企业存在异常。",aBoolean));
        /** 3.2.3.营运能力 */
        template.append(K6.getHtml2(riskModel2.getK6_3List(), "营运能力", "本风险监测时段中,暂未监测到本企业存在异常。",aBoolean));
        /** 3.3.授用信风险 */
        template.append(ReportUtils2.title("授用信风险", 2));
        /** 3.3.1.履约风险 */
        template.append(K6.getHtml2(riskModel2.getK6_4List(), "履约风险", "本风险监测时段中,暂未监测到本企业存在异常。",aBoolean));
        /** 3.3.2.过度授信风险 */
        template.append(K6.getHtml2(riskModel2.getK6_5List(), "过度授信风险", "本风险监测时段中,暂未监测到本企业存在异常。",aBoolean));
        /** 3.3.3.企业非银融资 */
        template.append(K6.getHtml2(riskModel2.getK6_6List(), "企业非银融资", "本风险监测时段中,暂未监测到本企业存在异常。",aBoolean));
        /** 3.3.4.其他授信异常 */
        template.append(K6.getHtml2(riskModel2.getK6_7List(), "其他授信异常", "本风险监测时段中,暂未监测到本企业存在异常。",aBoolean));
        /** 3.4.关联风险 */
        template.append(ReportUtils2.title("关联风险", 2));
        /** 3.4.1.工商信息监测 */
        template.append(K6.getHtml2(riskModel2.getK6_8List(), "工商信息监测", "本风险监测时段中,未监测到本企业存在企业关联人(企业)发生破产清算注销风险。",aBoolean));
        /** 3.4.2.司法信息监测 */
        template.append(K9.getHtml(riskModel2.getK9List(),aBoolean));
        /** 3.4.3.履约风险(征信) */
        template.append(K6.getHtml2(riskModel2.getK6_9List(), "履约风险(征信)", "本风险监测时段中,未监测到本企业存在关联征信五级不良、关联企业在他行未结清业务发生逾期、关联企业非银机构授信异常风险。",aBoolean));
        /** 3.5.名单监测 */
        template.append(ReportUtils2.title("名单监测", 2));
        /** 3.5.1.黑名单 */
        //template.append(K10.getHtml(riskModel2.getK10List()));
        /** 3.6.系统性风险 */
        template.append(ReportUtils2.title("系统性风险", 2));
        /** 3.6.1.行业风险 */
        template.append(K6.getHtml3(riskModel2.getK6_10List(),aBoolean));



        template.append("</div>");
        template.append("</body>");
        template.append("</html>");
        return template;
    }

    /**
     *  首页
     * @param companyName              企业名称
     * @param companyCode              统一社会信用代码
     * @param time                      报告生成日期,如:2021-01-01
     * @param dataRetrievalCycle      数据周期,如:2021-01-01 至 2024-01-31
     * @param bankName                 金融机构名称
     * @param person                   查询人员
     * @param reportNo                 报告编号
     */
    public static StringBuffer getFirstHtml(String companyName, String companyCode, String time, String dataRetrievalCycle
            , String bankName, String person, String reportNo,String beginDate,String endDate) {
        StringBuffer firstHtml = new StringBuffer();
        firstHtml.append("<div align=\"left\"><img style=\"height:30px;width:280px\" src=\"").append(ConstantConfig.RISK_IMAGE + "苏州征信-logo.png").append("\"/></div>");
        firstHtml.append("<br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>");
        //查询人员信息
        firstHtml.append("<div>");
        firstHtml.append("<div align=\"right\" style=\"font-size:30px; font-weight: 900; color:#005BAB;\">").append(companyName).append("</div><br/>");
        firstHtml.append("<div align=\"right\" style=\"font-size:18px; font-weight: 500; color:#808080;\">统一社会信用代码:").append(companyCode).append("</div>");
        firstHtml.append("</div>");
        firstHtml.append("<br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>");
        firstHtml.append("<div>");
        firstHtml.append("<div align=\"left\" style=\"font-size:16px; font-weight: 100; color:#808080;\">查询人员: ").append(person).append("</div>");
        firstHtml.append("<div align=\"left\" style=\"font-size:16px; font-weight: 100; color:#808080;\">查询机构: ").append(bankName).append("</div>");
        firstHtml.append("<div align=\"left\" style=\"font-size:16px; font-weight: 100; color:#808080;\">风险周期: ").append(beginDate+"至"+endDate).append("</div>");
        firstHtml.append("<div align=\"left\" style=\"font-size:16px; font-weight: 100; color:#808080;\">报告生成时间: ").append(time).append("</div>");
        firstHtml.append("</div><br/><br/><br/><br/><br/>");
        firstHtml.append("<div>");
        firstHtml.append("<div align=\"right\" style=\"font-size:20px; font-weight: 500; color:#4169E1;\">报告编号:").append(reportNo).append("</div>");
        firstHtml.append("</div><br/><br/><br/>");
        return firstHtml;
    }

    /**
     * 生成页脚
     * @param srcPdfPath 源文件
     * @param tagetPdfPath  加工后文件
     */
    public static void addPageNum(String srcPdfPath, String tagetPdfPath) {
        try {
            // 输出文件 流
            FileOutputStream fos = new FileOutputStream(tagetPdfPath);

            // 读取 源PDF文件,进行一页一页复制,才能触发 添加页码的  页面监听事件
            PdfReader reader = new PdfReader(srcPdfPath);
            // 获取 源文件总页数
            int num = reader.getNumberOfPages();

            // 新建文档,默认A4大小
            Document document = new Document(PageSize.A4);
            PdfWriter writer = PdfWriter.getInstance(document, fos);
            // 设置页面监听事件,必须在open方法前
            writer.setPageEvent(new PdfNumPageEventTax(num));
            document.open();
            // PDF内容体
            PdfContentByte pdfContent = writer.getDirectContent();
            //System.out.println("总页数:" + num);
            // 页面数是从1开始的
            for (int i = 1; i <= num; i++) {
                document.newPage();
                // 设置空页码进行展示
                writer.setPageEmpty(false);
                PdfImportedPage page = writer.getImportedPage(reader, i);
                // 复制好的页面,添加到内容去,触发事件监听
                pdfContent.addTemplate(page, 0, 3);
            }
            document.close();
            reader.close();
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    private static int interval = -5;

    //给pdf加水印
    public static void waterMark(String inputFile, String outputFile, String userName, String time,String bankName) {
        PdfReader reader = null;
        PdfStamper stamper = null;
        FileOutputStream outputStream = null;
        try {
            String waterMarkName = "长三角征信链";
            reader = new PdfReader(inputFile);
            outputStream = new FileOutputStream(outputFile);
            stamper = new PdfStamper(reader, outputStream);

            BaseFont base = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H",   BaseFont.EMBEDDED);

            Rectangle pageRect = null;
            PdfGState gs = new PdfGState();
            gs.setFillOpacity(0.15f);//控制水印深浅
            gs.setStrokeOpacity(0.4f);
            int total = reader.getNumberOfPages() + 1;

            JLabel label = new JLabel();
            FontMetrics metrics;
            int textH = 0;
            int textW = 0;
            label.setText(waterMarkName);
            metrics = label.getFontMetrics(label.getFont());
            textH = metrics.getHeight();
            textW = metrics.stringWidth(label.getText());

            PdfContentByte under;
            for (int i = 1; i < total; i++) {
                if(i==1 || i==total-1) continue;
                pageRect = reader.getPageSizeWithRotation(i);
                under = stamper.getOverContent(i);
                under.saveState();
                under.setGState(gs);
                under.beginText();
                under.setFontAndSize(base, 18);//控制水印字体大小
                // 水印文字成30度角倾斜
                // 获取每一页的高度、宽度
                float pageHeight = pageRect.getHeight();
                float pageWidth = pageRect.getWidth();

                // 根据纸张大小多次添加, 水印文字成30度角倾斜
                for (int height = interval + textH; height < pageHeight; height = height + textH * 8) {
                    for (int width = interval + textW; width < pageWidth + textW; width = width + textW * 6) {
                        // 将分段的字段进行输出编写
                        under.setFontAndSize(base, 12);//控制水印字体大小
                        under.showTextAligned(Element.ALIGN_LEFT, "查询人员:"+userName, width - textW, height -textH , 30);
                        under.setFontAndSize(base, 12);//控制水印字体大小
                        under.showTextAligned(Element.ALIGN_LEFT, "查询时间:"+time, width - textW+12, height -textH*2 , 30);
                        under.setFontAndSize(base, 12);//控制水印字体大小
                        under.showTextAligned(Element.ALIGN_LEFT, "查询机构:"+bankName, width - textW+24, height -textH*3 , 30);
                        under.setFontAndSize(base, 12);//控制水印字体大小
                        under.showTextAligned(Element.ALIGN_LEFT, "苏州企业征信服务有限公司", width - textW+36, height -textH*4 , 30);
                    }
                }

                under.endText();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            try {
                if(stamper != null){
                    stamper.close();
                }
                if(outputStream != null){
                    outputStream.close();
                }
                if(reader != null){
                    reader.close();
                }
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }

//    /** 文本内容 content:文本内容;fontSize:字体大小;color:字体颜色;backgroundColor:背景色 */
//    public static StringBuffer title(String content, int fontSize, int fontWeight){
//        StringBuffer description = new StringBuffer();
//        description.append("<div align=\"left\" style=\"");
//        if(fontWeight > 0) description.append("font-weight:").append(fontWeight).append(";");
//        if(fontSize > 0) description.append("font-size:").append(fontSize).append("px;");
//        description.append("line-height:").append(1.8).append(";");
//        description.append("letter-spacing:").append(1.8).append("px;");
//        description.append("\">");
//        description.append(content).append("</div>");
//        return description;
//    }

//    /** 文本内容 content:文本内容;fontSize:字体大小;color:字体颜色;backgroundColor:背景色 */
//    public static StringBuffer description(String content, int fontSize, String color, String backgroundColor, int fontWeight){
//        StringBuffer description = new StringBuffer();
        description.append("<br/>");
//        description.append("<div align=\"left\" style=\"");
//        if(fontWeight > 0) description.append("font-weight:").append(fontWeight).append(";");
//        if(fontSize > 0) description.append("font-size:").append(fontSize).append("px;");
//        if(StringUtils.isNotBlank(color)) description.append("color:").append(color).append(";");
//        if(StringUtils.isNotBlank(color)) description.append("padding-left:12px;padding-right:12px;padding-bottom:12px;background-color:").append(backgroundColor).append(";");
//        description.append("line-height:").append(1.8).append(";");
//        description.append("letter-spacing:").append(1.8).append("px;");
//        description.append("\">");
//        description.append("&nbsp;&nbsp;");
//        description.append(content).append("</div>");
        description.append("<br/>");
//        return description;
//    }
//
//    /**
//     * 加载图片(柱状图/折线图)
//     */
//    public static StringBuffer getImgOneHtml(String title, List<String> xData, List<Double> yDataList, List<Color> colorList, String yUnit, int type,
//                                             int width, int height, double SpaceFill, StringBuffer tempHtml) {
//        if (xData == null || xData.size() == 0) return tempHtml;
//        String path = new HistogramChar<>().getChart2(title, xData, yDataList, colorList, yUnit, type,
//                width, height, SpaceFill);
//        tempHtml.append("<div align=\"center\"><img style=\"height:262px;width:700px\" src=\"").append(path).append("\"/></div>");
//        return tempHtml;
//    }
//
//    /**
//     * 加载图片(扇形图)
//     */
//    public static StringBuffer getImgPieHtml(List<String> keyList, List<Double> rDataList, Boolean isTitleVisible, String title,
//                                             Boolean isLegendVisible, RectangleEdge rectangleEdge, int flag, StringBuffer tempHtml) {
//        if (rDataList == null || rDataList.size() == 0) return tempHtml;
//        tempHtml.append("<div align=\"center\">");
//        String path = Pie2Chart.pieChart(keyList, rDataList, isTitleVisible, title, isLegendVisible, rectangleEdge, flag);
//        tempHtml.append("<img style=\"width:700px\" src=\"").append(path).append("\"/>");
//        tempHtml.append("</div>");
//        return tempHtml;
//    }
}

多线程导出pdf数据

java 复制代码
public RiskModel2 queryRiskReport1(String corpKey,String beginDate,String endDate){
        RiskModel2 riskModel2 = new RiskModel2();
        /** 1.基本信息 */
        CompletableFuture<K1> k1 = CompletableFuture.supplyAsync(() ->
        {K1 k_1 = riskReportMapper.queryK1(corpKey);
            k_1.setTyshxydm(corpKey);
        return k_1;}, creditReportExecutor);
        /** 2.公司治理 */
        CompletableFuture<List<K3>> k3List = CompletableFuture.supplyAsync(() ->
        {
            List<K3> k_3List = riskReportMapper.queryK3List(corpKey, Arrays.asList("R001","R002","R003"),beginDate,endDate);
            return k_3List;
        }, creditReportExecutor);
        /** 3.风险信息:1级风险类型分布 */
        CompletableFuture<List<K4>> k4List = CompletableFuture.supplyAsync(() ->
        {
            List<K4> k_4List = riskReportMapper.queryK4List(corpKey,beginDate,endDate);
            return k_4List;
        }, creditReportExecutor);
        /** 3.风险信息:1级风险类型分布 */
        CompletableFuture<List<K5>> k5List = CompletableFuture.supplyAsync(() ->
        {
            List<K5> k_5List = riskReportMapper.queryK5List(corpKey,beginDate,endDate);
            return k_5List;
        }, creditReportExecutor);
        /** 3.1.经营风险 */
        CompletableFuture<List<K4>> k4_1List = CompletableFuture.supplyAsync(() ->
        {
            List<K4> k_4List = riskReportMapper.queryK4_1List(corpKey, "经营风险",beginDate,endDate);
            return k_4List;
        }, creditReportExecutor);
        /** 3.1.1.经营资质 */
        CompletableFuture<List<K3>> k3_1List = CompletableFuture.supplyAsync(() ->
        {
            List<K3> k_3List = riskReportMapper.queryK3List(corpKey, Arrays.asList("R004","R005"),beginDate,endDate);
            return k_3List;
        }, creditReportExecutor);
        /** 3.1.2.运营风险 */
        CompletableFuture<List<K6>> k6List = CompletableFuture.supplyAsync(() ->
        {
            List<K6> k_6List = riskReportMapper.queryK6List(corpKey, "运营风险",beginDate,endDate);
            return k_6List;
        }, creditReportExecutor);
        /** 3.1.3.司法风险 */
        CompletableFuture<List<K7>> k7_1List = CompletableFuture.supplyAsync(() ->
        {
            List<K7> k_7List = riskReportMapper.queryK7_1List(corpKey, "司法风险",beginDate,endDate);
            return k_7List;
        }, creditReportExecutor);
        CompletableFuture<List<K7>> k7List = CompletableFuture.supplyAsync(() ->
        {
            List<K7> k_7List = riskReportMapper.queryK7List(corpKey, "司法风险",beginDate,endDate);
            return k_7List;
        }, creditReportExecutor);
        /** 3.1.4.行政处罚 */
        CompletableFuture<List<K8>> k8List = CompletableFuture.supplyAsync(() ->
        {
            List<K8> k_8List = riskReportMapper.queryK8List(corpKey, "行政处罚",beginDate,endDate);
            return k_8List;
        }, creditReportExecutor);
        /** 3.2 财务风险 */
        CompletableFuture<List<K4>> k4_2List = CompletableFuture.supplyAsync(() ->
        {
            List<K4> k_4List = riskReportMapper.queryK4_1List(corpKey, "财务风险",beginDate,endDate);
            return k_4List;
        }, creditReportExecutor);
        /** 3.2.1 偿债能力 */
        CompletableFuture<List<K6>> k6_1List = CompletableFuture.supplyAsync(() ->
        {
            List<K6> k_6List = riskReportMapper.queryK6List(corpKey, "偿债能力",beginDate,endDate);
            return k_6List;
        }, creditReportExecutor);
        /** 3.2.2盈利能力 */
        CompletableFuture<List<K6>> k6_2List = CompletableFuture.supplyAsync(() ->
        {
            List<K6> k_6List = riskReportMapper.queryK6List(corpKey, "盈利能力",beginDate,endDate);
            return k_6List;
        }, creditReportExecutor);
        /** 3.2.3营运能力 */
        CompletableFuture<List<K6>> k6_3List = CompletableFuture.supplyAsync(() ->
        {
            List<K6> k_6List = riskReportMapper.queryK6List(corpKey, "营运能力",beginDate,endDate);
            return k_6List;
        }, creditReportExecutor);
        /** 3.3.1履约风险 */
        CompletableFuture<List<K6>> k6_4List = CompletableFuture.supplyAsync(() ->
        {
            List<K6> k_6List = riskReportMapper.queryK6List(corpKey, "履约风险",beginDate,endDate);
            return k_6List;
        }, creditReportExecutor);
        /** 3.3.2 过度授信风险 */
        CompletableFuture<List<K6>> k6_5List = CompletableFuture.supplyAsync(() ->
        {
            List<K6> k_6List = riskReportMapper.queryK6List(corpKey, "过度授信风险",beginDate,endDate);
            return k_6List;
        }, creditReportExecutor);
        /** 3.3.3 企业非银融资 */
        CompletableFuture<List<K6>> k6_6List = CompletableFuture.supplyAsync(() ->
        {
            List<K6> k_6List = riskReportMapper.queryK6List(corpKey, "企业非银融资",beginDate,endDate);
            return k_6List;
        }, creditReportExecutor);
        /** 3.3.4 其他授信异常 */
        CompletableFuture<List<K6>> k6_7List = CompletableFuture.supplyAsync(() ->
        {
            List<K6> k_6List = riskReportMapper.queryK6List(corpKey, "其他授信异常",beginDate,endDate);
            return k_6List;
        }, creditReportExecutor);
        /** 3.4.1 工商信息监测(暂无数据) */
        /** 3.4.2 司法信息监测 */
        CompletableFuture<List<K9>> k9List = CompletableFuture.supplyAsync(() ->
        {
            List<K9> k9_1List = riskReportMapper.queryK9List(corpKey, "司法信息监测",beginDate,endDate);
            return k9_1List;
        }, creditReportExecutor);
        /** 3.4.3 履约风险(征信) */
        CompletableFuture<List<K6>> k6_9List = CompletableFuture.supplyAsync(() ->
        {
            List<K6> k_6List = riskReportMapper.queryK6List(corpKey, "履约风险(征信)",beginDate,endDate);
            return k_6List;
        }, creditReportExecutor);
        /** 3.5.1 黑名单 */
        CompletableFuture<List<K10>> k10List = CompletableFuture.supplyAsync(() ->
        {
            List<K10> k10_1List = riskReportMapper.queryK10List(corpKey, "黑名单",beginDate,endDate);
            return k10_1List;
        }, creditReportExecutor);
        /** 3.6 系统性风险 */

        /** 3.6 系统性风险 */
        CompletableFuture<List<K6>> k6_10List = CompletableFuture.supplyAsync(() ->
        {
            List<K6> k_6List = riskReportMapper.queryK6List(corpKey, "行业风险",beginDate,endDate);
            return k_6List;
        }, creditReportExecutor);

        CompletableFuture<Void> allOf = CompletableFuture.allOf(k1, k3List, k4List, k5List, k3_1List, k4_1List, k6List, k7_1List, k7List
                , k4_2List, k8List, k6_1List, k6_2List, k6_3List, k6_4List, k6_5List, k6_6List, k6_7List, k9List, k6_9List, k10List, k6_10List);
        try {
            allOf.get();
            riskModel2 = RiskModel2.builder().k1(k1.get()).k3List(k3List.get()).k4List(k4List.get()).k5List(k5List.get()).
                    k3_1List(k3_1List.get()).k4_1List(k4_1List.get()).k6List(k6List.get()).k7_1List(k7_1List.get()).k7List(k7List.get()).k4_2List(k4_2List.get()).k8List(k8List.get())
                    .k6_1List(k6_1List.get()).k6_1List(k6_1List.get()).k6_2List(k6_2List.get()).k6_3List(k6_3List.get()).k6_4List(k6_4List.get())
                    .k6_5List(k6_5List.get()).k6_6List(k6_6List.get()).k6_7List(k6_7List.get()).k9List(k9List.get()).k6_9List(k6_9List.get()).k6_10List(k6_10List.get()).k10List(k10List.get()).build();
        } catch (InterruptedException |ExecutionException e) {
            e.printStackTrace();
            log.error("查询企业{}风险报告出错",corpKey);
        }
        return riskModel2;
    }

pdf导出工具类(页眉、图片底纹、柱图、饼图、表格、一级二级标题)

java 复制代码
package com.ruoyi.business.bankInterface.controller.risk.utils;

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfImportedPage;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
import com.ruoyi.business.bankInterface.ConstantConfig;
import com.ruoyi.business.bankInterface.controller.risk.utils.chart.HistogramChar;
import com.ruoyi.business.bankInterface.controller.risk.utils.chart.Pie2Chart;
import com.ruoyi.business.bankInterface.controller.tax.utils.annotation.ReportField;
import com.ruoyi.business.bankInterface.controller.tax.utils.annotation.ReportFieldAnnotation;
import org.apache.commons.lang3.StringUtils;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceRGB;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.jfree.ui.RectangleEdge;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.*;
import java.util.List;

public class ReportUtils2 {
    private static String baseUrl = ConstantConfig.IMAGE_TEMP_FOLDER;

    //列表数据
    public static StringBuffer listHtml(Class<?> clazz, String jsonStr, StringBuffer template, int tableType, int dataType){
        if(StringUtils.isBlank(jsonStr) || "{}".equals(jsonStr) || "[]".equals(jsonStr)) return template;
        Map<String, Object> data = null;
        if(dataType == 1){
            /** 数据类型是list */
            data = ReportUtils2.changeObjectList(clazz, jsonStr);
        }else{
            /** 数据类型是对象 */
            data = ReportUtils2.changeObject(clazz, jsonStr);
        }
        if(data == null || data.size() == 0) return template;
        List<ReportField> reportFieldList = (List<ReportField>)data.get("nameList");
        List<Map<String,Object>> valueList = (List<Map<String,Object>>)data.get("valueList");
        if(tableType == 1){//列表排列
            template.append(ReportUtils2.listHtml(reportFieldList, valueList));
        }else if(tableType == 3){//横着单列标题排列
            template.append(ReportUtils2.oneTitleHtml(reportFieldList, valueList));
        }else{//横着两列标题排列
            template.append(ReportUtils2.twoTitleHtml(reportFieldList, valueList));
        }
        return template;
    }

    //jsonArrStr支持的对象中可以有key:value和最多两个List<String>,且其中一个List<String>为yearList
    public static Map<String, Object> changeObjectList(Class<?> clazz, String jsonArrStr) {
        // 获取带有特定注解的字段
        Set<Field> annotatedFields = getAnnotatedFields(clazz, ReportFieldAnnotation.class);
        List<ReportField> reportFieldList = new ArrayList<>();
        List<JSONObject> objectList = JSONArray.parseArray(jsonArrStr, JSONObject.class);
        List<Map<String, String>> valueList = new ArrayList<>(); Map<String, String> value = null;
        int flag = 0;
        for(JSONObject jsonObject : objectList){
            value = new HashMap<>();
            for (Field field : annotatedFields) {
                ReportField reportField = new ReportField();
                ReportFieldAnnotation annotation = field.getAnnotation(ReportFieldAnnotation.class);
                int dataType = annotation.dataType();//0:字符串,1:List<String>
                String fieldName = field.getName();
                Object vObj = jsonObject.get(field.getName());
                if(dataType == 0){//字符串类型
                    if(flag == 0) {
                        reportField.setDesc(annotation.desc()); reportField.setName(fieldName); reportField.setSort(annotation.sort());
                        reportField.setWidth(annotation.width()); reportField.setNum(annotation.num()); reportFieldList.add(reportField);
                    }
                    //value.put(fieldName, Objects.isNull(vObj) ? "" : vObj.toString());

                    value.put(fieldName, Objects.isNull(vObj) ? "" : vObj.toString().replaceAll("<", "").replaceAll(">", ""));
                }else if(dataType == 1){//List<String>类型的时候字段名取yearList的值
                    if("yearList".equals(field.getName())) continue;
                    Object yearListObj = jsonObject.get("yearList");
                    if(Objects.isNull(yearListObj) || Objects.isNull(vObj)) continue;
                    List<String> yearList = JSONArray.parseArray(JSONObject.toJSONString(yearListObj), String.class);
                    List<String> vList = JSONArray.parseArray(JSONObject.toJSONString(vObj), String.class);
                    for(int i=0; i<yearList.size(); i++){
                        String year = yearList.get(i);
                        if(flag == 0) {reportField = new ReportField(); reportField.setDesc(year); reportField.setName(year); reportField.setSort(annotation.sort()); reportField.setWidth(annotation.width()); reportField.setNum(annotation.num()); reportFieldList.add(reportField);}
                        String v = vList.get(i);
                        value.put(year, v == null ? "" : v.replaceAll("<", "").replaceAll(">", ""));
                    }
                }
            }
            valueList.add(value); flag++;
        }
        reportFieldList.sort((t1, t2) -> { Integer counts = t1.getSort(); Integer counts1 = t2.getSort(); return counts.compareTo(counts1); });
        Map<String, Object> res = new HashMap<>();
        res.put("nameList", reportFieldList);
        res.put("valueList", valueList);
        return res;
    }

    //jsonStr只支持key:value
    public static Map<String, Object> changeObject(Class<?> clazz, String jsonStr) {
        //获取带有特定注解的字段
        Set<Field> annotatedFields = getAnnotatedFields(clazz, ReportFieldAnnotation.class);
        List<ReportField> reportFieldList = new ArrayList<>();
        JSONObject jsonObject = JSONObject.parseObject(jsonStr);
        List<Map<String, String>> valueList = new ArrayList<>(); Map<String, String> value = new HashMap<>();
        for (Field field : annotatedFields) {
            ReportField reportField = new ReportField();
            ReportFieldAnnotation annotation = field.getAnnotation(ReportFieldAnnotation.class);
            int dataType = annotation.dataType();//0:字符串,1:List<String>
            String fieldName = field.getName();
            Object vObj = jsonObject.get(fieldName);
            if(dataType == 0){//字符串类型
                reportField.setDesc(annotation.desc()); reportField.setName(fieldName); reportField.setSort(annotation.sort()); reportField.setWidth(annotation.width()); reportField.setNum(annotation.num()); reportFieldList.add(reportField);
                value.put(fieldName, Objects.isNull(vObj) ? "" : vObj.toString().replaceAll("<", "").replaceAll(">", ""));
            }else if(dataType == 1){//List<String>类型的时候字段名取yearList的值
                Object yearListObj = jsonObject.get("yearList");
                if(Objects.isNull(yearListObj) || Objects.isNull(vObj)) continue;
                List<String> yearList = JSONArray.parseArray(JSONObject.toJSONString(yearListObj), String.class);
                List<String> vList = JSONArray.parseArray(JSONObject.toJSONString(vObj), String.class);
                for(int i=0; i<yearList.size(); i++){
                    String year = yearList.get(i); String v = vList.get(i);
                    reportField.setDesc(year); reportField.setName(year); reportField.setSort(annotation.sort()); reportField.setWidth(annotation.width()); reportField.setNum(annotation.num()); reportFieldList.add(reportField);
                    value.put(year, v == null ? "" : v.replaceAll("<", "").replaceAll(">", ""));
                }
            }
        }
        valueList.add(value);
        Map<String, Object> res = new HashMap<>();
        reportFieldList.sort((t1, t2) -> { Integer counts = t1.getSort(); Integer counts1 = t2.getSort(); return counts.compareTo(counts1); });
        res.put("nameList", reportFieldList);
        res.put("valueList", valueList);
        return res;
    }

    /** 获取有该注解的字段 */
    public static Set<Field> getAnnotatedFields(Class<?> clazz, Class<? extends Annotation> annotation) {
        Set<Field> fields = new HashSet<>();
        Class<?> superClass = clazz;
        while (superClass != Object.class) {
            for (Field field : superClass.getDeclaredFields()) {
                if (field.isAnnotationPresent(annotation)) {
                    fields.add(field);
                }
            }
            superClass = superClass.getSuperclass();
        }
        return fields;
    }

    /** 个性化数据-列表数据展示 reportFieldList:标题行 value:标题行对应的字段对应的值 */
    public static StringBuffer listHtml(List<ReportField> reportFieldList, List<Map<String,Object>> value){
        List<String> keyList = new ArrayList<>();//存放标题行对应的字段
        StringBuffer tempHtml= new StringBuffer();
        tempHtml.append("<div class=\"table_box_b\">");
        tempHtml.append("<table width=\"100%\" cellspacing=\"0\">");
        tempHtml.append("<tbody>");
        /** -----------------------------标题列start----------------------------------- */
        tempHtml.append("<tr>"); int j=1; int size = reportFieldList.size();
        for(ReportField reportField : reportFieldList){
            if(j==size){
                tempHtml.append("<th height=\"30px\" width=\"").append(reportField.getWidth()).append("%\" nowrap=\"nowrap\" align=\"center\" style=\"").append(ReportLabelUtils.TH_FONT).append("border-bottom: 1px solid #F4F4F6;border-top:1px solid #F4F4F6;border-right:1px solid #F4F4F6;\">").append(reportField.getDesc()).append("</th>");
            } else if(j==1){
                tempHtml.append("<th height=\"30px\" width=\"").append(reportField.getWidth()).append("%\" nowrap=\"nowrap\" align=\"center\" style=\"").append(ReportLabelUtils.TH_FONT).append("border-top:1px solid #F4F4F6;border-left: 1px solid #F4F4F6;border-bottom: 1px solid #F4F4F6;border-right:1px solid #FFFFFF;\">").append(reportField.getDesc()).append("</th>");
            }else{
                tempHtml.append("<th height=\"30px\" width=\"").append(reportField.getWidth()).append("%\" nowrap=\"nowrap\" align=\"center\" style=\"").append(ReportLabelUtils.TH_FONT).append("border-bottom: 1px solid #F4F4F6;border-right: 1px solid #FFFFFF;border-top:1px solid #F4F4F6;\">").append(reportField.getDesc()).append("</th>");
            }
            keyList.add(reportField.getName()); j++;
        }
        tempHtml.append("</tr>");
        /** -----------------------------标题列end----------------------------------- */
        /** -----------------------------数据列start----------------------------------- */
        if(value != null && value.size() > 0){
            for(Map<String, Object> vMap : value) {
                tempHtml.append("<tr>"); int keySize = keyList.size(); int flag = 1;
                for (String key : keyList) {
                    if(keySize==flag){
                        tempHtml.append("<td height=\"30px\" nowrap=\"nowrap\" align=\"center\" style=\"").append(ReportLabelUtils.TD_FONT).append("border-left:1px solid #F4F4F6; border-bottom:1px solid #F4F4F6;border-right:1px solid #F4F4F6;\">").append(vMap.get(key)).append("</td>");
                    }else{
                        tempHtml.append("<td height=\"30px\" nowrap=\"nowrap\" align=\"center\" style=\"").append(ReportLabelUtils.TD_FONT).append("border-left:1px solid #F4F4F6; border-bottom:1px solid #F4F4F6;\">").append(vMap.get(key)).append("</td>");
                    }
                    flag++;
                }
                tempHtml.append("</tr>");
            }
        }
        /** -----------------------------数据列end----------------------------------- */
        tempHtml.append("</tbody></table></div>");
        return tempHtml;
    }

    /** 个性化数据-横着两列标题排列 reportFieldList:标题行 value:标题行对应的字段对应的值 */
    public static StringBuffer twoTitleHtml(List<ReportField> reportFieldList, List<Map<String,Object>> value){
        StringBuffer tempHtml= new StringBuffer();
        for(Map<String, Object> vMap : value){
            tempHtml.append("<div class=\"table_box_b\">");
            tempHtml.append("<table width=\"100%\" cellspacing=\"0\" style=\"border-right:1px solid #cdd3e0; border-top:1px solid #cdd3e0; \">");
            tempHtml.append("<tbody>");
            int flag = 1;
            for(ReportField reportField : reportFieldList){
                if(flag == 1 && flag == reportFieldList.size()){
                    tempHtml.append("<tr>");
                    tempHtml.append("<th height=\"30px\" width=\"25%\" nowrap=\"nowrap\" align=\"center\" style=\"background-color:#EAF2FA; color:#000000; font-size:10px;font-weight: 500;border-top:1px solid #F4F4F6;border-bottom: 1px solid #F4F4F6;border-left: 1px solid #F4F4F6;border-right:1px solid #F4F4F6; \">").append(reportField.getDesc()).append("</th>");
                    tempHtml.append("<td height=\"30px\" width=\"25%\" nowrap=\"nowrap\" align=\"left\" style=\"font-size:10px;padding:5px 5px; line-height:12px;border-top:1px solid #F4F4F6;border-bottom: 1px solid #F4F4F6;border-right:1px solid #F4F4F6;\">").append(vMap.get(reportField.getName())).append("</td>");
                    tempHtml.append("</tr>");
                }else if(flag == 1 || flag == 2){
                    if(flag == 1){
                        tempHtml.append("<tr>");
                        tempHtml.append("<th height=\"30px\" width=\"25%\" nowrap=\"nowrap\" align=\"center\" style=\"background-color:#EAF2FA; color:#000000; font-size:10px;font-weight: 500;border-top:1px solid #F4F4F6;border-bottom: 1px solid #FFFFFF;border-left: 1px solid #F4F4F6;border-right:1px solid #F4F4F6;\">").append(reportField.getDesc()).append("</th>");
                        tempHtml.append("<td height=\"30px\" width=\"25%\" nowrap=\"nowrap\" align=\"left\" style=\"font-size:10px;padding:5px 5px; line-height:12px;border-top:1px solid #F4F4F6;border-bottom: 1px solid #F4F4F6;border-right:1px solid #F4F4F6;\">").append(vMap.get(reportField.getName())).append("</td>");
                    }else{
                        tempHtml.append("<th height=\"30px\" width=\"25%\" nowrap=\"nowrap\" align=\"center\" style=\"background-color:#EAF2FA; color:#000000; font-size:10px;font-weight: 500;border-top:1px solid #F4F4F6;border-bottom: 1px solid #FFFFFF;border-right:1px solid #F4F4F6;\">").append(reportField.getDesc()).append("</th>");
                        tempHtml.append("<td height=\"30px\" width=\"25%\" nowrap=\"nowrap\" align=\"left\" style=\"font-size:10px;padding:5px 5px; line-height:12px;border-top:1px solid #F4F4F6;border-bottom: 1px solid #F4F4F6;border-right:1px solid #F4F4F6;\">").append(vMap.get(reportField.getName())).append("</td>");
                        tempHtml.append("</tr>");
                    }
                } else{
                    if(flag%2 == 1 && flag == reportFieldList.size()){
                        tempHtml.append("<tr>");
                        tempHtml.append("<th height=\"30px\" width=\"25%\" nowrap=\"nowrap\" align=\"center\" style=\"background-color:#EAF2FA; color:#000000; font-size:10px;font-weight: 500;border-bottom: 1px solid #F4F4F6;border-left: 1px solid #F4F4F6;border-right:1px solid #F4F4F6;\">").append(reportField.getDesc()).append("</th>");
                        tempHtml.append("<td height=\"30px\" nowrap=\"nowrap\" align=\"left\" style=\"font-size:10px;;padding:5px 5px; line-height:12px;border-bottom:1px solid #F4F4F6;border-right:1px solid #F4F4F6;\" colspan=\"3\">").append(vMap.get(reportField.getName())).append("</td>");
                        tempHtml.append("</tr>");
                    }else if(flag%2 == 0){
                        tempHtml.append("<th height=\"30px\" width=\"25%\" nowrap=\"nowrap\" align=\"center\" style=\"background-color:#EAF2FA; color:#000000; font-size:10px;font-weight: 500;border-bottom: 1px solid #FFFFFF;border-right:1px solid #F4F4F6;\">").append(reportField.getDesc()).append("</th>");
                        tempHtml.append("<td height=\"30px\" nowrap=\"nowrap\" align=\"left\" style=\"font-size:10px;;padding:5px 5px; line-height:12px;border-bottom:1px solid #F4F4F6;border-right:1px solid #F4F4F6;\">").append(vMap.get(reportField.getName())).append("</td>");
                        tempHtml.append("</tr>");
                    }else{
                        tempHtml.append("<tr>");
                        tempHtml.append("<th height=\"30px\" width=\"25%\" nowrap=\"nowrap\" align=\"center\" style=\"background-color:#EAF2FA; color:#000000; font-size:10px;font-weight: 500;border-bottom: 1px solid #FFFFFF;border-left: 1px solid #F4F4F6;border-right:1px solid #F4F4F6;\">").append(reportField.getDesc()).append("</th>");
                        tempHtml.append("<td height=\"30px\" width=\"30%\" nowrap=\"nowrap\" align=\"left\" style=\"font-size:10px;;padding:5px 5px; line-height:12px;border-bottom:1px solid #F4F4F6;border-right:1px solid #F4F4F6;\">").append(vMap.get(reportField.getName())).append("</td>");
                    }
                }
                flag++;
            }
            tempHtml.append("</tbody></table></div>");
        }
        return tempHtml;
    }

    /** 个性化数据-横着单列标题排列 reportFieldList:标题行 value:标题行对应的字段对应的值 */
    public static StringBuffer oneTitleHtml(List<ReportField> reportFieldList, List<Map<String,Object>> value){
        StringBuffer tempHtml= new StringBuffer();
        for(Map<String, Object> vMap : value){
            tempHtml.append("<div class=\"table_box_b\">");
            tempHtml.append("<table width=\"100%\" border=\"0\" cellspacing=\"0\" style=\"border-right:1px solid #cdd3e0; border-top:1px solid #cdd3e0;\">");
            tempHtml.append("<tbody>");
            int flag = 1;
            for(ReportField reportField : reportFieldList){
                if(flag == 1){
                    tempHtml.append("<tr>");
                    tempHtml.append("<th height=\"30px\" width=\"25%\" nowrap=\"nowrap\" align=\"center\" style=\"").append(ReportLabelUtils.TH_FONT).append("border-top:1px solid #F4F4F6;border-bottom: 1px solid #F4F4F6;border-left: 1px solid #F4F4F6;border-right:1px solid #F4F4F6;\">").append(reportField.getDesc()).append("</th>");
                    tempHtml.append("<td height=\"30px\" width=\"75%\" nowrap=\"nowrap\" align=\"left\" style=\"").append(ReportLabelUtils.TD_FONT).append("border-top:1px solid #F4F4F6;border-bottom:1px solid #F4F4F6;border-right:1px solid #F4F4F6;\">").append(vMap.get(reportField.getName())).append("</td>");
                    tempHtml.append("</tr>");
                }else{
                    tempHtml.append("<tr>");
                    tempHtml.append("<th height=\"30px\" width=\"25%\" nowrap=\"nowrap\" align=\"center\" style=\"").append(ReportLabelUtils.TH_FONT).append("border-bottom: 1px solid #F4F4F6;border-left: 1px solid #F4F4F6;border-right:1px solid #F4F4F6;\">").append(reportField.getDesc()).append("</th>");
                    tempHtml.append("<td height=\"30px\" width=\"75%\" nowrap=\"nowrap\" align=\"left\" style=\"").append(ReportLabelUtils.TD_FONT).append("border-bottom: 1px solid #F4F4F6;border-right:1px solid #F4F4F6;\">").append(vMap.get(reportField.getName())).append("</td>");
                    tempHtml.append("</tr>");
                }
                flag++;
            }
            tempHtml.append("</tbody></table></div>");
        }
        return tempHtml;
    }

    /** 文本内容 content:文本内容;level:标题等级 */
    public static StringBuffer title(String content, int level){
        StringBuffer description = new StringBuffer();
        if(level == 1) {
            description.append("<br/><div align=\"left\"><img style=\"height:30px;width:520px;\" src=\"").append(forTitle1(content)).append("\"/></div>");
        }
        if(level == 2) {
            description.append("<br/><div align=\"left\"><img style=\"height:30px;width:520px;\" src=\"").append(forTitle2(content)).append("\"/></div>");
        }
        if(level == 3) {
            description.append("<br/><div>");
            description.append("<img style=\"height: 15px; width:10px\" src=\"").append(ConstantConfig.RISK_IMAGE + "三级标题.jpg").append("\"/>&thinsp; <span style=\"font-weight: 900;color:#005BAB;\">").append(content).append("</span>");
            description.append("</div>");
        }
        return description;
    }

    /** 文本内容 content:文本内容;fontSize:字体大小;color:字体颜色;backgroundColor:背景色 */
    public static StringBuffer description(String content, int fontSize, String color, String backgroundColor, int fontWeight){
        StringBuffer description = new StringBuffer();
//        description.append("<br/>");
        description.append("<div align=\"left\" style=\"");
        if(fontWeight > 0) description.append("font-weight:").append(fontWeight).append(";");
        if(fontSize > 0) description.append("font-size:").append(fontSize).append("px;");
        if(StringUtils.isNotBlank(color)) description.append("color:").append(color).append(";");
        if(StringUtils.isNotBlank(color)) description.append("padding-left:12px;padding-right:12px;padding-bottom:12px;background-color:").append(backgroundColor).append(";");
        description.append("line-height:").append(1.5).append(";");
        description.append("letter-spacing:").append(1.2).append("px;");
        description.append("\">");
        description.append("&nbsp;&nbsp;");
        description.append(content).append("</div>");
//        description.append("<br/>");
        return description;
    }

    /**
     * 加载图片(柱状图/折线图)
     */
    public static StringBuffer getImgOneHtml(String title, List<String> xData, List<Double> yDataList, List<Color> colorList, String yUnit, int type,
                                             int width, int height, double SpaceFill, StringBuffer tempHtml) {
        if (xData == null || xData.size() == 0) return tempHtml;
        String path = new HistogramChar<>().getChart2(title, xData, yDataList, colorList, yUnit, type,
                width, height, SpaceFill);
        tempHtml.append("<div align=\"center\"><img style=\"height:262px;width:700px\" src=\"").append(path).append("\"/></div>");
        return tempHtml;
    }

    /**
     * 加载图片(扇形图)
     */
    public static StringBuffer getImgPieHtml(List<String> keyList, List<Double> rDataList, Boolean isTitleVisible, String title,
                                             Boolean isLegendVisible, RectangleEdge rectangleEdge, int flag, StringBuffer tempHtml) {
        if (rDataList == null || rDataList.size() == 0) return tempHtml;
        tempHtml.append("<div align=\"center\">");
        String path = Pie2Chart.pieChart(keyList, rDataList, isTitleVisible, title, isLegendVisible, rectangleEdge, flag);
        tempHtml.append("<img style=\"width:700px\" src=\"").append(path).append("\"/>");
        tempHtml.append("</div>");
        return tempHtml;
    }

    /**
     * 加图片做pdf首页的底纹
     * @param srcPdfPath 源文件
     * @param tagetPdfPath  加工后文件
     * @param pageNum        页码
     * @param type           底纹类型:0:客户风险分析报告;1:客群风险分析报告
     */
    public static void addImageWatermark(String srcPdfPath, String tagetPdfPath, int pageNum, int type) {
        try {
            // 加载PDF文件
            PdfReader reader = new PdfReader(srcPdfPath);
            PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(tagetPdfPath));
            int total = reader.getNumberOfPages();
            if(pageNum < 0) pageNum = total + pageNum;
            // 首页-头部-底纹
            com.itextpdf.text.Image watermark = com.itextpdf.text.Image.getInstance(ConstantConfig.RISK_IMAGE + "首页-头部-底纹.png");
            watermark.setAbsolutePosition(-2, 705); // 设置底纹位置
            watermark.scaleAbsolute(597, 135); // 设置底纹大小
            // 首页-中间-底纹
            com.itextpdf.text.Image watermark1 = com.itextpdf.text.Image.getInstance(ConstantConfig.RISK_IMAGE + "首页-中间-底纹.png");
            watermark1.setAbsolutePosition(-2, 155); // 设置底纹位置
            watermark1.scaleAbsolute(597, 700); // 设置底纹大小
            // 文字 - 客群风险分析报告/客户风险分析报告
            com.itextpdf.text.Image watermark_word1 = com.itextpdf.text.Image.getInstance(ConstantConfig.RISK_IMAGE + (type==0 ? "客户风险分析报告" : "客群风险分析报告") +".png");
            watermark_word1.setAbsolutePosition(200, 515); // 设置底纹位置
            watermark_word1.scaleAbsolute(360, 40); // 设置底纹大小
            // 首页-矩形-底纹
            com.itextpdf.text.Image watermark_line1 = com.itextpdf.text.Image.getInstance(ConstantConfig.RISK_IMAGE + "首页-矩形-底纹.png");
            watermark_line1.setAbsolutePosition(200, 485); // 设置底纹位置
            watermark_line1.scaleAbsolute(360, 2); // 设置底纹大小
            // 首页-分割线-底纹
            com.itextpdf.text.Image watermark_line2 = com.itextpdf.text.Image.getInstance(ConstantConfig.RISK_IMAGE + "首页-分割线-底纹.png");
            watermark_line2.setAbsolutePosition(-2, 153); // 设置底纹位置
            watermark_line2.scaleAbsolute(597, 1); // 设置底纹大小
            // 首页-底部-底纹
            com.itextpdf.text.Image watermark2 = com.itextpdf.text.Image.getInstance(ConstantConfig.RISK_IMAGE + "首页-底部-底纹.png");
            watermark2.setAbsolutePosition(-2, -2); // 设置底纹位置
            watermark2.scaleAbsolute(597, 215); // 设置底纹大小
            // 将底纹添加到首页页面
            PdfContentByte content = stamper.getOverContent(pageNum);
            content.addImage(watermark);
            content.addImage(watermark1);
            content.addImage(watermark_word1);
            content.addImage(watermark_line1);
            content.addImage(watermark_line2);
            content.addImage(watermark2);
            // 获取原始PDF内容并添加到新的PDF中
            PdfImportedPage page = stamper.getImportedPage(reader, pageNum);
            int rotation = reader.getPageRotation(1);
            if (rotation == 90 || rotation == 270) {
                content.addTemplate(page, 0, -1, 1, 0, 0, 610);
            } else {
                content.addTemplate(page, 1, 0, 0, 1, 0, 0);
            }
            // 关闭PDF文件
            stamper.close();
            reader.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * 加图片做pdf页眉
     * @param pdfFilePath 源文件
     * @param toFdfPath  加工后文件
     */
    public static void pdf_yemei(String companyName, String pdfFilePath, String toFdfPath) {
        try {
            String NoFirstYeMeiImage = baseUrl + companyName + "合并后图片.png";
            getImageAndChar2(ConstantConfig.RISK_IMAGE + "非首页-页眉.jpg", NoFirstYeMeiImage, companyName);
            // 加载PDF文件
            PdfReader reader = new PdfReader(pdfFilePath);
            PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(toFdfPath));
            int total = reader.getNumberOfPages();
            int pageNum = 1;
            while(pageNum < total) {
                pageNum++;
                if (pageNum <= 1) continue;
                // 非首页-页眉
                com.itextpdf.text.Image yemei = com.itextpdf.text.Image.getInstance(NoFirstYeMeiImage);
                yemei.setAbsolutePosition(0, 807); // 设置底纹位置
                yemei.scaleAbsolute(597, 33); // 设置底纹大小
                // 将底纹添加到首页页面
                PdfContentByte content = stamper.getOverContent(pageNum);
                content.addImage(yemei);
                // 获取原始PDF内容并添加到新的PDF中
                PdfImportedPage page = stamper.getImportedPage(reader, pageNum);
                int rotation = reader.getPageRotation(1);
                if (rotation == 90 || rotation == 270) {
                    content.addTemplate(page, 0, -1, 1, 0, 0, 610);
                } else {
                    content.addTemplate(page, 1, 0, 0, 1, 0, 0);
                }
            }
            // 关闭PDF文件
            stamper.close();
            reader.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /** 页眉专用 -- 合并文字和图片,生成一个新的图片 */
    public static void getImageAndChar2(String srcImagePath, String toImagePath, String content){
        try {
            // 读取第一张图片
            BufferedImage image1 = ImageIO.read(new File(srcImagePath));
            /** 创建一个新的BufferedImage,其宽度为两张图片的宽度之和,高度为两张图片中较高的那张图片的高度 */
            BufferedImage mergedImage = new BufferedImage(image1.getWidth(), image1.getHeight(), image1.getType());
            /** 创建Graphics2D对象以在新的合并图像上绘图 */
            Graphics2D g2d = mergedImage.createGraphics();
            g2d.drawImage(image1, 0, 0, null);
            /** 设置字体和颜色 */
            Font font = new Font("黑体", Font.BOLD, 70); g2d.setFont(font); g2d.setColor(Color.white);
            // 在合并图像上绘制汉字
            String text = content; // 这里可以替换为您想要显示的汉字
            int x = 270; // 汉字的起始位置,可以根据需要调整
            int y = 90; // 汉字的垂直位置,可以根据需要调整
            for (int i = 0; i < text.length(); i++) {
                char c = text.charAt(i);
                g2d.drawString(String.valueOf(c), x + i * 70, y); // 在每个汉字之间添加一些间距,可以根据需要调整间距大小
            }
            // 释放此图形的上下文以及它使用的所有系统资源
            g2d.dispose();
            // 将合并后的图像写入文件
            ImageIO.write(mergedImage, "png", new File(toImagePath));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /** 1级标题专用 -- 合并文字和图片,生成一个新的图片 */
    public static String forTitle1(String content){
        String toImagePath = baseUrl + System.currentTimeMillis();
        try {
            // 读取第一张图片
            BufferedImage image1 = ImageIO.read(new File(ConstantConfig.RISK_IMAGE + "一级标题.jpg"));
            /** 创建一个新的BufferedImage,其宽度为两张图片的宽度之和,高度为两张图片中较高的那张图片的高度 */
            BufferedImage mergedImage = new BufferedImage(image1.getWidth(), image1.getHeight(), image1.getType());
            /** 创建Graphics2D对象以在新的合并图像上绘图 */
            Graphics2D g2d = mergedImage.createGraphics();
            g2d.drawImage(image1, 0, 0, null);
            /** 设置字体和颜色 */
            Font font = new Font("黑体", Font.BOLD, 50); g2d.setFont(font); g2d.setColor(new Color(0, 91, 171));
            // 在合并图像上绘制汉字
            String text = content; // 这里可以替换为您想要显示的汉字
            int x = 240; // 汉字的起始位置,可以根据需要调整
            int y = 60; // 汉字的垂直位置,可以根据需要调整
            for (int i = 0; i < text.length(); i++) {
                char c = text.charAt(i);
                g2d.drawString(String.valueOf(c), x + i * 55, y); // 在每个汉字之间添加一些间距,可以根据需要调整间距大小
            }
            // 释放此图形的上下文以及它使用的所有系统资源
            g2d.dispose();
            // 将合并后的图像写入文件
            ImageIO.write(mergedImage, "jpg", new File(toImagePath));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return toImagePath;
    }

    /** 2级标题专用 -- 合并文字和图片,生成一个新的图片 */
    public static String forTitle2(String content){
        String toImagePath = baseUrl + System.currentTimeMillis();
        try {
            // 读取第一张图片
            BufferedImage image1 = ImageIO.read(new File(ConstantConfig.RISK_IMAGE + "二级标题.jpg"));
            /** 创建一个新的BufferedImage,其宽度为两张图片的宽度之和,高度为两张图片中较高的那张图片的高度 */
            BufferedImage mergedImage = new BufferedImage(image1.getWidth(), image1.getHeight(), image1.getType());
            /** 创建Graphics2D对象以在新的合并图像上绘图 */
            Graphics2D g2d = mergedImage.createGraphics();
            g2d.drawImage(image1, 0, 0, null);
            /** 设置字体和颜色 */
            Font font = new Font("黑体", Font.BOLD, 40); g2d.setFont(font); g2d.setColor(Color.white);
            // 在合并图像上绘制汉字
            String text = content; // 这里可以替换为您想要显示的汉字
            int x = 50; // 汉字的起始位置,可以根据需要调整
            int y = 50; // 汉字的垂直位置,可以根据需要调整
            for (int i = 0; i < text.length(); i++) {
                char c = text.charAt(i);
                g2d.drawString(String.valueOf(c), x + i * 45, y); // 在每个汉字之间添加一些间距,可以根据需要调整间距大小
            }
            // 释放此图形的上下文以及它使用的所有系统资源
            g2d.dispose();
            // 将合并后的图像写入文件
            ImageIO.write(mergedImage, "jpg", new File(toImagePath));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return toImagePath;
    }

}

实体类

java 复制代码
package com.ruoyi.business.bankInterface.controller.risk.model1;

import com.alibaba.fastjson2.JSONArray;
import com.ruoyi.business.bankInterface.controller.risk.utils.ReportLabelUtils;
import com.ruoyi.business.bankInterface.controller.risk.utils.ReportUtils2;
import com.ruoyi.business.bankInterface.controller.tax.utils.annotation.ReportFieldAnnotation;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * 公司治理
 */
@Data
public class K3 {
    @ReportFieldAnnotation(desc = "变更时间", sort = 1)
    private String bgsj;
    @ReportFieldAnnotation(desc = "变更事项", sort = 2)
    private String bgsx;
    @ReportFieldAnnotation(desc = "变更前", sort = 3)
    private String bgq;
    @ReportFieldAnnotation(desc = "变更后", sort = 4)
    private String bgh;
    @ReportFieldAnnotation(desc = "风险等级", sort = 5)
    private String fxdj;
    private String fxxl;

    public String getBgq() {
        if(StringUtils.isNotBlank(bgq)){
            int start = bgq.indexOf("(");
            int end = bgq.indexOf(")");
            if(start > 0 && end > 0){
                bgq = bgq.substring(0, start)+bgq.substring(end+1);
            }
        }
        return bgq;
    }

    public String getBgh() {
        if(StringUtils.isNotBlank(bgh)){
            int start = bgh.indexOf("(");
            int end = bgh.indexOf(")");
            if(start > 0 && end > 0){
                bgh = bgh.substring(0, start)+bgh.substring(end+1);
            }
        }
        return bgh;
    }

    public String getFxdj() {
        if(StringUtils.isNotBlank(fxdj)){
            if("红".equals(fxdj)) fxdj = "严重警告";
            if("橙".equals(fxdj)) fxdj = "警告";
            if("黄".equals(fxdj)) fxdj = "关注";
            if("提示".equals(fxdj)) fxdj = "提示";
        }
        return fxdj;
    }

    /** 公司治理 */
    public static StringBuffer getHtml1(List<K3> k3List){
        StringBuffer k3Html = new StringBuffer();
        if(k3List == null || k3List.size() == 0){
            k3Html.append(ReportUtils2.description("监测本公司近一年的注册资本、企业股东或高管、企业法定代表人变更情况,皆未发现有异常更改记录。",  12, ReportLabelUtils.NO_FX_COLOR, ReportLabelUtils.NO_FX_BACKGROUND_COLOR, 0));
        }else{
            k3Html.append(ReportUtils2.description("监测本公司近一年的注册资本、企业股东或高管、企业法定代表人变更情况,发现以下风险:",  12, ReportLabelUtils.FX_COLOR, ReportLabelUtils.FX_BACKGROUND_COLOR, 0));
            ReportUtils2.listHtml(K3.class, JSONArray.toJSONString(changeK3List(k3List)), k3Html, 1, 1);
        }
        return k3Html;
    }

    /** 经营资质 */
    public static StringBuffer getHtml2(List<K3> k3List){
        StringBuffer k3Html = new StringBuffer();
        k3Html.append(ReportUtils2.title("经营资质", 3));
        if(k3List == null || k3List.size() == 0){
            k3Html.append(ReportUtils2.description("本风险监测时段中,未监测到企业存在经营资质风险。",  12, ReportLabelUtils.NO_FX_COLOR, ReportLabelUtils.NO_FX_BACKGROUND_COLOR, 0));
        }else{
            StringBuffer text = new StringBuffer();
            text.append("在本风险监测时段中,监测到"+k3List.size()+"条经营资质风险,其中");
            if (k3List.stream().filter(item->"R004".equals(item.getFxxl())).count()>0)
                text.append("企业工商信息变更风险"+k3List.stream().filter(item->"R004".equals(item.getFxxl())).count()+
                        "条。");
            if (k3List.stream().filter(item->"R005".equals(item.getFxxl())).count()>0)
                text.append("企业经营期限到期或状态为'非存续'风险"+k3List.stream().filter(item->"R005".equals(item.getFxxl())).count()+
                        "条。");

            k3Html.append(ReportUtils2.description(
//                    "本风险监测时段中,监测到企业存在"+k3List.size()+"条经营资质风险,其中企业工商信息变更风险"+
//                    k3List.stream().filter(item ->"R004".equals(item.getFxxl())).count()+"条,企业经营期限到期或状态为'非存续'风险"+
//                    k3List.stream().filter(item ->"R005".equals(item.getFxxl())).count()+"条。"
                    text.toString()
                    ,  12, ReportLabelUtils.FX_COLOR, ReportLabelUtils.FX_BACKGROUND_COLOR, 0));
            ReportUtils2.listHtml(K3.class, JSONArray.toJSONString(k3List), k3Html, 1, 1);
        }
        return k3Html;
    }

    /** 剔除数据 */
    private static List<K3> changeK3List(List<K3> k3List){
        if(k3List == null || k3List.size() == 0) return k3List;
        List<K3> k3NewList = new ArrayList<>();
        for(K3 k3 : k3List){
            /** 剔除掉企业注册资金非减少的数据 */
            try {
                if("企业注册资本抽离".equals(k3.getBgsx()) && Double.valueOf(k3.getBgq()) <= Double.valueOf(k3.getBgh())) continue;
                k3NewList.add(k3);
            }catch (Exception e){

            }

        }
        return k3NewList;
    }

   
}

pdf工具类(根据html生成pdf文件)

java 复制代码
package com.ruoyi.business.bankInterface.controller.risk;

import com.itextpdf.text.*;
import com.itextpdf.text.Image;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.*;
import com.itextpdf.tool.xml.XMLWorkerHelper;
import com.ruoyi.business.bankInterface.controller.tax.utils.DateUtils;
import com.ruoyi.business.bankInterface.domain.utils.AsianFontProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.nio.charset.Charset;
import java.util.Date;
import java.util.Enumeration;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.List;

public class PdfUtils {
//    public static final String imgPrefixUrl="/home/cc/data/images/";
        public static final String imgPrefixUrl="D:\\test\\images\\";
    private static final Logger logger = LoggerFactory.getLogger(PdfUtils.class);

    //根据html生成pdf文件
//    public static void htmp2pdf(String creditName, String pdfName,String template){
//        Document document = null;
//        PdfWriter pdfWriter = null;
//        try {
//            document = new Documapi/v1/financial/queryFinancialDataent(PageSize.A4);
//            pdfWriter = PdfWriter.getInstance(document, new FileOutputStream(pdfName));
//            document.open();
//            document.addAuthor("Soren");
//            document.addCreator("Soren");
//            document.addCreationDate();
//            document.addTitle("测试生成pdf");
//            XMLWorkerHelper helper = XMLWorkerHelper.getInstance();
//            //读取模板文件并且写入String中
//            InputStream in = new FileInputStream(template);
//            InputStreamReader isr = new InputStreamReader(in, "utf-8");
//            BufferedReader brd = new BufferedReader(isr);
//            StringBuffer sbf = new StringBuffer();
//            String line = "";
//            while((line=brd.readLine())!=null) {
//                sbf.append(line);
//            }
//            String htmlTemplete = sbf.toString();
//
//            //此处替换特定字符或者拼接html代码的处理
//            htmlTemplete = htmlTemplete.replaceAll("###TITLE###", "长三角征信链企业征信报告");
//            htmlTemplete = htmlTemplete.replaceAll("###INTRODUCE###", "该报告来源:"+creditName);
//            htmlTemplete = htmlTemplete.replaceAll("###date###", "日期:"+DateUtils.convertYMD(new Date()));
            htmlTemplete = htmlTemplete.replaceAll("###date###", "日期:"+UUID.randomUUID().toString());
//            //模板不支持svg格式图片
//            helper.parseXHtml(pdfWriter, document, new ByteArrayInputStream(htmlTemplete.getBytes("UTF-8")), Charset.forName("utf8"), new AsianFontProvider());
//            logger.info("根据html生成pdf文件完成!");
//        } catch (FileNotFoundException e) {
//            e.printStackTrace();
//        } catch (DocumentException e) {
//            e.printStackTrace();
//        } catch (IOException e) {
//            e.printStackTrace();
//        }finally {
//            if(document!=null)
//                //如果不关闭则会生成空的破损的pdf
//                document.close();
//        }
//        return;
//    }

    //根据html生成pdf文件
//    public static void htmppdf(String htmlStr, String pdfName, Boolean isTrue){
//        Document document = null;
//        PdfWriter pdfWriter = null;
//        try {
//            document = new Document(PageSize.A4);
//            pdfWriter = PdfWriter.getInstance(document, new FileOutputStream(pdfName));
//            document.open();
//            document.addAuthor("Soren");
//            document.addCreator("Soren");
//            document.addCreationDate();
//            document.addTitle("测试生成pdf");
//            XMLWorkerHelper helper = XMLWorkerHelper.getInstance();
//            //模板不支持svg格式图片
//            helper.parseXHtml(pdfWriter, document, new ByteArrayInputStream(htmlStr.getBytes("UTF-8")), Charset.forName("utf8"), new AsianFontProvider());
//            logger.info("根据html生成pdf文件完成!");
//            if(isTrue){
//                //先把文件名字更换为临时名字
//                String temName = pdfName.substring(0, pdfName.lastIndexOf(".")) + "temp" + pdfName.substring(pdfName.lastIndexOf("."));//临时文件名
//                renameFile(pdfName, temName);
//                //文件加水印,输出原文件名
//                waterMark(temName,
//                        pdfName);
//            }
//        } catch (FileNotFoundException e) {
//            e.printStackTrace();
//        } catch (DocumentException e) {
//            e.printStackTrace();
//        } catch (IOException e) {
//            e.printStackTrace();
//        }finally {
//            if(document!=null)
//                //如果不关闭则会生成空的破损的pdf
//                document.close();
//        }
//        return;
//    }
    /*
     * 合并pdf文件
     * @param files 要合并文件数组(绝对路径如{ "e:\\1.pdf", "e:\\2.pdf" ,
     * "e:\\3.pdf"}),合并的顺序按照数组中的先后顺序,如2.pdf合并在1.pdf后。
     * @param newfile 合并后新产生的文件绝对路径,如 e:\\temp\\tempNew.pdf,
     * @return boolean 合并成功返回true;否则,返回false
     *
     */
    public static boolean mergePdfFiles(List<String> files, String newfile) {
        boolean retValue = false;
        Document document = null;
        OutputStream os = null;
        PdfReader reader1 = null;
        PdfCopy copy = null;
        PdfReader reader = null;
        try {
            reader1 = new PdfReader(files.get(0));
            document = new Document(reader1.getPageSize(1));
            os = new FileOutputStream(newfile);
            copy = new PdfCopy(document, os);
            document.open();
            for (int i = 0; i < files.size(); i++) {
                reader = new PdfReader(files.get(i));
                int n = reader.getNumberOfPages();
                for (int j = 1; j <= n; j++) {
                    document.newPage();
                    PdfImportedPage page = copy.getImportedPage(reader, j);
                    copy.addPage(page);
                }
            }
            retValue = true;
        } catch (Exception e) {
            e.printStackTrace();
            logger.info("合并文件.error:"+e.getMessage());
        } finally {
            try {
                if(reader != null){
                    reader.close();
                }
                if(copy != null){
                    copy.close();
                }
                if(os != null){
                    os.close();
                }
                if(reader1 != null){
                    reader1.close();
                }
                if(document != null){
                    document.close();
                }
            }catch (Exception e){
                e.printStackTrace();
                logger.info(e.getMessage());
            }

        }
        logger.info("合并pdf文件完成!");
        return retValue;
    }

    /*
     * pdf文件是否加密授权(加密文件不可更改。加一层水印,如果加成功,表示不是加密文件)
     */
    public static boolean isEncryption(String oFile) {
        boolean retValue = false;
        PdfReader reader = null;
        PdfStamper stamper = null;
        try {
            String waterMarkName = "长三角征信链";
            reader = new PdfReader(oFile);
            stamper = new PdfStamper(reader, new FileOutputStream(
                    oFile+"123"));

            BaseFont base = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H",   BaseFont.EMBEDDED);
            Rectangle pageRect = null;
            PdfGState gs = new PdfGState();
            gs.setFillOpacity(0.2f);//控制水印深浅
            gs.setStrokeOpacity(0.4f);
            int total = reader.getNumberOfPages() + 1;
            JLabel label = new JLabel();
            FontMetrics metrics;
            int textH = 0;
            int textW = 0;
            label.setText(waterMarkName);
            metrics = label.getFontMetrics(label.getFont());
            textH = metrics.getHeight();
            textW = metrics.stringWidth(label.getText());

            PdfContentByte under;
            for (int i = 1; i < total; i++) {
                pageRect = reader.getPageSizeWithRotation(i);
                under = stamper.getOverContent(i);
                under.saveState();
                under.setGState(gs);
                under.beginText();
                under.setFontAndSize(base, 15);//控制水印字体大小
                // 水印文字成30度角倾斜
                //你可以随心所欲的改你自己想要的角度
                for (int height = interval + textH; height < pageRect.getHeight();
                     height = height + textH*5) {
                    for (int width = interval + textW; width < pageRect.getWidth() + textW;
                         width = width + textW*2) {
                        under.showTextAligned(Element.ALIGN_LEFT
                                , waterMarkName, width - textW,
                                height - textH, 30);
                    }
                }
                // 添加水印文字
                under.endText();
            }
        } catch (Exception e) {
            retValue = true;
        }finally {
            try {
                //一定不要忘记关闭流
                if(stamper != null){
                    stamper.close();
                }
                if(reader != null){
                    reader.close();
                }
            }catch (Exception e){
                e.printStackTrace();
                logger.info(e.getMessage());
            }
        }
        return retValue;
    }


    /**文件转换为字节数组
     * @param file
     * @return
     */
    public static byte[] fileToByteArray(File file) {
        byte[] imagebs = null;
        FileInputStream fis = null;
        ByteArrayOutputStream baos = null;
        try {
            //读取输入的文件====文件输入流
            fis = new FileInputStream(file);
            //字节数组输出流  在内存中创建一个字节数组缓冲区,所有输出流的数据都会保存在字符数组缓冲区中
            baos = new ByteArrayOutputStream();
            int len;
            byte[] buffer = new byte[1024];
            //将文件读入到字节数组中
            while ((len = fis.read(buffer)) != -1) {
                // 将指定字节数组中从偏移量 off 开始的 len 个字节写入此字节数组输出流。
                baos.write(buffer, 0, len);
            }
            imagebs = baos.toByteArray();//当前输出流的拷贝  拷贝到指定的字节数组中


            baos.close();
            fis.close();
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            try {
                //一定不要忘记关闭流
                if(baos != null){
                    baos.close();
                }
                if(fis != null){
                    fis.close();
                }
            }catch (Exception e){
                e.printStackTrace();
                logger.info(e.getMessage());
            }

        }

        return imagebs;

    }

    /**根据byte[] 数组生成文件  (在本地)
     * @param bfile  字节数组
     * @param filePath 文件路径
     */
    public static void getFile(byte[] bfile, String filePath) {
        BufferedOutputStream bos = null;  //带缓冲得文件输出流
        FileOutputStream fos = null;      //文件输出流
        File file = null;
        try {
            String path = filePath.substring(0,filePath.lastIndexOf(File.separator));
            File dir = new File(path);
            if(!dir.exists()){//判断文件目录是否存在
                dir.mkdirs();
            }
            file = new File(filePath);  //文件路径+文件名
            fos = new FileOutputStream(file);
            bos = new BufferedOutputStream(fos);
            bos.write(bfile);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (bos != null) {
                try {
                    bos.close();
                } catch (Exception e1) {
                    e1.printStackTrace();
                }
            }
            if (fos != null) {
                try {
                    fos.close();
                } catch (Exception e1) {
                    e1.printStackTrace();
                }
            }
        }
    }

    /**
     * 给文件重命名
     */
    public static void renameFile(String oldname,String newname){
        logger.info("重命名文件开始oldname=" + oldname + "&newname=" + newname);
        if(!oldname.equals(newname)){//新的文件名和以前文件名不同时,才有必要进行重命名
            File oldfile=new File(oldname);
            File newfile=new File(newname);
            if(!oldfile.exists()){
                logger.info("重命名文件不存在!");
                return;//重命名文件不存在
            }
            if(newfile.exists())//若在该目录下已经有一个文件和新文件名相同,则不允许重命名
                logger.info(newname+"已经存在!");
            else{
                oldfile.renameTo(newfile);
            }
        }else{
            logger.info("新文件名和旧文件名相同...");
        }
    }
    private static int interval = -5;
    //给pdf加水印
    public static void waterMark(String inputFile,
                                 String outputFile,
                                 String userName,
                                 String time
    ) {
        PdfReader reader = null;
        PdfStamper stamper = null;
        FileOutputStream outputStream = null;
        try {
            String waterMarkName = "长三角";
            reader = new PdfReader(inputFile);
            outputStream = new FileOutputStream(outputFile);
            stamper = new PdfStamper(reader, outputStream);

            BaseFont base = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H",   BaseFont.EMBEDDED);

            Rectangle pageRect = null;
            PdfGState gs = new PdfGState();
            gs.setFillOpacity(0.15f);//控制水印深浅
            gs.setStrokeOpacity(0.4f);
            int total = reader.getNumberOfPages() + 1;

            JLabel label = new JLabel();
            FontMetrics metrics;
            int textH = 0;
            int textW = 0;
            label.setText(waterMarkName);
            metrics = label.getFontMetrics(label.getFont());
            textH = metrics.getHeight();
            textW = metrics.stringWidth(label.getText());

            PdfContentByte under;
            for (int i = 1; i < total; i++) {
                pageRect = reader.getPageSizeWithRotation(i);
                under = stamper.getOverContent(i);
                under.saveState();
                under.setGState(gs);
                under.beginText();
                under.setFontAndSize(base, 18);//控制水印字体大小
                // 水印文字成30度角倾斜
                // 获取每一页的高度、宽度
                float pageHeight = pageRect.getHeight();
                float pageWidth = pageRect.getWidth();

                // 根据纸张大小多次添加, 水印文字成30度角倾斜
                for (int height = interval + textH; height < pageHeight; height = height + textH * 8) {
                    for (int width = interval + textW; width < pageWidth + textW; width = width + textW * 3) {
                        // 将分段的字段进行输出编写
                        under.setFontAndSize(base, 18);//控制水印字体大小
                        under.showTextAligned(Element.ALIGN_LEFT, waterMarkName, width - textW, height -textH , 30);
                        under.setFontAndSize(base, 12);//控制水印字体大小
                        under.showTextAligned(Element.ALIGN_LEFT, userName, width - textW+12, height -textH*2 , 30);
                        under.setFontAndSize(base, 12);//控制水印字体大小
                        under.showTextAligned(Element.ALIGN_LEFT, time, width - textW+24, height -textH*3 , 30);
                    }
                }

                under.endText();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            try {
                if(stamper != null){
                    stamper.close();
                }
                if(outputStream != null){
                    outputStream.close();
                }
                if(reader != null){
                    reader.close();
                }
            }catch (Exception e){
                e.printStackTrace();
                logger.info(e.getMessage());
            }
        }
    }

    public static void main(String[] args) {
//        renameFile("D:\\test\\123.pdf","D:\\test\\模板.pdf");
        //根据html生成pdf
//        PdfUtils.htmp2pdf("苏信", "D:\\test\\1234.pdf","D:\\test\\template(3).html");
//        PdfUtils.htmp2pdf("<br/>苏州征信、江苏省南京分融服务信用平台、安徽征信", "D:\\test\\123.pdf","D:\\test\\first.html");
//        D:\test\template(1).html

        //合并pdf文件
//        List<String> files = new ArrayList<>();
//        files.add("D:\\test\\123.pdf");
//        files.add("D:\\test\\1234.pdf");
//        String savepath = "D:\\test\\xiaomingnew.pdf";
//        Boolean bool = mergePdfFiles(files, savepath);
//        //给pdf加水印
//        waterMark("D:\\test\\xiaomingnew.pdf", "D:\\test\\666.pdf", "xoads", "2021");
//        String pdfName = "/d:cdc.cdsc.csdcs";
//        String begin = pdfName.substring(0, pdfName.lastIndexOf("."));
//        String endStr = pdfName.substring(pdfName.lastIndexOf("."));
//        System.out.println("begin="+begin);
        System.out.println("endStr=" + "xxx.pdf".substring(0, "xxx.pdf".length() - 4));


//        try {
//            //合并pdf文件
//            Boolean bool = PdfUtils.mergePdfFiles(Arrays.asList("D:\\test\\666.pdf","D:\\test\\666.pdf"), "D:\\test\\777.pdf");
//        }catch (Exception e){
//        }


    }

    //解压文件
    public static void zipToFile(String sourceFile, String toFolder) throws Exception {
        InputStream inputStream = null;
        OutputStream outputStream = null;
        ZipFile zfile = null;
        try {
            String toDisk = toFolder;//接收解压后的存放路径
            zfile = new ZipFile(sourceFile);//连接待解压文件
            logger.info("要解压的文件是:"+ zfile.getName());
            Enumeration zList = zfile.entries();//得到zip包里的所有元素
            ZipEntry ze = null;
            byte[] buf = new byte[1024];
            while (zList.hasMoreElements()) {
                ze = (ZipEntry) zList.nextElement();
                if (ze.isDirectory()) {
                    logger.info("打开zip文件里的文件夹:"+ ze.getName() +"skipped...");
                    continue;
                }
                logger.info("zip包里的文件:"+ ze.getName() +" "+"大小为:" + ze.getSize() +"KB");
                //以ZipEntry为参数得到一个InputStream,并写到OutputStream中
                outputStream = new BufferedOutputStream(
                        new FileOutputStream(getRealFileName(toDisk, ze.getName())));
                inputStream = new BufferedInputStream(zfile.getInputStream(ze));
                int readLen = 0;
                while ((readLen = inputStream.read(buf, 0, 1024)) != -1) {
                    outputStream.write(buf, 0, readLen);
                }
                inputStream.close();
                outputStream.close();
                logger.info("已经解压出:"+ ze.getName());
            }
            zfile.close();
        }catch (Exception e){
            e.printStackTrace();
            logger.info(e.getMessage());
        }finally {
            try {
                if(inputStream != null){
                    inputStream.close();
                }
                if(outputStream != null){
                    outputStream.close();
                }
                if(zfile != null){
                    zfile.close();
                }

            }catch (Exception e){
                e.printStackTrace();
                logger.info(e.getMessage());
            }
        }

    }

    private static File getRealFileName(String zippath, String absFileName){
        String[] dirs = absFileName.split("/", absFileName.length());
        File ret = new File(zippath);// 创建文件对象
        if (dirs.length > 1) {
            for (int i = 0; i < dirs.length - 1; i++) {
                ret = new File(ret, dirs[i]);
            }
        }
        if (!ret.exists()) {// 检测文件是否存在
            ret.mkdirs();// 创建此抽象路径名指定的目录
        }
        ret = new File(ret, dirs[dirs.length - 1]);// 根据 ret 抽象路径名和 child 路径名字符串创建一个新 File 实例
        return ret;
    }


    //根据html生成pdf文件
    public static void htmp2pdf(String creditName, String htmlTemplate,String pdfName,boolean hasBackground,boolean isTrue){
        String path = pdfName.substring(0,pdfName.lastIndexOf(File.separator));
        File dir = new File(path);
        if(!dir.exists()){//判断文件目录是否存在
            dir.mkdirs();
        }
        Document document = null;
        PdfWriter pdfWriter = null;
        FileOutputStream fileOutputStream = null;
        ByteArrayInputStream byteArrayInputStream = null;
        try {
            document = new Document(PageSize.A4);
            fileOutputStream = new FileOutputStream(pdfName);
            pdfWriter = PdfWriter.getInstance(document, fileOutputStream);

            document.open();
            document.addAuthor("Soren");
            document.addCreator("Soren");
            document.addCreationDate();
            document.addTitle("测试生成pdf");
            if(hasBackground){
                Image image = Image.getInstance(imgPrefixUrl+"background.jpg");
                /* 设置图片的位置 */
                image.setAbsolutePosition(0, 80);
                /* 设置图片的大小 */
                image.scaleAbsolute(595, 842);
                document.add(image);
            }

            //此处替换特定字符或者拼接html代码的处理
            htmlTemplate = htmlTemplate.replaceAll("###TITLE###", "长三角报告");
            htmlTemplate = htmlTemplate.replaceAll("###INTRODUCE###", "该报告来源:"+creditName);
            htmlTemplate = htmlTemplate.replaceAll("###date###", "日期:"+ DateUtils.convertYMD(new Date()));
            XMLWorkerHelper helper = XMLWorkerHelper.getInstance();

            //模板不支持svg格式图片
            byteArrayInputStream = new ByteArrayInputStream(htmlTemplate.getBytes("UTF-8"));
            helper.parseXHtml(pdfWriter, document, byteArrayInputStream, Charset.forName("utf8"), new AsianFontProvider());
            logger.info("pdf文件转换完成!");
//            if(isTrue){
//                //先把文件名字更换为临时名字
//                String begin = pdfName.substring(0, pdfName.lastIndexOf("."));
//                String endStr = pdfName.substring(pdfName.lastIndexOf("."));
//                String temName = begin + "temp" + endStr;
//                renameFile(pdfName, temName);
//                //文件加水印,输出原文件名
//                waterMark(temName,
//                        pdfName);
//            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (DocumentException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {

                if(document!=null){
                    document.close();
                }
                if(fileOutputStream!=null){
                    fileOutputStream.close();
                }if(byteArrayInputStream!=null){
                    byteArrayInputStream.close();
                }
                if(pdfWriter!=null){
                    pdfWriter.close();
                }
            }catch (Exception e){
                e.printStackTrace();
                logger.info(e.getMessage());
            }


        }
    }

    /**
     * 删除单个文件
     *
     * @param fileName
     *            要删除的文件的文件名
     * @return 单个文件删除成功返回true,否则返回false
     */
    public static boolean deleteFile(String fileName) {
        File file = new File(fileName);
        // 如果文件路径所对应的文件存在,并且是一个文件,则直接删除
        if (file.exists() && file.isFile()) {
            if (file.delete()) {
                logger.info("删除单个文件" + fileName + "成功!");
                return true;
            } else {
                logger.info("删除单个文件" + fileName + "失败!");
                return false;
            }
        } else {
            logger.info("删除单个文件失败:" + fileName + "不存在!");
            return false;
        }
    }
}

页脚工具类

java 复制代码
package com.ruoyi.business.bankInterface.controller.tax.utils.pdf;

import com.itextpdf.text.Document;
import com.itextpdf.text.Element;
import com.itextpdf.text.Font;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.pdf.*;

/**
 *  @description 针对页码生成的PDF事件监听
 *  @author myw
 *  @date 2023-4-10 20:24:21
 **/
public class PdfNumPageEventTax extends PdfPageEventHelper {

    private int total;

    PdfNumPageEventTax(){

    }

    public PdfNumPageEventTax(int num){
        this.total = num;
    }

    @Override
    public void onEndPage(PdfWriter writer, Document document) {
        try {
            if(writer.getPageNumber() ==1) return;
            // PDF文档内容
            PdfContentByte pdfContent = writer.getDirectContent();
            pdfContent.saveState();
            pdfContent.beginText();
            int footerFontSize = 10;
            // 解决页码中文无法显示 或者 显示为乱码的问题
            // 但是必须引入jar包 itext-asian-5.2.0.jar
            BaseFont baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", false);
            Font fontDetail = new Font(baseFont, footerFontSize, Font.NORMAL);
            pdfContent.setFontAndSize(baseFont, footerFontSize);
            // 页脚的页码 展示
            String footerNum = String.format("第%d页 共"+total+"页", writer.getPageNumber());
            Phrase phrase = new Phrase(footerNum, fontDetail);
            // 页码的 横轴 坐标 居中
            float x = ( document.left() + document.right() ) / 2 +10;
            // 页码的 纵轴 坐标
            float y = document.bottom(-20) ;
            // 添加文本内容,进行展示页码
            ColumnText.showTextAligned(pdfContent, Element.ALIGN_CENTER, phrase, x, y, 0);
            pdfContent.endText();
            pdfContent.restoreState();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onStartPage(PdfWriter writer, Document document) {
//        try {
//            // PDF文档内容
//            PdfContentByte pdfContent = writer.getDirectContent();
//            pdfContent.saveState();
//            pdfContent.beginText();
//            int footerFontSize = 10;
//            // 解决页码中文无法显示 或者 显示为乱码的问题
//            // 但是必须引入jar包 itext-asian-5.2.0.jar
//            BaseFont baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", false);
//            Font fontDetail = new Font(baseFont, footerFontSize, Font.NORMAL);
//            pdfContent.setFontAndSize(baseFont, footerFontSize);
//            // 页脚的页码 展示
//            String footerNum = String.format("第%d页,共"+total+"页", writer.getPageNumber());
//            Phrase phrase = new Phrase(footerNum, fontDetail);
//            // 页码的 横轴 坐标 居中
//            float x = ( document.left() + document.right() ) / 2 +10;
//            // 页码的 纵轴 坐标
//            float y = document.bottom(-20) ;
//            // 添加文本内容,进行展示页码
//            ColumnText.showTextAligned(pdfContent, Element.ALIGN_CENTER, phrase, x, y, 0);
//            pdfContent.endText();
//            pdfContent.restoreState();
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
        super.onStartPage(writer, document);
    }
}

柱图工具类

java 复制代码
package com.ruoyi.business.bankInterface.controller.risk.utils.chart;

import com.alibaba.fastjson2.JSONArray;
import com.ruoyi.business.bankInterface.ConstantConfig;
import com.ruoyi.business.bankInterface.controller.risk.utils.ColorEnum;
import org.apache.commons.lang3.StringUtils;
import org.knowm.xchart.BitmapEncoder;
import org.knowm.xchart.CategoryChart;
import org.knowm.xchart.CategoryChartBuilder;
import org.knowm.xchart.CategorySeries;
import org.knowm.xchart.internal.chartpart.Chart;
import org.knowm.xchart.style.Styler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * 柱状图工具类
 */
public class HistogramChar <C extends Chart<?, ?>> {

  private static final Logger logger = LoggerFactory.getLogger(HistogramChar.class);
  private static String baseUrl = ConstantConfig.IMAGE_TEMP_FOLDER;

  public static void main(String[] args) throws IOException {
    List<String> titleList = JSONArray.parseArray("[\"严重警告\", \"警告\", \"关注\", \"提示\"]", String.class);
    List<Double> yData1 = JSONArray.parseArray("[6.0, 3.0, 1.0, 5.0]", Double.class);
    //柱状图
    String zhuImg = new HistogramChar().getChart2("风险等级分布", titleList, yData1, ColorEnum.lColorList2, "%", 0,
            700, 263, 0.2);

    logger.info("柱状图" + zhuImg);
  }

  public String getChart(String title, List<String> titleList, List<String> xData, List<List<Double>> yDataList, List<Color> colorList, String yUnit, int type,
                                int width, int height, double SpaceFill) {
    File file = new File(baseUrl);
    if (!file.exists()){
      file.mkdirs();
    }
    try {
      String path = baseUrl + titleList.get(0)+ System.currentTimeMillis()+".png";
      CategoryChart chart = new CategoryChartBuilder().width(width).height(height).theme(Styler.ChartTheme.Matlab).build();
      chart = chartTitle(chart, title);
      chart.getStyler().setPlotGridLinesVisible(true);//图表中垂直网格线的可见性
      chart.getStyler().setPlotGridLinesColor(new Color(184, 200,240));//设置图表中垂直网格线颜色
      chart.getStyler().setPlotBorderColor(new Color(236, 238,240));//设置图表中绘图区域的边框的颜色
      chart.getStyler().setLegendPosition(Styler.LegendPosition.OutsideS);//设置图例(Legend)的位置
      chart.getStyler().setLegendLayout(Styler.LegendLayout.Horizontal);//设置图例(Legend)的排列
      chart.getStyler().setXAxisLabelRotation(0);//设置X轴的字旋转角度
      if(xData != null && xData.size() > 6){
        chart.getStyler().setXAxisLabelRotation(40);//设置X轴的字旋转角度
      }
      chart.setYAxisGroupTitle(0, yUnit);//设置Y轴组的标题
      chart.getStyler().setYAxisGroupPosition(0, Styler.YAxisPosition.Left);//设置Y轴组的显示位置
      // 设置字体大小
      chart.getStyler().setLegendFont(new Font("宋体", Font.BOLD, 25));//设置图例的字体样式
      chart.getStyler().setAxisTitleFont(new Font("宋体", Font.BOLD, 25));//设置坐标轴标题的字体样式
      chart.getStyler().setLabelsFont(new Font("宋体", Font.BOLD, 25));//设置图表中标签的字体样式
      chart.getStyler().setLegendBorderColor(Color.white);
      chart.getStyler().setAvailableSpaceFill(SpaceFill);//设置图表可用空间的填充方式
      chart.getStyler().setYAxisDecimalPattern("#");//设置Y轴的小数点格式//避免科学计数法
      chart.getStyler().setChartPadding(10);//设置图表的内边距
      chart.getStyler().setPlotBorderVisible(true);//设置图表中绘图区域的边框是否可见
//      chart.getStyler().setYAxisMin(0.0);
      chart.getStyler().setAxisTickMarksColor(Color.white);//设置图表中刻度标记的颜色
      //柱状图
      if(type == 0 && titleList != null && titleList.size() > 0){
        chart.getStyler().setOverlapped(false);//设置图表中数据系列的重叠方式
        for(int i=0; i < titleList.size(); i++){
          CategorySeries series1 = chart.addSeries(titleList.get(i), xData, yDataList.get(i));
          series1.setChartCategorySeriesRenderStyle(CategorySeries.CategorySeriesRenderStyle.Bar);
          series1.setFillColor(colorList.get(i));
          series1.setYAxisGroup(0);
        }
      }

      /** 折线图 */
      if(type == 1 && titleList != null && titleList.size() > 0){
        chart.getStyler().setOverlapped(true);//设置图表中数据系列的重叠方式
        for(int i=0; i < titleList.size(); i++){
          CategorySeries series2 = chart.addSeries(titleList.get(i), xData, yDataList.get(i));
          series2.setChartCategorySeriesRenderStyle(CategorySeries.CategorySeriesRenderStyle.Line);
          series2.setYAxisGroup(0);
          series2.setLineColor(colorList.get(i));
          series2.setMarkerColor(colorList.get(i));
        }
      }
      BitmapEncoder.saveBitmap(chart, path, BitmapEncoder.BitmapFormat.PNG);
      return path;
    }catch (Exception e){
      e.printStackTrace();
    }
    return null;
  }

  /**
   *
   * @param title
   * @param xDataList       X轴数据列表/线名字列表
   * @param yDataList   Y轴数据列表
   * @param colorList   颜色列表
   * @param yUnit       Y轴单位名字
   * @param type        图形类型,0:柱状图,1:折线图
   * @param width       图片宽度
   * @param height      图片高度
   * @param SpaceFill
   * @return
   */
  public String getChart2(String title, List<String> xDataList, List<Double> yDataList, List<Color> colorList, String yUnit, int type,
                         int width, int height, double SpaceFill) {
    File file = new File(baseUrl);
    if (!file.exists()){
      file.mkdirs();
    }
    try {
      String path = baseUrl + xDataList.get(0)+ System.currentTimeMillis()+".png";
      CategoryChart chart = new CategoryChartBuilder().width(width).height(height).theme(Styler.ChartTheme.Matlab).build();
      chart = chartTitle(chart, title);/** 标题配置 */
      chart = chartLegend(chart);/** 图例配置 */
      chart = chartGridOrBorder(chart);/** 网格或边框配置 */
      chart = chartXY(chart, xDataList.size() > 6 ? true : false, yUnit);/** 坐标轴相关配置 */
      chart.getStyler().setAvailableSpaceFill(SpaceFill);//设置图表可用空间的填充方式
      chart.getStyler().setOverlapped(true);//设置图表中数据系列的重叠方式
      //柱状图
      if(type == 0 && xDataList != null && xDataList.size() > 0){
        for(int i=0; i < xDataList.size(); i++){
          List<Double> yData = new ArrayList<>();
          for(int y=0; y < yDataList.size(); y++){
            if(y==i){
              yData.add(yDataList.get(i));
            }else{
              yData.add(0.0);
            }
          }
          CategorySeries series1 = chart.addSeries(xDataList.get(i), xDataList, yData);
          series1.setChartCategorySeriesRenderStyle(CategorySeries.CategorySeriesRenderStyle.Bar);
          series1.setFillColor(colorList.get(i));
          series1.setYAxisGroup(0);
        }
      }
      BitmapEncoder.saveBitmap(chart, path, BitmapEncoder.BitmapFormat.PNG);
      return path;
    }catch (Exception e){
      e.printStackTrace();
    }
    return null;
  }

  /** 标题配置 */
  private CategoryChart chartTitle(CategoryChart chart, String title){
    if(StringUtils.isNotBlank(title)){
      chart.setTitle(title);
      chart.getStyler().setChartTitleFont(new Font("宋体", Font.BOLD, 25));//设置标题字体
      chart.getStyler().setChartTitleBoxBackgroundColor(new Color(234,242,250));
      chart.getStyler().setChartTitleBoxVisible(true);
      chart.getStyler().setChartTitlePadding(15);
    }
    return chart;
  }

  /** 图例配置 */
  private CategoryChart chartLegend(CategoryChart chart){
    chart.getStyler().setLegendPosition(Styler.LegendPosition.OutsideS);//设置图例(Legend)的位置
    chart.getStyler().setLegendLayout(Styler.LegendLayout.Horizontal);//设置图例(Legend)的排列
    chart.getStyler().setLegendFont(new Font("宋体", Font.PLAIN, 20));//设置图例的字体样式
    chart.getStyler().setLegendBorderColor(Color.white);
    return chart;
  }

  /** 网格或边框配置 */
  private CategoryChart chartGridOrBorder(CategoryChart chart){
    chart.getStyler().setPlotGridLinesVisible(true);//图表中垂直网格线的可见性
    chart.getStyler().setPlotGridLinesColor(new Color(184, 200,240));//设置图表中垂直网格线颜色
    chart.getStyler().setPlotBorderColor(new Color(236, 238,240));//设置图表中绘图区域的边框的颜色
    chart.getStyler().setPlotBorderVisible(true);//设置图表中绘图区域的边框是否可见
    chart.getStyler().setChartPadding(10);//设置图表的内边距
    return chart;
  }

  /** X轴相关配置 */
  private CategoryChart chartXY(CategoryChart chart, Boolean isRotation, String yUnit){
    chart.getStyler().setAxisTickMarksColor(Color.white);//设置图表中刻度标记的颜色
    chart.getStyler().setAxisTitleFont(new Font("宋体", Font.PLAIN, 25));//设置坐标轴标题的字体样式
    chart.getStyler().setAxisTickLabelsFont(new Font("宋体", Font.PLAIN, 20));//设置坐标轴的字体样式
    /** X轴相关配置 */
    chart.getStyler().setXAxisLabelRotation(0);//设置X轴的字旋转角度
    if(isRotation){
      chart.getStyler().setXAxisLabelRotation(40);//设置X轴的字旋转角度
    }
    /** Y轴相关配置 */
    chart.setYAxisGroupTitle(0, yUnit);//设置Y轴组的标题
    chart.getStyler().setYAxisGroupPosition(0, Styler.YAxisPosition.Left);//设置Y轴组的显示位置
    chart.getStyler().setYAxisDecimalPattern("#");//设置Y轴的小数点格式//避免科学计数法
//    chart.getStyler().setYAxisMin(0.6);
    return chart;
  }
}

饼图工具类

java 复制代码
package com.ruoyi.business.bankInterface.controller.risk.utils.chart;

import com.alibaba.fastjson2.JSONArray;
import com.ruoyi.business.bankInterface.ConstantConfig;
import com.ruoyi.business.bankInterface.controller.risk.utils.ColorEnum;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.labels.PieSectionLabelGenerator;
import org.jfree.chart.labels.StandardPieSectionLabelGenerator;
import org.jfree.chart.plot.PiePlot;
import org.jfree.data.general.DefaultPieDataset;
import org.jfree.ui.RectangleEdge;

import java.awt.*;
import java.io.File;
import java.text.DecimalFormat;
import java.util.Arrays;
import java.util.List;

public class Pie2Chart {

    private static String baseUrl = ConstantConfig.IMAGE_TEMP_FOLDER;

    public static void main(String[] args) throws Exception{
        List<String> keyList = Arrays.asList("无任何司法异常", "涉及刑事诉讼且为被告人", "涉重大经济纠纷", "涉及经济纠纷", "涉及劳动纠纷",
                "近一年立案数量大于3", "当前存在执行公开信息", "新增查封信息", "失信被执行");
        List<Double> rDataList = JSONArray.parseArray("[40, 15, 1, 8, 17, 5, 10, 2, 2]", Double.class);
        Boolean isTitleVisible = true;//标题是否显示
        String title = "司法风险分布";
        Boolean isLegendVisible = false;//图例是否显示
        RectangleEdge rectangleEdge = RectangleEdge.BOTTOM;//图例位置
        String path = pieChart(keyList, rDataList, isTitleVisible, title, isLegendVisible, rectangleEdge, 1);
        System.out.println(path);
    }

    public static String pieChart(List<String> keyList, List<Double> rDataList, Boolean isTitleVisible, String title,
                                  Boolean isLegendVisible, RectangleEdge rectangleEdge, int flag){
        String path = baseUrl + System.currentTimeMillis()+".png";
        try {
            // 创建数据集
            DefaultPieDataset dataset = new DefaultPieDataset();
            for(int i=0; i<keyList.size(); i++){
                dataset.setValue(keyList.get(i), rDataList.get(i));
            }
            // 创建饼图
            JFreeChart chart = ChartFactory.createPieChart(
                    title,  // 图表标题
                    dataset,           // 数据集
                    true,             // 是否显示图例
                    false,
                    false
            );
            chart = chartLegend(chart, isLegendVisible, rectangleEdge);
            chart = chartTitle(chart, isTitleVisible);
            chart = chartPiePlot(keyList, chart, flag);
            ChartUtilities.saveChartAsPNG(new File(path), chart, 700, 350);
        }catch (Exception e){
         e.printStackTrace();
        }
        return path;
    }

    private static JFreeChart chartLegend(JFreeChart chart, Boolean isLegendVisible, RectangleEdge rectangleEdge){
        if(isLegendVisible){
            /** 图例显示 */
            Font font = new Font("宋体", Font.PLAIN, 12);
            chart.getLegend().setItemFont(font);// 设置图例类别字体
            chart.getLegend().setBorder(0, 0, 0, 0);//设置图例边框
            chart.getLegend().setMargin(10, 30, 10, 0);//设置图例边框内边框
            chart.getLegend().setPosition(rectangleEdge);//配置图例位置

        }else{
            /** 图例不显示 */
            chart.getLegend().setVisible(false);
        }
        return chart;
    }

    /** 标题配置 */
    private static JFreeChart chartTitle(JFreeChart chart, Boolean isTitleVisible){
        if(isTitleVisible){
            /** 标题显示 */
            //如果不使用Font,中文将显示不出来
            Font titleFont = new Font("宋体", Font.BOLD, 25);
            chart.getTitle().setFont(titleFont); // 设置标题字体
            chart.getTitle().setMargin(10, 30, 10, 0);
            chart.getTitle().setBackgroundPaint(Color.WHITE);
        }
        return chart;
    }

    /** PiePlot配置 */
    private static JFreeChart chartPiePlot(List<String> keyList, JFreeChart chart, int flag){
        PiePlot piePlot = (PiePlot)chart.getPlot();
        for(int i=0; i<keyList.size(); i++){
            piePlot.setSectionPaint(keyList.get(i), ColorEnum.zhColorList.get(i));
        }
        piePlot.setBackgroundPaint(Color.WHITE);// 例如,设置为白色背景
        piePlot.setShadowPaint(Color.WHITE);//饼图的阴影颜色
        piePlot.setOutlinePaint(Color.WHITE);//数据区的边界线条颜色
        if(flag == 0){
            /** 展示key+百分比 */
            PieSectionLabelGenerator labelGenerator = new StandardPieSectionLabelGenerator(
                    "{0}\n{2}", // 标签格式,其中 {0} 是扇区键,{1} 是扇区值,{2} 是百分比
                    new DecimalFormat("0"), // 用于格式化数值的 DecimalFormat 对象
                    new DecimalFormat("0%") // 用于格式化百分比的 DecimalFormat 对象
            );
            piePlot.setLabelGenerator(labelGenerator);
        }else if(flag == 1){
            /** 展示百分比 */
            PieSectionLabelGenerator labelGenerator = new StandardPieSectionLabelGenerator(
                    "{2}", // 标签格式,其中 {0} 是扇区键,{1} 是扇区值,{2} 是百分比
                    new DecimalFormat("0"), // 用于格式化数值的 DecimalFormat 对象
                    new DecimalFormat("0%") // 用于格式化百分比的 DecimalFormat 对象
            );
            piePlot.setLabelGenerator(labelGenerator);
        }else if(flag == 2){
            /** 展示百分比 */
            PieSectionLabelGenerator labelGenerator = new StandardPieSectionLabelGenerator(
                    "{0}\n企业占比{1}%", // 标签格式,其中 {0} 是扇区键,{1} 是扇区值,{2} 是百分比
                    new DecimalFormat("0"), // 用于格式化数值的 DecimalFormat 对象
                    new DecimalFormat("0%")// 用于格式化数值的 DecimalFormat 对象
            );
            piePlot.setLabelGenerator(labelGenerator);
        }else{
            /** 不展示内容 */
            piePlot.setLabelGenerator(null);
        }
        /** 配置标签 */
        Font font = new Font("宋体", Font.PLAIN, 12);
        piePlot.setLabelFont(font);/** 分类标签的字体 */
        piePlot.setIgnoreNullValues(true);//忽略空值
        piePlot.setLegendItemShape(new Rectangle(10, 10));
        piePlot.setLabelOutlinePaint(Color.WHITE);/** 分类标签的边框颜色 */
        piePlot.setLabelShadowPaint(Color.WHITE);/** 分类标签的阴影颜色 */
        piePlot.setLabelBackgroundPaint(Color.WHITE);/** 分类标签的背景颜色 */
        piePlot.setLabelLinkStroke(new BasicStroke(0.5F)); //
        piePlot.setLabelLinkPaint(Color.lightGray);
        piePlot.setLabelGap(0.01);// 调整标签与饼图边缘的间隙,以便更好地对齐
        return chart;
    }
}


package com.ruoyi.business.bankInterface.controller.risk.utils.chart;

import com.alibaba.fastjson2.JSONArray;
import com.ruoyi.business.bankInterface.ConstantConfig;
import com.ruoyi.business.bankInterface.controller.risk.utils.ColorEnum;
import org.apache.commons.lang3.StringUtils;
import org.knowm.xchart.BitmapEncoder;
import org.knowm.xchart.PieChart;
import org.knowm.xchart.PieChartBuilder;
import org.knowm.xchart.PieSeries;
import org.knowm.xchart.internal.chartpart.Chart;
import org.knowm.xchart.style.PieStyler;
import org.knowm.xchart.style.Styler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;

public class PieChar <C extends Chart<?, ?>> {

  private static final Logger logger = LoggerFactory.getLogger(PieChar.class);

  protected static String baseUrl = ConstantConfig.IMAGE_TEMP_FOLDER;

  public static void main(String[] args) throws IOException {
    List<String> titleList = Arrays.asList("无任何司法异常", "涉及刑事诉讼且为被告人", "涉重大经济纠纷", "涉及经济纠纷", "涉及劳动纠纷",
            "近一年立案数量大于3", "当前存在执行公开信息", "新增查封信息", "失信被执行");
    List<Double> rDataList = JSONArray.parseArray("[40, 15, 1, 8, 17, 5, 10, 2, 2]", Double.class);
    String hImg = new PieChar().getChart("司法风险分布",titleList, rDataList, ColorEnum.zhColorList, false, Styler.LegendPosition.OutsideE, Styler.LegendLayout.Vertical);
    logger.info("环形图" + hImg);
  }

  /**
   * 饼状图/环图
   * @param title
   * @param titleList 模块名
   * @param rData 数据量
   * @param colorList 模块的颜色集合
   * @param legendVisible 图例是否可见,true:可见,false:不可见
   * @param legendPosition 设置图例(Legend)的位置  OutsideE:左侧 OutsideS:
   * @param legendLayout 设置图例(Legend)的排列 Vertical:竖着排列 Horizontal:横着排列
   * @return
   */
  public String getChart(String title, List<String> titleList, List<Double> rData, List<Color> colorList,
                         Boolean legendVisible, Styler.LegendPosition legendPosition, Styler.LegendLayout legendLayout){
    File file = new File(baseUrl);
    if (!file.exists()){
      file.mkdirs();
    }
    try {
      String path = baseUrl + titleList.get(0)+ System.currentTimeMillis()+".png";
      PieChart chart = new PieChartBuilder().width(1200).height(450).theme(Styler.ChartTheme.Matlab).build();
      chart = chartTitle(chart, title);
      /** 配置图例:是否可见、位置、排列*/
      chart = legendVisible(chart, legendVisible, legendPosition, legendLayout);
      chart = chartLabels(chart, true);
      chart.getStyler().setSliceBorderWidth(0.3);//设置饼图中每个扇区(Slice)的边框宽度
      chart.getStyler().setSliceBorderWidth(2);//环形图各个块的间距
      chart.getStyler().setDefaultSeriesRenderStyle(PieSeries.PieSeriesRenderStyle.Pie);//设置是环还是扇形
      chart.getStyler().setLabelType(PieStyler.LabelType.Percentage);//展示哪些内容
      chart.getStyler().setPlotContentSize(0.8);//设置饼图绘图内容的大小
      chart.getStyler().setSumVisible(false);
      chart.getStyler().setPlotBorderVisible(false);//设置饼图绘图边框的可见性
      for(int i=0; i < titleList.size(); i++){
        PieSeries series =chart.addSeries(titleList.get(i), rData.get(i));
        series.setFillColor(colorList.get(i));
//        series.setShowInLegend(true);
      }
      BitmapEncoder.saveBitmap(chart, path, BitmapEncoder.BitmapFormat.PNG);
      return path;
    }catch (Exception e){
      e.printStackTrace();
    }
    return null;
  }


  private PieChart legendVisible(PieChart chart, Boolean legendVisible, Styler.LegendPosition legendPosition, Styler.LegendLayout legendLayout){
//      chart.getStyler().setLegendPadding(100);//设置图例(Legend)的内边距
//      chart.getStyler().setLegendSeriesLineLength(200);//设置图例系列线条的长度
    chart.getStyler().setLegendBorderColor(Color.white);//设置图例边框颜色:白色
    chart.getStyler().setLegendVisible(false);//默认图例不可见
    if(legendVisible){
      chart.getStyler().setLegendVisible(true);//图例可见
      chart.getStyler().setLegendPosition(legendPosition);//设置图例(Legend)的位置
      chart.getStyler().setLegendLayout(legendLayout);//设置图例(Legend)的排列
      chart.getStyler().setLegendFont(new Font("宋体", Font.PLAIN, 12));//设置图例的字体样式
    }
    return chart;
  }

  private PieChart chartTitle(PieChart chart, String title){
    if(StringUtils.isNotBlank(title)){
      chart.setTitle(title);
      chart.getStyler().setChartTitleFont(new Font("宋体", Font.BOLD, 25));//设置标题字体
      chart.getStyler().setChartTitleBoxBackgroundColor(new Color(234,242,250));
      chart.getStyler().setChartTitleBoxVisible(true);
      chart.getStyler().setChartTitlePadding(15);
    }
    return chart;
  }

  private PieChart chartLabels(PieChart chart, Boolean labelsVisible){
    chart.getStyler().setLabelsDistance(0.8);
    chart.getStyler().setLabelsVisible(false);//设置饼图中每个扇区(Slice)的标签是否可见
    if(labelsVisible){
      chart.getStyler().setLabelsFont(new Font("宋体", Font.CENTER_BASELINE, 12));
      chart.getStyler().setLabelsFontColor(Color.black);
      chart.getStyler().setLabelsVisible(true);//设置饼图中每个扇区(Slice)的标签是否可见
      chart.getStyler().setLabelsFontColorAutomaticEnabled(true);//设置成false的时候,有个白色的图列字变成了指定的颜色
      chart.getStyler().setLabelsFontColorAutomaticLight(Color.black);
      chart.getStyler().setLabelsFontColorAutomaticDark(Color.orange);
      chart.getStyler().setForceAllLabelsVisible(true);//控制饼图中所有扇区的标签是否必须可见
    }
    return chart;
  }
}
相关推荐
KiddoStone9 分钟前
多实例schedule job同步数据流的数据一致性设计和实现方案
java
岁忧30 分钟前
(LeetCode 每日一题) 1865. 找出和为指定值的下标对 (哈希表)
java·c++·算法·leetcode·go·散列表
YuTaoShao34 分钟前
【LeetCode 热题 100】240. 搜索二维矩阵 II——排除法
java·算法·leetcode
考虑考虑1 小时前
JDK9中的dropWhile
java·后端·java ee
想躺平的咸鱼干2 小时前
Volatile解决指令重排和单例模式
java·开发语言·单例模式·线程·并发编程
hqxstudying2 小时前
java依赖注入方法
java·spring·log4j·ioc·依赖
·云扬·2 小时前
【Java源码阅读系列37】深度解读Java BufferedReader 源码
java·开发语言
Bug退退退1233 小时前
RabbitMQ 高级特性之重试机制
java·分布式·spring·rabbitmq
小皮侠3 小时前
nginx的使用
java·运维·服务器·前端·git·nginx·github
Zz_waiting.3 小时前
Javaweb - 10.4 ServletConfig 和 ServletContext
java·开发语言·前端·servlet·servletconfig·servletcontext·域对象