这边用到的依赖是FreeMarker、hutool工具类
<!--FreeMarker依赖-->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.28</version>
</dependency>
<!--Hutool工具类-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.17</version>
</dependency>
2.1 : 将需要动态替换的内容转换成占位符名称并用${占位符}包裹起来.
2.2 : 将文件保存为xml文件。
2.3 : 将文件复制到编译器idea下并修改后缀名称为 模板文件.ftl
注意 : 转换后的Excel文件中的单元格都为String类型,如果为数字最好将String转换成Number类型,这样才能进行Excel导出的动态公式计算。
2.4 : 如果需要遍历多个单元格,可以根据Freemarker语法在单元格中进行遍历添加(先找到要遍历的Table(表格)标签,行遍历找Row标签,单元格遍历找Cell标签)
<#list PjCenterPlans as data>
<Table ss:ExpandedColumnCount="24" ss:ExpandedRowCount="27" x:FullColumns="1" x:FullRows="1"
ss:DefaultColumnWidth="54" ss:DefaultRowHeight="13.5">
<Row ss:Height="20.25">
<Cell ss:StyleID="s166" ss:MergeAcross="23">
<#--取值根据遍历后的对象来取值 data.数据-->
<Data ss:Type="String">${data.projectPage!}Data>
Cell>
Row>
Table>
#list>
#本项目的代码,仅参考具体的操作,具体的核心方法为
//本项目的代码,方法仅供参考。
public void print() throws IOException, TemplateException{
Map<String, Object> map = new HashMap<>();
List<ExportCentrePlanVo> vos = new ArrayList<>();
map.put("PjCenterPlans", vos);
ModelTemplateUtil templateUtil = new ModelTemplateUtil();
//渲染Excel模板文件(方法在下面展示)
File file = templateUtil.createExcel(map, "模板名称", "输出路径");
//在浏览器进行下载
FileUtil.downFile(IdWorker.get32UUID() + ".xlsx", file, true);
}
//临时文件夹 (user.dir:当前项目相对路径 当前项目路径/temporary/)
public static final String temporary = System.getProperty("user.dir").concat(File.separator + "temporary" + File.separator);
//freeMark模板文件夹路径 当前项目路径/modelTemplate/
private static final String modelTemplate = System.getProperty("user.dir").concat(File.separator + "modelTemplate");
/**
* FreeMarker生成Excel方法
*
* @param dataMap 数据
* @param templateName 目标名
* @param saveFilePath 保存文件路径的全路径名(路径+文件名)
*/
public File createExcel(Map<String, Object> dataMap, String templateName, String saveFilePath) throws IOException, TemplateException {
//临时下载文件路径
saveFilePath = saveFilePath.concat(RandomUtil.randomInt(0, Integer.MAX_VALUE) + ".xls");
// 设置模板文件的父目录
FileTemplateLoader templateLoader = new FileTemplateLoader(new File(modelTemplate));
//加载模板(路径)数据
config.setTemplateLoader(templateLoader);
//设置异常处理器 这样的话 即使没有属性也不会出错 如:${list.name}...不会报错
config.setTemplateExceptionHandler(TemplateExceptionHandler.IGNORE_HANDLER);
Template template = null;
// 数据准备,可以是从数据库中查询,这里为了方便演示,手动 new 了
// 生成 excel 文件
try {
if (templateName.contains("."))
template = config.getTemplate(templateName);
else
template = config.getTemplate(templateName + ".ftl");
} catch (TemplateNotFoundException e) {
log.error("模板文件未找到", e);
e.printStackTrace();
} catch (MalformedTemplateNameException e) {
log.error("模板类型不正确", e);
e.printStackTrace();
} catch (ParseException e) {
log.error("解析模板出错,请检查模板格式", e);
e.printStackTrace();
} catch (IOException e) {
log.error("IO读取失败", e);
e.printStackTrace();
}
File outFile = new File(saveFilePath);
if (!outFile.getParentFile().exists()) {
outFile.getParentFile().mkdirs();
}
Writer out;
FileOutputStream fos = null;
try {
fos = new FileOutputStream(outFile);
} catch (FileNotFoundException e) {
log.error("输出文件时未找到文件", e);
e.printStackTrace();
}
out = new BufferedWriter(new OutputStreamWriter(fos));
//将模板中的预先的代码替换为数据
try {
template.process(dataMap, out);
} catch (TemplateException e) {
log.error("填充模板时异常", e);
e.printStackTrace();
} catch (IOException e) {
log.error("IO读取时异常", e);
e.printStackTrace();
}
log.info("由模板文件:" + templateName + ".ftl" + " 生成文件 :" + saveFilePath + " 成功!!");
try {
out.close();//web项目不可关闭
} catch (IOException e) {
log.error("关闭Write对象出错", e);
e.printStackTrace();
}
return outFile;
}
/**
* 下载文件到浏览器
*
* @param fileName 要下载的文件名
* @param file 需要下载的文件对象
* @param remove 是否删除文件
* @throws IOException
*/
public static void downFile(String fileName, File file, Boolean remove) throws IOException {
//获取上下文的request和response
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (ObjectUtil.isNull(attributes)) {
return;
}
HttpServletRequest request = attributes.getRequest();
HttpServletResponse response = attributes.getResponse();
// 文件存在才下载
if (file.exists()) {
OutputStream out = null;
FileInputStream in = null;
try {
// 1.读取要下载的内容
in = new FileInputStream(file);
// 2. 告诉浏览器下载的方式以及一些设置
// 解决文件名乱码问题,获取浏览器类型,转换对应文件名编码格式,IE要求文件名必须是utf-8, firefo要求是iso-8859-1编码
setHttpHeader(request, response, fileName);
// 将要下载的文件内容通过输出流写到浏览器
assert response != null;
out = response.getOutputStream();
int len;
byte[] buffer = new byte[1024];
while ((len = in.read(buffer)) > 0) {
out.write(buffer, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (out != null) {
out.close();
}
if (in != null) {
in.close();
}
if (remove && file.isFile() && file.exists()) {
file.delete();
System.out.println(String.format("%s文件删除成功", file.getName()));
}
}
}
![在这里插入图片描述](https://img-blog.csdnimg.cn/49fca25640ed4036838415e652d118b9.png
/**
* xml回车符(特殊符号),在每一个需要换行的文字后面拼接上该字符即可完成换行操作
*/
private final String chr = "
";