依赖如下
<dependency>
<groupId>com.alibabagroupId>
<artifactId>easyexcelartifactId>
<version>2.2.6version>
<exclusions>
<exclusion>
<groupId>javax.servletgroupId>
<artifactId>servlet-apiartifactId>
exclusion>
<exclusion>
<groupId>org.apache.poigroupId>
<artifactId>poiartifactId>
exclusion>
<exclusion>
<groupId>org.apache.poigroupId>
<artifactId>poi-ooxmlartifactId>
exclusion>
<exclusion>
<groupId>org.apache.poigroupId>
<artifactId>poi-ooxml-schemasartifactId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>org.apache.poigroupId>
<artifactId>poiartifactId>
<version>4.1.1version>
dependency>
<dependency>
<groupId>org.apache.poigroupId>
<artifactId>poi-ooxmlartifactId>
<version>4.1.1version>
dependency>
<dependency>
<groupId>org.jxlsgroupId>
<artifactId>jxlsartifactId>
<version>2.6.0version>
<exclusions>
<exclusion>
<groupId>ch.qos.logbackgroupId>
<artifactId>logback-coreartifactId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>org.jxlsgroupId>
<artifactId>jxls-poiartifactId>
<version>1.2.0version>
dependency>
<dependency>
<groupId>fr.opensagres.xdocreportgroupId>
<artifactId>fr.opensagres.xdocreport.coreartifactId>
<version>2.0.2version>
dependency>
<dependency>
<groupId>fr.opensagres.xdocreportgroupId>
<artifactId>fr.opensagres.xdocreport.documentartifactId>
<version>2.0.2version>
dependency>
<dependency>
<groupId>fr.opensagres.xdocreportgroupId>
<artifactId>fr.opensagres.xdocreport.templateartifactId>
<version>2.0.2version>
dependency>
<dependency>
<groupId>fr.opensagres.xdocreportgroupId>
<artifactId>fr.opensagres.xdocreport.document.docxartifactId>
<version>2.0.2version>
dependency>
<dependency>
<groupId>fr.opensagres.xdocreportgroupId>
<artifactId>fr.opensagres.xdocreport.template.freemarkerartifactId>
<version>2.0.2version>
dependency>
<dependency>
<groupId>org.freemarkergroupId>
<artifactId>freemarkerartifactId>
<version>2.3.20version>
dependency>
<dependency>
<groupId>commons-iogroupId>
<artifactId>commons-ioartifactId>
<version>2.5version>
dependency>
实体类:
@Data
@ContentRowHeight(15) //内容行高
@HeadRowHeight(25)//表头行高
public class Users implements Serializable {
/**
* 主键id
*/
@ExcelIgnore
//不导出该字段
private Long id;
/**
* 账号
*/
@ExcelProperty(value = "账号", index = 0)
//设置该列为第0列,表头为“账号”,
@ColumnWidth(20)
//该字段列的宽度
private String account;
/**
* 用户名
*/
@ExcelProperty(value = "用户名", index = 1)
@ColumnWidth(15)
private String username;
/**
* 密码
*/
@ExcelProperty(value = "密码", index = 2)
@ColumnWidth(20)
private String password;
/**
* 描述
*/
@ExcelProperty(value = "描述", index = 3)
@ColumnWidth(40)
private String described;
/**
* 创建人
*/
@ExcelProperty(value = "创建人", index = 4)
@ColumnWidth(20)
private String cname;
/**
* 修改人
*/
@ExcelProperty(value = "修改人", index = 5)
@ColumnWidth(20)
private String chname;
}
工具类:
public class Export {
//导出excel,fileName为文件名称,data是要导出的数据,返回值需要是void
public static void exportExcel(HttpServletResponse response, String fileName, List data) {
// 设置下载信息
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
try {
EasyExcel.write(response.getOutputStream(), Users.class)
.registerWriteHandler(setStyle())
.sheet("导出测试").doWrite(data);
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
response.getOutputStream().close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//设置导出的样式
private static HorizontalCellStyleStrategy setStyle() {
WriteCellStyle headWriteCellStyle = new WriteCellStyle();
//设置背景颜色
headWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());
//设置头字体
WriteFont headWriteFont = new WriteFont();
headWriteFont.setFontHeightInPoints((short) 13);
headWriteFont.setBold(true);
headWriteCellStyle.setWriteFont(headWriteFont);
//设置头居中
headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
//内容策略
WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
//设置 自动换行
// contentWriteCellStyle.setWrapped(true);
//设置 垂直居中
contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
//设置 水平居中
contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
return horizontalCellStyleStrategy;
}
}
controller
//返回值需要是void
@GetMapping("/exportData")
public void exportData(HttpServletResponse response) {
// 查询数据信息
List<Users> list = usersService.list();
try {
String fileName = URLEncoder.encode("用户列表","UTF-8");
Export.exportExcel(response,fileName, list,Users.class);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
导出Word方式多种多样,通常有以下几种方式:
1. 使用第三方Java工具类库Hutool的Word工具类
2. 利用Apache POI和FreeMarker模板引擎;
3. 第三方报表工具。
上面的几种方式虽然可以实现Word文档的导出,但有以下缺点:
第一种方式操作简单,但也只能生成简单的Word文档,无法生成有表格的Word文档;
第二种方式可以生成复杂的Word文档,但是还要进行Word转xml,xml转ftl的双重转换,不适合内容经常变更的Word文档;
第三种方式有时候不适合对格式要求严格的文档。
下面介绍通过XDocReport和FreeMarker模板引擎生成Word文档的方法。
例如我们现在有以下文档,我们可以用动态变量去替换文档中的数据
关于Word模板中的动态变量,我们知道:
1.Word文档中的Word域,word域是引导Word在文档中自动插入文字、图形、页码或其他信息的一组代码。
在这里我们可以把,Word域理解成标识符,这个标识符表示Word文档中要被替换的内容;
2.FreeMarker模板下的变量表达式,比如用${city}替换Word示例模板中的北京市。
了解了以上两个概念后,我们就可以动手编辑Word模板了,步骤如下:
首先在Word模板中选中要替换的文本,在这儿拿标题中的"测试文档"为例,然后键盘使用 Ctrl + F9 组合键将其设置为域,此时文本会被"{}"包围,接着鼠标右键选择【编辑域(E)…】:
在弹出的对话框中,类别选择“邮件合并”,域名选择 “MergeField”,域属性中的域名填入模版表达式${title},点击【确定】按钮:
编辑后的效果如下:
将文本替换为表达式后,得到模板:
为表格中的数据,通常都是动态,大部分情况就是对集合的遍历。
具体操作步骤如下:
选定表格中要替换的文本,然后键盘使用 Ctrl + F9 组合键将其设置为域,接着鼠标右键选择【编辑域(E)…】:
最终得到模板:
@GetMapping("/exportWord")
public void exportWord(HttpServletResponse response) {
//获取Word模板,模板存放路径在项目的resources目录下
String fileName ="测试文档.docx";
// 查询数据信息
List<Users> list = usersService.list();
try {
//注册xdocreport实例并加载FreeMarker模板引擎
//获取Word模板,模板存放路径在项目的resources目录下
InputStream ins = this.getClass().getResourceAsStream("/模板.docx");
//注册xdocreport实例并加载FreeMarker模板引擎
IXDocReport report = XDocReportRegistry.getRegistry().loadReport(ins,
TemplateEngineKind.Freemarker);
//创建xdocreport上下文对象
IContext context = report.createContext();
//创建要替换的文本变量
context.put("title", "文档标题");
context.put("name", "导出文档的人");
context.put("doc", "至今一切社会的历史都是阶级斗争的历史。\n" +
"\n" +
" 自由民和奴隶、贵族和平民、领主和农奴、行会师傅和帮工,一句话,压迫者和被压迫者,始终处于相互对立的地位,进行不断的、有时隐蔽有时公开的斗争,而每一次斗争的结局是整个社会受到革命改造或者斗争的各阶级同归于尽。\n" +
"\n" +
" 在过去的各个历史时代,我们几乎到处都可以看到社会完全划分为各个不同的等级,看到社会地位分成的多种多样的层次。在古罗马,有贵族、骑士、平民、奴隶,在中世纪,有封建主、臣仆、行会师傅、帮工、农奴,而且几乎在每一个阶级内部又有一些特殊的阶层。\n" +
"\n" +
" 从封建社会的灭亡中产生出来的现代资产阶级社会并没有消灭阶级对立。它只是用新的阶级、新的压迫条件、新的斗争形式代替了旧的。\n" +
"\n" +
" 但是,我们的时代,资产阶级时代,却有一个特点:它使阶级对立简单化了。整个社会日益分裂为两大敌对的阵营,分裂为两大相互直接对立的阶级:资产阶级和无产阶级。");
//需要注意的是替换文档模板里的数据如果不能为空,可以为空字符串
context.put("list", list);
//创建字段元数据
FieldsMetadata fm = report.createFieldsMetadata();
//Word模板中的表格数据对应的集合类型
fm.load("list", Users.class, true);
//输出到本地目录
//FileOutputStream out = new FileOutputStream(new File("D://商品销售报表.docx"));
//report.process(context, out);
//浏览器端下载
response.setCharacterEncoding("utf-8");
response.setContentType("application/msword");
response.setHeader("Content-Disposition", "attachment;filename="
.concat(String.valueOf(URLEncoder.encode(fileName, "UTF-8"))));
report.process(context, response.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
} catch (XDocReportException e) {
e.printStackTrace();
}
}