这篇文章干什么?
使用代码将word模板内容进行替换,并输出替换后的word。
思路总览
1、准备一个word模板,将里面需要替换的值改为${变量名}
2、将word导出为xml,复制一份xml,将复制的这份xml文件改为.ftl结尾的文件。
3、引包,编写(复制)代码。
1、准备word模板
${test1}就是要通过代码替换的内容
2、转换文件格式
xml文件可以通过word导出,然后修改后缀为.ftl的文件,我们需要的就是.ftl文件。并将该文件放入到指定文件夹。
3、编写代码
引包:
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.30</version>
</dependency>
代码:
import freemarker.template.Configuration;
import freemarker.template.Template;
import java.io.*;
// 相关工具
@Autowired
private ExportFile exportFile;
// 常量
private Configuration configuration = null;
/**
* 输出word
*/
public void commonExportWord() {
// 获取map数据
Map<String,Object> map = getColumnMapById();
// 配置configuration
Template template = setConfiguration();
try{
// 输出文档路径及名称
Writer out = null;
String fileName = exportFile.encodingFilenameWord("filename");
// 文件的输出位置(输出到本地绝对路径里)
File outFile = new File("/Users/relycf/Desktop/test");
// 文件的输出位置(输出到项目相对路径里)
// File outFile = new File(exportFile.getAbsoluteFile(fileName));
out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), StandardCharsets.UTF_8));
template.process(map, out);
out.close();
// 如果你只是输出到本地,就可以不要下面这句,这句主要是为了返回流下载word。
// exportFile.fileDownload(fileName);
}catch (Exception e){
log.error("导出word 输出流异常");
}
}
/**
* 构建填充word的数据
* @return
*/
public Map<String,Object> getColumnMapById(){
Map<String,Object> map = new HashMap<>();
map.put("test1","一百");
return map;
}
/**
* 填充 configuration
*/
public Template setConfiguration(){
// 这是三种不同的文件加载方式,我们本地读取用第二种
// public void setClassForTemplateLoading(Class clazz, String pathPrefix);
// public void setDirectoryForTemplateLoading(File dir) throws IOException;
// public void setServletContextForTemplateLoading(Object servletContext, String path);
Template template = null;
try{
configuration = new Configuration();
configuration.setDefaultEncoding("utf-8");
// 输入文档路径及名称
// 从本地路径读取存放ftl的文件夹
configuration.setDirectoryForTemplateLoading(new File("/Users/relycf/Desktop/test"));
// 从项目里的相对路径读取存放ftl的文件夹
// configuration.setDirectoryForTemplateLoading(new File("./template"));
// 被读取的文件
template = configuration.getTemplate("two2.ftl");
template.setEncoding("utf-8");
return template;
}catch (Exception e){
log.error("configuration配置失败");
}
return template;
}
相关方法中的封装代码:
@Component
@Slf4j
public class ExportFile {
/**
* 获取相对位置的下载路径
*
* @param filename 文件名称
*/
public String getAbsoluteFile(String filename) {
String downloadPath = "./download/" + filename;
File desc = new File(downloadPath);
if (!desc.getParentFile().exists()) {
desc.getParentFile().mkdirs();
}
return downloadPath;
}
/**
* 编码文件名word
*/
public String encodingFilenameWord(String filename) {
filename = UUID.randomUUID() + "_" + filename + ".docx";
return filename;
}
}
到这里,执行commonExportWord方法,就可以在输出的本地文件夹找到输出的.docx文件了,打开后发现已经成功了(如下图)。
补充–下载流
截止到这里,如果不需要下载文件流,只是输出到本地,已经结束了。如果需要输出流,还有一段代码:(需要将上面那个输出文件路径的位置改为相对的,让下载流能够获取到位置)
@Resource
private HttpServletResponse response;
/**
* 下载文件 如果需要下载才需要到这个方法
* @param fileName
* @param delete
*/
public void fileDownload(String fileName) {
try {
response.setContentType("application/json;charset=utf-8");
String filePath = getAbsoluteFile(fileName);
String realFileName = System.currentTimeMillis() + fileName.substring(fileName.indexOf("_") + 1);
FileUtils.setAttachmentResponseHeader(response, realFileName);
FileUtils.writeBytes(filePath, response.getOutputStream());
FileUtils.deleteFile(filePath);
} catch (Exception e) {
log.error("下载文件失败", e);
}
}
FileUtils:
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
/**
* 文件处理工具类
*
*/
public class FileUtils extends org.apache.commons.io.FileUtils{
/**
* 输出指定文件的byte数组
*
* @param filePath 文件路径
* @param os 输出流
* @return
*/
public static void writeBytes(String filePath, OutputStream os) throws IOException
{
FileInputStream fis = null;
try
{
File file = new File(filePath);
if (!file.exists())
{
throw new FileNotFoundException(filePath);
}
fis = new FileInputStream(file);
byte[] b = new byte[1024];
int length;
while ((length = fis.read(b)) > 0)
{
os.write(b, 0, length);
}
}
catch (IOException e)
{
throw e;
}
finally
{
if (os != null)
{
try
{
os.close();
}
catch (IOException e1)
{
e1.printStackTrace();
}
}
if (fis != null)
{
try
{
fis.close();
}
catch (IOException e1)
{
e1.printStackTrace();
}
}
}
}
/**
* 删除文件
*
* @param filePath 文件
* @return
*/
public static boolean deleteFile(String filePath)
{
boolean flag = false;
File file = new File(filePath);
// 路径为文件且不为空则进行删除
if (file.isFile() && file.exists())
{
file.delete();
flag = true;
}
return flag;
}
/**
* 下载文件名重新编码
*
* @param response 响应对象
* @param realFileName 真实文件名
* @return
*/
public static void setAttachmentResponseHeader(HttpServletResponse response, String realFileName) throws UnsupportedEncodingException
{
String percentEncodedFileName = percentEncode(realFileName);
StringBuilder contentDispositionValue = new StringBuilder();
contentDispositionValue.append("attachment; filename=")
.append(percentEncodedFileName)
.append(";")
.append("filename*=")
.append("utf-8''")
.append(percentEncodedFileName);
response.setHeader("Content-disposition", contentDispositionValue.toString());
}
/**
* 百分号编码工具方法
*
* @param s 需要百分号编码的字符串
* @return 百分号编码后的字符串
*/
public static String percentEncode(String s) throws UnsupportedEncodingException
{
String encode = URLEncoder.encode(s, StandardCharsets.UTF_8.toString());
return encode.replaceAll("\\+", "%20");
}
}
请求方式(需要自己写个controller):
结束。