计划逐步完善这款软件,让不懂编程的用户也可以轻松使用。
模板篇:
针对设计中的1、2步骤
第一步:从目录中读取.xml模板文件,而不是将模板文件内置到代码项目中。
原代码中用
configure.setClassForTemplateLoading(this.getClass(),"/excel2word/template");
读取项目中的模板目录,修改为
config.setDirectoryForTemplateLoading(new File("D:/temp/") );
即可实现从系统文件夹中读取模板文件。
第二步:word另存为.xml时${}之间产生的多余字符问题。在word中采用特殊字符如crmark01 替代${01}。
读取.xml文件之后,通过正则replaceAll将自定义标记格式替换为freemarker标记,存储为temp.xml文件,完成操作后再删除此文件。
正则表达式如下:
String xmlStr ="crmark09";
String str = xmlStr.replaceAll("crmark0?(\\d{1,2})", "\\${m$1}");
System.out.println(str);
将模板的文件导入、加载以及移除等功能抽象为一个TemplateManager类,并将路径等信息暂时存放在某个常量类中。
先将word另存为的template.xml文件读取为String,然后replaceAll掉所有的crmark标签为${m数字}格式,最后再生成一个新的temp.xml文件
注意:生成temp.xml的方式一定要采用字节流!字符流会造成生成的word格式错误。
WorkConstant代码:
package excel2word.config.constants;
public class WorkConstant {
public static final String WORK_PATH = "D:/temp/";
public static final String TEMPLATE_NAME = "template";
public static final String TEMP_NAME = "temp";
}
FileType代码:
package excel2word.config.enumerations;
public enum FileType {
XML_TYPE(".xml"),
WORD_03_TYPE(".doc"),
EXCEL_03_TYPE(".xls")
;
private String label;
private FileType(String label) {
this.label = label;
}
public String getLabel() {
return label;
}
}
TemplateManager代码:
package excel2word.template;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Writer;
import org.apache.commons.lang.StringUtils;
import excel2word.config.constants.WorkConstant;
import excel2word.config.enumerations.FileType;
import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapper;
import freemarker.template.Template;
import freemarker.template.TemplateExceptionHandler;
public class TemplateManager {
private static Configuration config = null;
private static String templatePath;
/**
* 生成模板temp文件
*
* @param TemplateType type 模板类型
* @return Template 模板
* @throws IOException
*/
public static Template loading(FileType templateType) throws IOException {
config = new Configuration();
config.setDefaultEncoding("utf-8");
//TODO work目录不存在 可自动创建
Template template = null;
InputStream in = null;
BufferedReader reader = null;
// Writer out = null;
FileOutputStream fos = null;
config.setObjectWrapper(new DefaultObjectWrapper());
config.setTemplateExceptionHandler(TemplateExceptionHandler.IGNORE_HANDLER);
try {
config.setDirectoryForTemplateLoading(new File(WorkConstant.WORK_PATH) );
in = new FileInputStream(new File(WorkConstant.WORK_PATH
+ WorkConstant.TEMPLATE_NAME + templateType.getLabel()));
reader = new BufferedReader(new InputStreamReader(in));
String line = null;
StringBuilder sb = new StringBuilder();
while ((line = reader.readLine()) != null) {
sb.append(line);
}
TemplateManager.templatePath = WorkConstant.WORK_PATH
+ WorkConstant.TEMP_NAME + templateType.getLabel();
// out = new BufferedWriter(new FileWriter(templatePath));
// out.write(sb.toString().replaceAll("crmark0?(\\d{1,2})", "\\${m$1}"));
fos = new FileOutputStream(new File(templatePath));
fos.write(sb.toString().replaceAll("crmark0?(\\d{1,2})", "\\${$1}").getBytes());
template = config.getTemplate(WorkConstant.TEMP_NAME + templateType.getLabel());
} catch (IOException e) {
e.printStackTrace();
destory();
throw e;
} finally {
try {
if (fos != null) {
fos.close();
}
// if (out != null) {
// out.close();
// }
if (in != null) {
in.close();
}
if (reader != null) {
reader.close();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// out = null;
fos = null;
in = null;
reader = null;
}
}
return template;
}
/**
* 销毁模板,清除temp文件
*/
public static void destory() {
if(StringUtils.isNotBlank(TemplateManager.templatePath)) {
File file = new File(TemplateManager.templatePath);
if (file.exists()) {
file.delete();
}
TemplateManager.templatePath = null;
config.clearTemplateCache();
}
}
}
工具篇:
针对设计中的3、4步骤
第一步:创建excel数据读取工具类;
原计划提取的数据形式应为List<Map<Integer, Object>>,excel中的列号=标签中数字=Map中的key。
template.process方法没有解析Integer类型的key,因此将标签修改为${m数字}
XlsUtil代码:
package excel2word.utils;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
public class XlsUtil {
public static Map<String, Object> extractRow(Row row){
//默认第一行为生成文件名,所以不能为null
if (null == row || null == row.getCell(0)) {
return null;
}
Map<String, Object> params = new HashMap<String, Object>();
for (int i=0; i<100; i++) {
//key对应列,为空显示为空字段
params.put("m"+(i+1), row.getCell(i)==null?"":row.getCell(i));
}
return params;
}
public static List<Map<String, Object>> extractXls(FileInputStream fis) throws IOException{
List<Map<String, Object>> results = new ArrayList<Map<String,Object>>();
try {
Workbook book = new HSSFWorkbook(fis);
Sheet sheet = book.getSheetAt(0);
for (int i=sheet.getFirstRowNum(); i <= sheet.getLastRowNum(); i++) {
Map<String, Object> param = extractRow(sheet.getRow(i));
results.add(param);
}
} catch (IOException e) {
throw e;
}
return results;
}
}
DocUtil代码:
package excel2word.utils;
import java.io.File;
import excel2word.config.constants.WorkConstant;
import excel2word.config.enumerations.FileType;
public class DocUtil {
public static File create(FileType type, String docName) {
//解决重名问题
int i = 1;
String outPath = WorkConstant.WORK_PATH + docName+type.getLabel();
File doc = new File(outPath);
while (doc.exists()) {
outPath = WorkConstant.WORK_PATH + docName+"("+i+")"+type.getLabel();
doc = new File(outPath);
i++;
}
return doc;
}
}
最后再来看一下main方法,顺序为
创建模板,读取excel数据,遍历数组创建word文件。
MainUtil代码:
package excel2word;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.List;
import java.util.Map;
import excel2word.config.constants.WorkConstant;
import excel2word.config.enumerations.FileType;
import excel2word.template.TemplateManager;
import excel2word.utils.DocUtil;
import excel2word.utils.XlsUtil;
import freemarker.template.Template;
public class MainUtil {
public static void main(String[] args) {
Template template = null;
FileInputStream xlsFin = null;
Writer out = null;
List<Map<String, Object>> xlsList = null;
try {
template = TemplateManager.loading(FileType.XML_TYPE);
xlsFin = new FileInputStream(new File(WorkConstant.WORK_PATH+WorkConstant.TEMPLATE_NAME+FileType.EXCEL_03_TYPE.getLabel()));
xlsList = XlsUtil.extractXls(xlsFin);
for (Map<String, Object> xls : xlsList) {
//默认第一列为doc文件名
File doc = DocUtil.create(FileType.WORD_03_TYPE, xls.get("m1").toString());
out= new BufferedWriter(new OutputStreamWriter(new FileOutputStream(doc),"utf-8"));
template.process(xls, out);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
TemplateManager.destory();
if (null != xlsFin) {
try {
xlsFin.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
xlsFin = null;
}
}
}
}
}
遇到的问题:
字节流导致的word格式错误。
行号作为key的Map<Integer, Object> 不能解析。
constant指定路径方式不灵活。
word文件的标签容易增加一些格式标签。
明天继续改造