Java读取Excel并生成Word&PDF

  • 最近需要用Java处理Excel中的数据,并生成word和pdf格式的文档(其中word和pdf需要带背景图),所以在这里做下总结。
  • 使用技术:FreeMarker + easyexcel + jacob

①FreeMarker大家应该会比较熟悉,一个模板引擎。
②easyexcel 是阿里巴巴开源,用于快速、简单避免OOM的java处理Excel工具。
②JACOB是一个JAVA-COM Bridge,允许您从Java调用COM Automation组件。它使用JNI对COM和Win32库进行本机调用。

  • 使用easyexcel处理excel
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.metadata.BaseRowModel;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
 * JavaBean与Excel之间的关系映射
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ERReport extends BaseRowModel {
    @ExcelProperty(value = "省", index = 0)
    private String province;
    @ExcelProperty(value = "市", index = 1)
    private String city;
    @ExcelProperty(value = "学校", index = 2)
    private String school;
    @ExcelProperty(value = "班级", index = 3)
    private String classs;
    @ExcelProperty(value = "老师", index = 4
    private String teacher;
}  
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.metadata.BaseRowModel;
import com.google.common.collect.Lists;
/**
 * 自定义Listener继承AnalysisEventListener,重写invoke方法,为了方便获取值,添加了一个getData的方法
 */
public class ExcelListener<T extends BaseRowModel> extends AnalysisEventListener<T> {
    private final List<T> data = Lists.newArrayList();
    @Override
    public void invoke(T t, AnalysisContext analysisContext) {
        data.add(t);
    }
    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {

    }
    public List<T> getData(){
        return data;
	}
public class ExcelUtils {
	/**
 	 * 读取excel的方法
	 */
    public static <T extends BaseRowModel> List<T> readExcel(final InputStream inputStream, final Class<? extends BaseRowModel> clazz) {
        if (null == inputStream) {
            throw new NullPointerException("the inputStream is null!");
        }
        AnalysisEventListener listener = new ExcelListener();
        ExcelReader reader = new ExcelReader(inputStream, null, listener);
        reader.read(new com.alibaba.excel.metadata.Sheet(1, 1, clazz));
        return ((ExcelListener) listener).getData();
    }
    public static void main(String[] args) throws Exception {
        String filePath = "C:\\Users\\Administrator\\Desktop\\test.xlsx";
        List<ERReport> datas = ExcelUtils.readExcel(new FileInputStream(new File(filePath)), ERReport.class);
        datas.forEach(System.out::println);
    }
  • 新建一个word文件,把固定不变的地方写好,将要替换的值改用${xxx}占位符的方式,然后把后缀名改为.ftl。(注:如果此条路行不通,可以先将word另存为xml文件,再将xml转为ftl格式),放到项目的resource/templates目录下,便于读取。
    Java读取Excel并生成Word&PDF_第1张图片
  • 如果需要设置图片,打开ftl文件后,搜索标签(我用的是wps,如果是office word,可能并不一定是这个标签),这里正常显示的会是一长串base64编码后的字符串。因为这里我需要替换图片,所以用了占位符。
    Java读取Excel并生成Word&PDF_第2张图片
  • 转为word的代码如下:
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import sun.misc.BASE64Encoder;

import java.io.*;
import java.util.HashMap;
import java.util.Map;
public class WordUtils {
   public static void main(String[] args) throws Exception {
       String imgPath = "C:\\Users\\Administrator\\Desktop\\timg.jpg";
       BASE64Encoder encoder = new BASE64Encoder();
       String imgStr = encoder.encode(encode(imgPath));
       System.out.println(imgStr);
        // 这里只是一个示例,key=value的格式,这里的key对应的ftl文件占位符{}中的字符串。
       Map<String, Object> dataMap = new HashMap<String, Object>() {{
           put("imgStr",imgStr);
           put("province","北京市");
           put("city","海淀区");
           put("school","");
           put("class","二三班");
       }};
        //处理excel,将其中的数据填充至模板中,最后生成word。
   	   List<ERReport> datas = ExcelUtils.readExcel(new FileInputStream(new File(filePath)), ERReport.class);
   	   datas.forEach((ERReport e) -> {
               try {
                   processTemplate(e, “Your File Name”);
                   System.out.println("转换成功");
               } catch (Exception ex) {
                   LOGGER.error("Excel转换Word错误.", ex);
               }
           });
   }
 	private static byte[] encode(String imagePath) throws IOException {
       InputStream in = null;
       byte[] data = null;
       try {
           in = new FileInputStream(imagePath);
           data = new byte[in.available()];
           in.read(data);
           in.close();
       } catch (Exception e) {
           e.printStackTrace();
       } finally {
           if (in != null) {
               in.close();
           }
           return data;
       }
  	}

	public static void processTemplate(Object dataMap, String fileName) throws IOException, TemplateException {
       Configuration configuration = new Configuration();
       configuration.setDefaultEncoding("utf-8");
       configuration.setClassForTemplateLoading(WordUtils.class, "/templates");
       Template template = configuration.getTemplate("template.ftl");
       File file = new File("C:\\Users\\Administrator\\Desktop\\" + fileName + ".docx");
       BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), "utf-8"));
       template.process(dataMap, bufferedWriter);
   }
}
  • word转pdf(使用jacob)

    所需依赖我放在百度云盘上了,如果有用到的朋友遇到问题,可以来微博或者github上面找我: https://pan.baidu.com/s/1uV54gViWt9x3eDYB0OAM0w 提取码: yy95
    解压后会是下图所示,将两个dll文件放在jdk的bin目录下, 将jacob.jar导入项目中。
    Java读取Excel并生成Word&PDF_第3张图片

  • word转pdf的代码如下:
public class PDFUtils {
    public static void main(String[] args) {
        String wordFile = "C:\\Users\\Administrator\\Desktop\\二年级五班.docx";
        String pdfFile = "C:\\Users\\Administrator\\Desktop\\二年级五班.pdf";
        processWordToPdf(wordFile,pdfFile);
    }
    public static void processWordToPdf(String wordFile,String pdfFile){
        ActiveXComponent app = null;
        System.out.println("开始转换...");
        // 开始时间
        long start = System.currentTimeMillis();
        try {
            // 打开word
            app = new ActiveXComponent("Word.Application");
            // 获得word中所有打开的文档
            Dispatch documents = app.getProperty("Documents").toDispatch();
            System.out.println("打开文件: " + wordFile);
            // 打开文档
            Dispatch document = Dispatch.call(documents, "Open", wordFile, false, true).toDispatch();
            // 如果文件存在的话,不会覆盖,会直接报错,所以我们需要判断文件是否存在
            File target = new File(pdfFile);
            if (target.exists()) {
                target.delete();
            }
            System.out.println("另存为: " + pdfFile);
            // 另存为,将文档报错为pdf,其中word保存为pdf的格式宏的值是17
            Dispatch.call(document, "SaveAs", pdfFile, 17);
            // 关闭文档
            Dispatch.call(document, "Close", false);
            // 结束时间
            long end = System.currentTimeMillis();
            System.out.println("转换成功,用时:" + (end - start) + "ms");
        } catch (Exception e) {
            System.out.println("转换失败" + e.getMessage());
        } finally {
            // 关闭office
            app.invoke("Quit", 0);
        }
    }
}
  • 总结

总体思路:利用easyexcel读取excel里面的数据,然后利用事先定义好的freemarker模板,往里面填充值,最后生成word,再利用jacob根据word生成pdf。(代码中用到了lombok和google guava,所以可能直接复制以上代码并不能直接使用)

你可能感兴趣的:(Java)