POI实现导出word文件【内容包括文本,表格,图片】

使用POI生成word文档

业务要求: 网站页面内容导出为相关分析报告,内容包括文本描述,分析表格【行,列内容不固定】,echars图表等

  • 引入poi相关依赖
   
    <dependency>
         <groupId>org.apache.poigroupId>
         <artifactId>poi-ooxmlartifactId>
         <version>3.17version>
   dependency>
    <dependency>
         <groupId>org.apache.poigroupId>
         <artifactId>poi-scratchpadartifactId>
         <version>3.17version>
   dependency>
    <dependency>
         <groupId>org.apache.poigroupId>
         <artifactId>poi-ooxml-schemasartifactId>
         <version>3.17version>
   dependency>
  • 代码中所涉及数据集合结构
		List<String> listColumns = new ArrayList<>();
		List<List<String>> listLineData = new ArrayList<>();
		//map中 img为base64格式字符串 item作为图片字描述的key
		List<Map<String,String>> listPicContent = new ArrayList<>() 
		//图片处理
		//处理页面所需图片存至服务器
        for (int s = 0; s < listPicContent .size(); s++) {
        	//base64字符串格式过长,后台采用StringBuffer接收
            StringBuffer img = 
            	new StringBuffer(listPicContent .get(s).get("img"));
            Base64ToPicUtils.convertBase64ToImage(img,s + "");
        }
  • 导出文本内容渲染【内容导出顺序:表格 、文字描述对应echars图片】
		//创建word文档对象
	    XWPFDocument document = new XWPFDocument();
	    //创建文本标题
	    XWPFParagraph title = document.createParagraph();
	    //设置段落居中
	    title.setAlignment(ParagraphAlignment.CENTER);
	    XWPFRun titleRun = title.createRun();
	    titleRun.setFontSize(20);
	    titleRun.setFontFamily("宋体");
	    titleRun.setBold(true);
	    titleRun.setText("word文档标题");
	    titleRun.addBreak(); //换行
	    //添加内容段落  首先展示分析表格
	    XWPFParagraph paragraph = document.createParagraph();
	    paragraph.setAlignment(ParagraphAlignment.valueOf(STJc.INT_LEFT));
	    XWPFRun firstRun = paragraph.createRun();
	    firstRun .setFontSize(17);
	    firstRun .setFontFamily("黑体");
	    firstRun .addTab();
	    firstRun .setText("表格标题描述***分析报表");
	    //创建表格的第一步
	    //创建列数,listColumns表示表格列头数据封装集合
	    XWPFTable table = document.createTable(1,listColumns.size());
	    //设置表格居中展示
	    CTJc jc = table.getCTTbl().getTblPr().getJc();
	      if(jc == null){
	          jc = table.getCTTbl().getTblPr().addNewJc();
	      }
	    jc.setVal(STJc.CENTER);
		 //设置列头信息
	    table.getRow(0).setHeight(500);	
	    for (int i=0; i<listColumns.size(); i++){
		  setCellText(table.getRow(0).getCell(i),listColumns.get(i),null,1000); 
		}
		//表格内容: 行首及内容信息
        Integer j = 0;
        for (int index = 0; index < listLineData.size(); index++) {   //listLineData 表示行数据集合
            //这个是在表格的添加,添加到第几行
            List<String> item = listLineData.get(index);
            XWPFTableRow row = table.insertNewTableRow(j+1);
            //设置单元格高
            row.setHeight(1000);
            for (int i = 0; i < listColumns.size(); i++ ) {
                XWPFTableCell cell = row.createCell();
                CTTc ctTc = cell.getCTTc();
                CTTcPr ctTcPr = ctTc.addNewTcPr();
                ctTcPr.addNewTcW().setW(BigInteger.valueOf(1000));
                cell.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.RESTART);
                if(StringUtils.isNotBlank(item.get(i))){
                    cell.setText(item.get(i)); //单元格文本填充
                }else{
                    cell.setText(null);
                }
            }
        }
		/**
         *  接上文代码, 图片文字组合部分导出
         *  页面图表转化为base64格式后传至后端,
         *  未找到poi直接解析base64格式的方法,
         *  现将base64格式解析为图片存至服务器,
         *  poi引入对应图片
         */
        for(int x = 0; x < listPicContent.size(); x++){
            XWPFParagraph paragraph1 = document.createParagraph();
            //设置之段落左对齐
            paragraph1.setAlignment(ParagraphAlignment.valueOf(STJc.INT_LEFT));
            // 
            XWPFRun firstRun = paragraph1.createRun();
            firstRun.setFontSize(13);
            firstRun.setFontFamily("黑体");
            firstRun.addTab();
             //存储图片名称对应数据下标  便于实现数据与文本对应
            String picName = "D://Temp//" + x + ".png" ;  //测试服务器地址即可
            File file = new File(picName);
            if(file.exists()){
                createPicture(document,picName); //写入图片
            }
            firstRun.setText((x+1)+ "、" + listPicContent.get(x).get("item")); // 序号+写入图片对应文字
            firstRun.addBreak(); //换行
            firstRun.addTab();
            firstRun.addBreak(); //换行
        }
    	//路径问题处理
        String path = "D://Temp//";
        File savefile = new File(path);
        if (!savefile.exists()) {
            savefile.mkdirs();
        }
        String flieName = path + "xxxx分析报告"+".docx";
        FileOutputStream fos = new FileOutputStream(flieName);
        document.write(fos);
        fos.close();
  • 最后进行文件下载
FileUtil.downloadFile(fileName,response);//执行下载
  • 表格插入图片方法
	/**
     *
     * @param doc
     * @param picPath
     * @throws InvalidFormatException
     * @throws IOException
     */
    public void createPicture(XWPFDocument doc, String picPath) throws InvalidFormatException, IOException, org.apache.poi.openxml4j.exceptions.InvalidFormatException {
        XWPFParagraph paraX = doc.createParagraph();
        XWPFRun run = paraX.createRun();
        FileInputStream is = new FileInputStream(picPath);
        int picType = -1;
        //判断图片类型
        String suffix = picPath.substring(picPath.lastIndexOf(".")+1);
        if(suffix.equals("png")) picType = XWPFDocument.PICTURE_TYPE_PNG;
        else if(suffix.equals("jpg")) picType = XWPFDocument.PICTURE_TYPE_JPEG;
        run.addPicture(is, picType, picPath, Units.toEMU(300), Units.toEMU(200));
        is.close();
    }  
  • Base64格式转存图片工具类
import java.awt.image.BufferedImage;
import java.io.*;

public class Base64ToPicUtils {

    private static String PATH = "D:\\Temp\\";  //图片转存路径

    public static void convertBase64ToImage(StringBuffer base64Code,String name){
        String str = base64Code.toString();
        BufferedImage image = null;
        byte[] imageByte = null;
        if(StringUtils.isNotBlank(str)){
            int i = str.indexOf(",");
            String s = str.subSequence(i+1, str.length()).toString();
            String replace = s.replace(" ", "+");
            try {
                BASE64Decoder decoder = new BASE64Decoder();
                byte[] imgbyte = decoder.decodeBuffer(s);
                String aa = PATH + name + ".png";
                OutputStream os = new FileOutputStream(aa);
                os.write(imgbyte, 0, imgbyte.length);
                os.flush();
                os.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
  • 文件下载工具类
package com.sdyy.common.utils;

import cn.hutool.core.io.IoUtil;
import com.aspose.words.Document;
import com.aspose.words.License;
import com.aspose.words.SaveFormat;
import sun.misc.BASE64Decoder;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.Map;
import java.util.UUID;


public class FileUtil {

    public static void uploadFile(byte[] file, String filePath, String fileName) throws Exception {
        File targetFile = new File(filePath);
        if (!targetFile.exists()) {
            targetFile.mkdirs();
        }
        FileOutputStream out = new FileOutputStream(filePath + fileName);
        out.write(file);
        out.flush();
        out.close();
    }

    public static boolean deleteFile(String fileName) {
        File file = new File(fileName);
        // 如果文件路径所对应的文件存在,并且是一个文件,则直接删除
        if (file.exists() && file.isFile()) {
            if (file.delete()) {
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    }

    public static String renameToUUID(String fileName) {
        return UUID.randomUUID() + "." + fileName.substring(fileName.lastIndexOf(".") + 1);
    }


    /**
     * 创建目录
     */
    public static void createDir(String fileSavePath) {
        File file = new File(fileSavePath);
        if (!file.exists()) {
            file.mkdirs();
        }
    }

    public static File doc2pdf(File file, String docPath) throws Exception {
        //1.设置凭证
        String basePath = Thread.currentThread().getContextClassLoader().getResource("").getPath() + "static/docs/license.xml";
        InputStream license = new FileInputStream(basePath);// 凭证文件
        License aposeLic = new License();
        aposeLic.setLicense(license);
        //2.进行转换
       FileInputStream input = new FileInputStream(file);
        String fileName = file.getName().replace("docx", "") + "pdf";
        File pdf = new File(docPath + fileName);
        OutputStream out = new FileOutputStream(pdf);
        Document doc = new Document(input);                    //Address是将要被转化的word文档
        doc.save(out, SaveFormat.PDF);//全面支持DOC, DOCX, OOXML, RTF HTML, OpenDocument, PDF, EPUB, XPS, SWF 相互转换
        IoUtil.close(input);
        IoUtil.close(out);
        IoUtil.close(license);
        return pdf;
    }

	// 
    public static void downloadFile2(String filePath, HttpServletResponse response) {
        // 声明工具类
        BufferedInputStream in = null;
        BufferedOutputStream out = null;

        try {
            // 若路径为空
            if (StringUtils.isEmpty(filePath)) {
                throw new Exception("invalid filepath of null.");
            }

            // 没找到文件
            File file = new File(filePath);
            if (!file.exists()) {
                throw new Exception("file not exist in path [" + filePath + "]");
            }

            // 获取文件名
            String fileName = file.getName();

            // 输出文件流到浏览器
            in = new BufferedInputStream(new FileInputStream(filePath));
            out = new BufferedOutputStream(response.getOutputStream());
            response.setContentType("application/x-download;charset=utf-8");
            response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
            byte[] buffer = new byte[8192];
            int count = 0;
            while ((count = in.read(buffer, 0, 8192)) != -1) {
                out.write(buffer, 0, count);
            }

            out.flush();
            file = null;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            closeStream(in, out);
        }
    }

    /**
     * 关闭输入输出流
     */
    public static void closeStream(InputStream in, OutputStream out) {
        if (null != in) {
            try {
                in.close();
            } catch (IOException e) {
                // e.printStackTrace();
            }
        }
        if (null != out) {
            try {
                out.close();
            } catch (IOException e) {
                // e.printStackTrace();
            }
        }
}

    public static String downloadFile(String filePath,HttpServletResponse response) throws UnsupportedEncodingException {
        String[] strArray=filePath.split("//");
        String filename=strArray[strArray.length-1];
        response.setHeader("Access-Control-Expose-Headers","Content-Disposition");
        response.setCharacterEncoding("UTF-8");
        response.setHeader("content-type", "application/octet-stream");
        response.setContentType("application/octet-stream");
        try {
            response.setHeader("Content-Disposition", "attachment;filename=" + java.net.URLEncoder.encode(filename, "UTF-8"));
        } catch (UnsupportedEncodingException e2) {
            e2.printStackTrace();
        }
        byte[] buff = new byte[1024];
        BufferedInputStream bis = null;
        OutputStream os = null;
        try {
            os = response.getOutputStream();
            bis = new BufferedInputStream(new FileInputStream(new File(filePath)));
            int i = bis.read(buff);
            while (i != -1) {
                os.write(buff, 0, buff.length);
                os.flush();
                i = bis.read(buff);
            }
        } catch (FileNotFoundException e1) {
            return "系统找不到指定的文件";
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (bis != null) {
                try {
                    bis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return "success";
    }


    /**
     * base64字符串转化成图片
     * @param imgStr
     * @return
     */
    public static String GenerateImage(String imgFile,String imgStr) {   //对字节数组字符串进行Base64解码并生成图片
        String type = "png";
        if (StringUtils.isBlank(imgStr)) //图像数据为空
            return "false";
        BASE64Decoder decoder = new BASE64Decoder();
        try
        {
            //获取图片类型
            String[] splitData = imgStr.split(";base64,");
            if(splitData.length == 1) {
                imgStr = splitData[0];
            }else {
                type = splitData[0].split("/")[1];
                imgStr = splitData[1];
            }
            //Base64解码
            byte[] b = decoder.decodeBuffer(imgStr);
            for(int i=0;i<b.length;++i)
            {
                if(b[i]<0)
                {//调整异常数据
                    b[i]+=256;
                }
            }
            //生成jpeg图片
            String imgFilePath = imgFile + "." +type;//新生成的图片
            OutputStream out = new FileOutputStream(imgFilePath);
            out.write(b);
            out.flush();
            out.close();
            return imgFilePath;
        }
        catch (Exception e)
        {
            return "false";
        }
    }
    /**
     * 删除文件夹(强制删除)
     *
     * @param path
     */
    public static void deleteAllFilesOfDir(File path) {
        if (null != path) {
            if (!path.exists())
                return;
            if (path.isFile()) {
                boolean result = path.delete();
                int tryCount = 0;
                while (!result && tryCount++ < 10) {
                    System.gc(); // 回收资源
                    result = path.delete();
                }
            }
            File[] files = path.listFiles();
            if (null != files) {
                for (int i = 0; i < files.length; i++) {
                    deleteAllFilesOfDir(files[i]);
                }
            }
            path.delete();
        }
    }
}
  • 处理多个canvas画布组成的图表
/**
 * 将多个canvas画布组成的图表合成为一个完整的canvas,并获取完整的dataURl
 * @param divId divId 包含整个画布的divId
 * @returns {String} widthXheight@dataURL 例:
 * 400X300@data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA
 */
function getFullCanvasDataURL(divId){
    debugger;
    //将第一个画布作为基准。
    var baseCanvas = $("#"+divId).find("canvas").first()[0];
    if(!baseCanvas){
        return false;
    };
    var width = baseCanvas.width;
    var height = baseCanvas.height;
    var ctx = baseCanvas.getContext("2d");

//    const imageData = ctx.getImageData(0, 0,width,height);
//                 for (let i = 0; i < imageData.data.length; i += 4) {
//                      // 当该像素是透明的,则设置成白色
//                      if (imageData.data[i + 3] === 0) {
//                        imageData.data[i] = 255;
//                        imageData.data[i + 1] = 255;
//                        imageData.data[i + 2] = 255;
//                        imageData.data[i + 3] = 255;
//                      }
//                    }
//                    ctx.putImageData(imageData, 0, 0);
//                   var dataURL = canvasDom.toDataURL('image/png');
    //遍历,将后续的画布添加到在第一个上
    $("#"+divId).find("canvas").each(function(i,canvasObj){
        if(i>0){
            var canvasTmp = $(canvasObj)[0];
            ctx.drawImage(canvasTmp,0,0,width,height);

        }
    });
    //获取base64位的url
    return baseCanvas.toDataURL('image/png');
}

END 导出文件效果

POI实现导出word文件【内容包括文本,表格,图片】_第1张图片
POI实现导出word文件【内容包括文本,表格,图片】_第2张图片

你可能感兴趣的:(后端,java)