日常开发工作中,我们时常会有一些管理系统相关的需求,例如在做一些窗口柜台效率提升的项目时,就时常会有需求在线上通过表单的形式填写,直接生成已填写好的合同、文件、表格等。
今天我们主要来描述一下,通过java如何实现这种方式?
1、首先,我们java项目无论是javaweb还是springboot,抑或是springCloud项目,我们都必须在业务实现的模块引入对应的jar包
<!-- poi-tl模板填充工具 -->
<dependency>
<groupId>com.deepoove</groupId>
<artifactId>poi-tl</artifactId>
<version>1.12.2</version>
</dependency>
2、其次,我们需要调整项目的poi的版本,调整到与poi-tl刚好适合的版本
比如:是满足要求的。
<poi.version>5.2.5</poi.version>
3、我们将需要填充的文件放置到项目可以读取到的路径下:
这里我们为了方便演示就直接将文本放置在项目的resource路径之下了:

76ae2f21-9981-4630-963e-2eccf532ebcd.png
4、我们打开该文件看一下:

8decbd95-164f-4a70-bb35-071fc0ba9813.png
红色框住的部分是一个Excel的表格,可以按照自己书写内容的多少进行增加减少。
5、编写接口代码:
此处为了方便大家清晰的使用,我将整个Controller复制过来了:
@RestController
@RequestMapping("/files")
public class FilesController {
private static final Logger log = LoggerFactory.getLogger(FilesController.class);
@PostMapping("/filing")
public void downloadWordTemplateFillData(HttpServletResponse response, @RequestBody ParamEntity entity) throws Exception {
if (null == entity) {
throw new ServiceException("数据不能不能为空!");
}
if (StringUtils.isEmpty(entity.getFileType())) {
throw new ServiceException("名称类型不能为空!");
}
String parentPath = System.getProperty("user.dir") + File.separator + "temp" + File.separator;
File file = new File(parentPath);
if (!file.exists()) {
file.mkdirs();
}
// 暂放于此
String outPath = "";
String fileName = "";
if (entity.getFileType().equals("excel")){
outPath = parentPath + "templateNew" + ".xlsx";
}else{
outPath = parentPath + "templateNew" + ".docx";
}
File excelFile = new File(outPath);
if (excelFile.exists()) {
excelFile.delete();
}
FileInputStream in = null;
OutputStream outs = null;
Map<String, Object> sourceTextMap = (Map<String, Object>) entity.getEntity();
try {
if (entity.getFileType().equals("word")){
Map<String, Object> templateData = new HashMap<String, Object>() {{
put("dept", null == sourceTextMap.get("dept") ? "" : sourceTextMap.get("dept").toString());
put("name", null == sourceTextMap.get("name") ? "" : sourceTextMap.get("name").toString());
put("startTime", null == sourceTextMap.get("startTime") ? "" : sourceTextMap.get("startTime").toString());
put("endTime", null == sourceTextMap.get("endTime") ? "" : sourceTextMap.get("endTime").toString());
put("a1", new HashMap<String, Object>() {{
put("one", null == sourceTextMap.get("one") ? "" : sourceTextMap.get("one").toString());
put("two", null == sourceTextMap.get("two") ? "" : sourceTextMap.get("two").toString());
put("three", null == sourceTextMap.get("three") ? "" : sourceTextMap.get("three").toString());
put("four", null == sourceTextMap.get("four") ? "" : sourceTextMap.get("four").toString());
put("five", null == sourceTextMap.get("five") ? "" : sourceTextMap.get("five").toString());
}});
}};
// 读取模板文件
try (InputStream templateIn = FilesController.class.getResourceAsStream("/template/template.docx")) {
// 生成模板文件
assert templateIn != null;
XWPFTemplate template = XWPFTemplate.compile(templateIn).render(templateData);
template.writeAndClose(Files.newOutputStream(Paths.get(outPath)));
// 这个目的是:生成文件之后调用 cmd 打开本地文件,实际生产不需要该操作
Runtime.getRuntime().exec(String.format("cmd /c %s", outPath));
} catch (IOException e) {
log.error("导出异常:" + e);
}
}
}
catch (Exception e){
log.error("导出异常:" + e);
} finally {
IOUtils.closeQuietly(in);
IOUtils.closeQuietly(outs);
}
}
}
6、构造填充部分的实体类:
public class ParamEntity {
private Object entity;
private String fileType;
public Object getEntity() {
return entity;
}
public void setEntity(Object entity) {
this.entity = entity;
}
public String getFileType() {
return fileType;
}
public void setFileType(String fileType) {
this.fileType = fileType;
}
@Override
public String toString() {
return "ParamEntity{" +
"entity=" + entity +
", fileType='" + fileType + '\'' +
'}';
}
}
7、核心代码讲解:写入操作:
FileInputStream in = null;
OutputStream outs = null;
Map<String, Object> sourceTextMap = (Map<String, Object>) entity.getEntity();
try {
if (entity.getFileType().equals("word")){
Map<String, Object> templateData = new HashMap<String, Object>() {{
put("dept", null == sourceTextMap.get("dept") ? "" : sourceTextMap.get("dept").toString());
put("name", null == sourceTextMap.get("name") ? "" : sourceTextMap.get("name").toString());
put("startTime", null == sourceTextMap.get("startTime") ? "" : sourceTextMap.get("startTime").toString());
put("endTime", null == sourceTextMap.get("endTime") ? "" : sourceTextMap.get("endTime").toString());
put("a1", new HashMap<String, Object>() {{
put("one", null == sourceTextMap.get("one") ? "" : sourceTextMap.get("one").toString());
put("two", null == sourceTextMap.get("two") ? "" : sourceTextMap.get("two").toString());
put("three", null == sourceTextMap.get("three") ? "" : sourceTextMap.get("three").toString());
put("four", null == sourceTextMap.get("four") ? "" : sourceTextMap.get("four").toString());
put("five", null == sourceTextMap.get("five") ? "" : sourceTextMap.get("five").toString());
}});
}};
// 读取模板文件
try (InputStream templateIn = FilesController.class.getResourceAsStream("/template/template.docx")) {
// 生成模板文件
assert templateIn != null;
XWPFTemplate template = XWPFTemplate.compile(templateIn).render(templateData);
template.writeAndClose(Files.newOutputStream(Paths.get(outPath)));
// 这个目的是:生成文件之后调用 cmd 打开本地文件,实际生产不需要该操作
Runtime.getRuntime().exec(String.format("cmd /c %s", outPath));
} catch (IOException e) {
log.error("导出异常:" + e);
}
}
}
8、测试效果:apiPost测试:

b210d10d-2008-48de-82a0-224fa2a964d6.png
根据测试得到的文件如图:

c3da32cf-3492-401d-b54e-43aaf4baf667.png
这样我们基本就完成了通过java代码实现文本文件的填充了,当然Excel及其他可支持的文件形式也是如此。