java模板导出PDF(echarts、图片,表格)

首先工具准备phantomjs下载地址:https://phantomjs.org/download.html

echarts-convert下载地址:https://gitee.com/saintlee/echartsconvert
pdf编辑器Adobe Acrobat DC

工具我已经打包好了链接:https://pan.baidu.com/s/1Om5Ap56uJNgsN8VatZCoGA?pwd=gdzx 
提取码:gdzx

1.echarts-convert代码改写

 将echarts-convert.js中图片位置,中文解码改为一层

2.如果是Linux系统将echarts-convert.js第53行注释掉

 3.Linux中运行下边的代码,安装字体库

yum install bitmap-fonts bitmap-fonts-cjk

4.建立pdf模板

使用Adobe Acrobat DC编辑模板

使用表单工具建立模板填充,设置相关属性 ,文字,图片,表格设置方式相同。

二。代码准备

运行phantomjs

phantomjs 全路径+echarts-convert.js -s -p 6666

将编辑好的模板放到该目录下

 pom.xml

        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itextpdf</artifactId>
            <version>5.5.9</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itext-asian</artifactId>
            <version>5.2.0</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/cn.hutool/hutool-all -->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.20</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>
        <!--用于jfreechart生成图片  -->
        <dependency>
            <groupId>org.jfree</groupId>
            <artifactId>jfreechart</artifactId>
            <version>1.5.0</version>
        </dependency>
<!--        phantomjs服务端模式-->
        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
            <version>2.3.28</version>
        </dependency>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.7</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.56</version>
        </dependency>
        <dependency>
            <groupId>org.icepear.echarts</groupId>
            <artifactId>echarts-java</artifactId>
            <version>1.0.7</version>
        </dependency>
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

public class HttpUtil {

    public static String post(String url, Map<String, String> params, String charset)
            throws ClientProtocolException, IOException {
        String responseEntity = "";

        // 创建CloseableHttpClient对象
        CloseableHttpClient client = HttpClients.createDefault();

        // 创建post方式请求对象
        HttpPost httpPost = new HttpPost(url);

        // 生成请求参数
        List<NameValuePair> nameValuePairs = new ArrayList<>();
        if (params != null) {
            for (Entry<String, String> entry : params.entrySet()) {
                nameValuePairs.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
            }
        }

        // 将参数添加到post请求中
        httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs, charset));

        // 发送请求,获取结果(同步阻塞)
        CloseableHttpResponse response = client.execute(httpPost);

        // 获取响应实体
        HttpEntity entity = response.getEntity();
        if (entity != null) {
            // 按指定编码转换结果实体为String类型
            responseEntity = EntityUtils.toString(entity, charset);
        }

        // 释放资源
        EntityUtils.consume(entity);
        response.close();

        return responseEntity;
    }
}
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import org.apache.http.client.ClientProtocolException;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

public class EchartsUtil {
    //phantomjs的ip和端口
    private static String url = "http://localhost:6666";
    private static final String SUCCESS_CODE = "1";

    public static String generateEchartsBase64(String option) throws ClientProtocolException, IOException {
        String base64 = "";
        if (option == null) {
            return base64;
        }
        option = option.replaceAll("\\s+", "").replaceAll("\"", "'");

        // 将option字符串作为参数发送给echartsConvert服务器
        Map<String, String> params = new HashMap<>();
        params.put("opt", option);
        String response = HttpUtil.post(url, params, "utf-8");

        // 解析echartsConvert响应
        JSONObject responseJson = JSON.parseObject(response);
        String code = responseJson.getString("code");

        // 如果echartsConvert正常返回
        if (SUCCESS_CODE.equals(code)) {
            base64 = responseJson.getString("data");
        }
        // 未正常返回
        else {
            String string = responseJson.getString("msg");
            throw new RuntimeException(string);
        }

        return base64;
    }
}
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.*;
import lombok.experimental.UtilityClass;
import org.icepear.echarts.Bar;
import org.icepear.echarts.Line;
import org.icepear.echarts.Option;
import org.icepear.echarts.Pie;
import org.icepear.echarts.charts.line.LineSeries;
import org.icepear.echarts.charts.pie.PieSeries;
import org.icepear.echarts.components.coord.cartesian.CategoryAxis;
import org.icepear.echarts.components.coord.cartesian.ValueAxis;
import org.icepear.echarts.components.legend.Legend;
import org.icepear.echarts.components.title.Title;
import org.icepear.echarts.components.tooltip.Tooltip;
import org.icepear.echarts.origin.util.SeriesOption;
import org.icepear.echarts.render.ChartMeta;
import org.icepear.echarts.render.Engine;
import org.springframework.core.io.ClassPathResource;
import sun.misc.BASE64Decoder;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.*;
import java.util.List;

@UtilityClass
public class CreatePdfUtil {
    //pdf模板页数
    public static final Integer PDF_NUM = 13;


    public static void createPdf(HttpServletResponse response,Map<String,Object> map) throws Exception {
        //设置请求返回类型
        response.setHeader("Content-Disposition", "attachment; filename=xxxx.pdf");
        OutputStream outputStream = response.getOutputStream();
        //模板路径,放到项目里用这个ClassPathResource
        ClassPathResource TemplatePDF = new ClassPathResource("templates/temp.pdf");
        //模板字体
        BaseFont bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
        //用于存储每页生成pdf流
        ByteArrayOutputStream bos[] = new ByteArrayOutputStream[PDF_NUM];



        for (Integer i = 0; i < PDF_NUM ; i++) {
            HashMap<String, Object> textMap = (HashMap<String, Object>) map.get("text");
            bos[i] = new ByteArrayOutputStream();
            InputStream inputStream = TemplatePDF.getInputStream();
            PdfReader reader = new PdfReader(inputStream);
            PdfStamper stamp = new PdfStamper(reader, bos[i]);
            AcroFields form = stamp.getAcroFields();
            form.addSubstitutionFont(bf);

            for (Map.Entry<String, Object> text : textMap.entrySet()) {
                form.setField(text.getKey(), text.getValue().toString());
            }
            //添加统计图
            HashMap<String, Object> imageMap = (HashMap<String, Object>) map.get("image");
            for (Map.Entry<String, Object> image : imageMap.entrySet()) {
                try {
                    //玫瑰🌹图
                    byte[] pie = generateImages(image.getValue().toString());
                    Image ajgImage = Image.getInstance(pie);
                    List<AcroFields.FieldPosition> list = form.getFieldPositions(image.getKey());
                    if (list != null && list.size() > 0){
                        int page = list.get(0).page;
                        Rectangle ajg = list.get(0).position;
                        //添加图片
                        PdfContentByte cb = stamp.getOverContent(page);
                        // 根据域大小设置缩放图片
                        ajgImage.scaleToFit(ajg.getWidth(), 600);
                        // 设置居中
                        ajgImage.setAlignment(Image.MIDDLE);
                        // 绝对定位
                        ajgImage.setAbsolutePosition(ajg.getLeft(), ajg.getBottom());
                        cb.addImage(ajgImage);
                    }

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }



            //表格 一行数据是一个list
            Map<String,List<List<String>>> tableMap = (Map<String, List<List<String>>>) map.get("table");

            // 表格类
            for (String key : tableMap.keySet()) {
                List<List<String>> lists = tableMap.get(key);
                int pageNo = form.getFieldPositions(key).get(0).page;
                PdfContentByte pcb = stamp.getOverContent(pageNo);
                Rectangle signRect = form.getFieldPositions(key).get(0).position;
                //表格位置
                int column = lists.get(0).size();
                int row = lists.size();
                PdfPTable table = new PdfPTable(column);
                float tatalWidth = signRect.getRight() - signRect.getLeft() - 1;
                int size = lists.get(0).size();
                float width[] = new float[size];
                for (int a = 0; a < size; a++) {
                    if (a == 0) {
                        width[a] = 60f;
                    } else {
                        width[a] = (tatalWidth - 60) / (size - 1);
                    }
                }
                table.setTotalWidth(width);
                table.setLockedWidth(true);
                table.setKeepTogether(true);
                table.setSplitLate(false);
                table.setSplitRows(true);
                Font FontProve = new Font(bf, 10, 0);
                //表格数据填写
                for (int a = 0; a < row; a++) {
                    List<String> l = lists.get(a);
                    for (int j = 0; j < l.size(); j++) {
                        Paragraph paragraph = new Paragraph(String.valueOf(l.get(j)), FontProve);
                        PdfPCell cell = new PdfPCell(paragraph);
                        cell.setBorderWidth(1);
                        cell.setVerticalAlignment(Element.ALIGN_CENTER);
                        cell.setHorizontalAlignment(Element.ALIGN_CENTER);
                        cell.setLeading(0, (float) 1.4);
                        table.addCell(cell);
                    }
                }
                table.writeSelectedRows(0, -1, signRect.getLeft(), signRect.getTop(), pcb);
            }
            // 如果为false,生成的PDF文件可以编辑,如果为true,生成的PDF文件不可以编辑
            stamp.setFormFlattening(true);
            stamp.close();
            Document doc = new Document();
            PdfCopy copy = new PdfCopy(doc, bos[i]);
            doc.open();
            int pageNum = reader.getNumberOfPages();
            for (int j = 1; j <= pageNum; j++) {
                PdfImportedPage importPage = copy.getImportedPage(new PdfReader(bos[i].toByteArray()), j);
                copy.addPage(importPage);
            }
            doc.close();



            stamp.setFormFlattening(true);
            stamp.close();
        }

        //创建并打开一个pdf对象
        Document doc = new Document();
        PdfCopy pdfCopy = new PdfCopy(doc, outputStream);
        doc.open();

        for (int i = 0; i < PDF_NUM ; i++) {
            PdfImportedPage page = pdfCopy.getImportedPage(new PdfReader(bos[i].toByteArray()), i + 1);
            pdfCopy.addPage(page);
        }
        //关闭
        doc.close();
    }

    public static byte[] generateImages(String option) throws Exception {
        BASE64Decoder decoder = new BASE64Decoder();
        // 根据option参数
        // 生成option字符串
        String base64 = EchartsUtil.generateEchartsBase64(option);
        // 解密
        byte[] b = decoder.decodeBuffer(base64);
        for (int i = 0; i < b.length; ++i) {
            if (b[i] < 0) {
                b[i] += 256;
            }
        }
        return b;
    }
    public static void generateImage(String base64, String path) throws IOException {
        BASE64Decoder decoder = new BASE64Decoder();
        try (OutputStream out = new FileOutputStream(path)){
            // 解密
            byte[] b = decoder.decodeBuffer(base64);
            for (int i = 0; i < b.length; ++i) {
                if (b[i] < 0) {
                    b[i] += 256;
                }
            }
            out.write(b);
            out.flush();
        }
    }

    /**
     * 设置图片
     * @param stamp
     * @param from
     * @param name
     * @param url
     * @throws Exception
     */
    public void setImg(PdfStamper stamp, AcroFields from, String name,String url) throws Exception {
        //添加图片
        PdfContentByte cb = stamp.getOverContent(1);
        //添加logo
        Rectangle logo = from.getFieldPositions(name).get(0).position;
        Image logoImage = Image.getInstance(url);
        //根据域的大小缩放图片,我这里宽度在原有的域基础上加了100,你们可以自己调节
        logoImage.scaleToFit(logo.getWidth() + 100, logo.getHeight());
        logoImage.setAlignment(Image.MIDDLE);
        logoImage.setAbsolutePosition(logo.getLeft(), logo.getBottom());
        cb.addImage(logoImage);
    }


    /**
     * 柱状图
     * 使用 {@link Bar} 构建
     */
    public static String getBar() {

// All methods in ECharts Java supports method chaining
        Bar bar = new Bar()
                .setLegend()
                .setTooltip("item")
                .addXAxis(new String[]{"Matcha Latte", "Milk Tea", "Cheese Cocoa", "Walnut Brownie"})
                .addYAxis()
                .addSeries("2020", new Number[]{43.3, 83.1, 86.4, 72.4})
                .addSeries("2021", new Number[]{85.8, 73.4, 65.2, 53.9})
                .addSeries("2022", new Number[]{93.7, 55.1, 82.5, 39.1});
        Engine engine = new Engine();
// The render method will generate our EChart into a HTML file saved locally in the current directory.
// The name of the HTML can also be set by the first parameter of the function.
        return engine.renderJsonOption(bar);

    }

    /**
     * 折线图
     * ECharts中,一切图表皆Option,使用 {@link Line} 构建
     */
    public static String getLine1() {

// All methods in ECharts Java supports method chaining
        Line line = new Line()
                .setLegend()
                .setTooltip("item")
                .addXAxis(new String[]{"Matcha Latte", "Milk Tea", "Cheese Cocoa", "Walnut Brownie"})
                .addYAxis()
                .addSeries("2020", new Number[]{43.3, 83.1, 86.4, 72.4})
                .addSeries("2021", new Number[]{85.8, 73.4, 65.2, 53.9})
                .addSeries("2022", new Number[]{93.7, 55.1, 82.5, 39.1});
        Engine engine = new Engine();
// The render method will generate our EChart into a HTML file saved locally in the current directory.
// The name of the HTML can also be set by the first parameter of the function.

// json 格式数据
        return engine.renderJsonOption(line);

    }


    /**
     * 折线图
     * ECharts中,一切图表皆Option,使用 {@link Option} 构建
     */
    public static String getLine2() {

        Option option = new Option();
        option.setLegend(new Legend().setData(new String[]{"2020", "2021", "2022"}));
        option.setTooltip(new Tooltip().setTrigger("item"));
        option.setXAxis(new CategoryAxis().setData(new String[]{"Matcha Latte", "Milk Tea", "Cheese Cocoa", "Walnut " +
                "Brownie"}));
        option.setYAxis(new ValueAxis().setType("value"));
        LineSeries lineSeries1 = new LineSeries().setName("2020").setData(new Number[]{43.3, 83.1, 86.4, 72.4});
        LineSeries lineSeries2 = new LineSeries().setName("2021").setData(new Number[]{85.8, 73.4, 65.2, 53.9});
        LineSeries lineSeries3 = new LineSeries().setName("2022").setData(new Number[]{93.7, 55.1, 82.5, 39.1});
        option.setSeries(new SeriesOption[]{lineSeries1, lineSeries2, lineSeries3});
        Engine engine = new Engine();
        return engine.renderJsonOption(option);

    }

    /**
     * 饼图
     * 使用 {@link Pie} 构建
     * ref <a href="https://echarts.apache.org/examples/zh/editor.html?c=pie-simple">...</a>
     */
    public static String getPie() {

        List<PieData> list = new ArrayList<>();

        list.add(new PieData("直接访问", 335));
        list.add(new PieData("邮件营销", 310));
        list.add(new PieData("联盟广告", 234));
        list.add(new PieData("视频广告", 135));
        list.add(new PieData("搜索引擎", 1548));

        PieSeries pieSeries = new PieSeries()
                .setName("访问来源")
                .setType("pie")
                .setRadius("55%")
                .setData(list);

        Pie pie = new Pie()
                .setTitle(new Title().setText("Referer of a Website").setSubtext("Fake Data").setLeft("center"))
                .setLegend(new Legend().setOrient("vertical").setLeft("left"))
                .setTooltip("item")
                .addSeries(pieSeries);
        Engine engine = new Engine();
// The render method will generate our EChart into a HTML file saved locally in the current directory.
// The name of the HTML can also be set by the first parameter of the function.

// json 格式数据
        return engine.renderJsonOption(pie);

    }

    /**
     * 玫瑰图
     * 使用 {@link Pie} 构建
     * ref <a href="https://echarts.apache.org/examples/zh/editor.html?c=pie-simple">...</a>
     */
    public static String getPe() {

        List<PieData> list = new ArrayList<>();

        list.add(new PieData("直接访问", 335));
        list.add(new PieData("邮件营销", 310));
        list.add(new PieData("联盟广告", 234));
        list.add(new PieData("视频广告", 135));
        list.add(new PieData("搜索引擎", 1548));
        Number[] ints = new Number[2];
        ints[0] = 50;
        ints[1] = 250;
        String[] str = new String[2];
        str[0] = "50%";
        str[1] = "50%";

        PieSeries pieSeries = new PieSeries()
                .setName("Nightingale Chart")
                .setType("pie")
                .setRadius(ints)
                .setCenter(str)
                .setRoseType("area")
                .setData(list);

        Pie pie = new Pie()
                .setTitle(new Title().setText("Referer of a Website").setSubtext("Fake Data").setLeft("center"))
                .setLegend(new Legend().setOrient("vertical").setLeft("left"))
                .setTooltip("item")
                .addSeries(pieSeries);
        Engine engine = new Engine();
        ChartMeta chartMeta = new ChartMeta("200", "200", engine.renderJsonOption(pie));
// The render method will generate our EChart into a HTML file saved locally in the current directory.
// The name of the HTML can also be set by the first parameter of the function.
//        engine.render("demo-pie.html", pie);
// json 格式数据
        return engine.renderJsonOption(pie);

    }


    /**
     * 饼图数据
     */
    static class PieData {
        private String name;
        private Integer value;

        public PieData(String name, Integer value) {
            this.name = name;
            this.value = value;
        }

    }

}
import com.pdf.pdfexport.util.CreatePdfUtil;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController()
@RequestMapping("/export")
public class controller {

    @GetMapping()
    public void export(HttpServletResponse httpServletRequest){
        HashMap<String, Object> textMap = new HashMap<>();
        textMap.put("deptName","测试部门名称");
        textMap.put("time","2023-06");
        textMap.put("createTime","2023-08-26");


        HashMap<String, Object> imageMap = new HashMap<>();
        imageMap.put("pie",CreatePdfUtil.getPie());

        List<String> list = new ArrayList<>();
        list.add("标题");
        list.add("日期");
        list.add("金额");
        list.add("备注");

        List<String> list2 = new ArrayList<>();
        list2.add("标题");
        list2.add("2021-08-27");
        list2.add("100000");
        list2.add("");

        List<String> list3 = new ArrayList<>();
        list3.add("标题22");
        list3.add("2021-08-29");
        list3.add("200000");
        list3.add("备注");

        List<List<String>> List = new ArrayList<>();
        List.add(list);
        List.add(list2);
        List.add(list3);
        Map<String, List<List<String>>> listMap = new HashMap<>();
        // 这里的listMap中key要和模板中的域名对应
        listMap.put("table", List);


        Map<String, Object> map = new HashMap<>();
        map.put("table", listMap);
        map.put("text", textMap);
        map.put("image", imageMap);



        try {
            CreatePdfUtil.createPdf(httpServletRequest,map);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

三。运行项目

访问

http://localhost:8080/export

 观察导出的模板

 

相当完美!!教程结束!!完结撒花🌹🌹🌹🌹🌹

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据提供的引用内容,可以使用Java实现根据模板生成导出PDF的功能。具体步骤如下: 1.使用JavaPDF库,例如iText或Apache PDFBox,读取PDF模板文件。 2.使用模板文件的参数,填充PDF表单字段或者在PDF页面上添加文本、图片等内容。 3.将填充后的PDF文件导出到指定的路径。 下面是一个使用iText库实现根据模板导出PDF的示例代码: ```java import com.itextpdf.text.Document; import com.itextpdf.text.pdf.PdfCopy; import com.itextpdf.text.pdf.PdfImportedPage; import com.itextpdf.text.pdf.PdfReader; import com.itextpdf.text.pdf.PdfStamper; import java.io.FileOutputStream; import java.util.Map; public class PdfGenerator { public static void generatePdf(String templatePath, String outputPath, Map<String, String> params) throws Exception { // 读取PDF模板文件 PdfReader reader = new PdfReader(templatePath); // 创建输出流 FileOutputStream fos = new FileOutputStream(outputPath); // 创建PDF文档对象 Document document = new Document(); // 创建PDF写入器 PdfCopy copy = new PdfCopy(document, fos); // 打开文档 document.open(); // 填充PDF表单字段 PdfStamper stamper = new PdfStamper(reader, fos); for (Map.Entry<String, String> entry : params.entrySet()) { stamper.getAcroFields().setField(entry.getKey(), entry.getValue()); } stamper.setFormFlattening(true); stamper.close(); // 将填充后的PDF文件导出到指定的路径 for (int i = 1; i <= reader.getNumberOfPages(); i++) { PdfImportedPage page = copy.getImportedPage(new PdfReader(reader), i); copy.addPage(page); } document.close(); reader.close(); fos.close(); } } ``` 其,`templatePath`为PDF模板文件的路径,`outputPath`为导出PDF文件的路径,`params`为填充PDF表单字段的参数。可以根据实际需求修改代码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值