①FreeMarker大家应该会比较熟悉,一个模板引擎。
②easyexcel 是阿里巴巴开源,用于快速、简单避免OOM的java处理Excel工具。
②JACOB是一个JAVA-COM Bridge,允许您从Java调用COM Automation组件。它使用JNI对COM和Win32库进行本机调用。
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);
}
标签(我用的是wps,如果是office word,可能并不一定是这个标签),这里正常显示的会是一长串base64编码后的字符串。因为这里我需要替换图片,所以用了占位符。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);
}
}
所需依赖我放在百度云盘上了,如果有用到的朋友遇到问题,可以来微博或者github上面找我: https://pan.baidu.com/s/1uV54gViWt9x3eDYB0OAM0w 提取码: yy95
解压后会是下图所示,将两个dll文件放在jdk的bin目录下, 将jacob.jar导入项目中。
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,所以可能直接复制以上代码并不能直接使用)