一、工具类如下
package com.enter.net.util;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
*
* @Author: zhangshizhe
*
* @Date: 2020年05月30日 9:00:33
*
* @Description: 使用模板导出工具类
*
* @Version: 1.0
*
*/
public class ExportFreemakerUtil {
//注:如果使用表格宽度的话,每次添加新表格时需要重新new对象
private List table_widths = new ArrayList<>();//当前表格宽度数组
private static final int SUM_TABLE_WIDTH = 9326;//表格默认总宽度
/**
* 自动计算列宽
* @param num
*/
public ExportFreemakerUtil(Integer num) {
for (int i = 0; i < num; i++) {
table_widths.add(SUM_TABLE_WIDTH / num);
}
}
/**
* 自动计算剩余列宽
* @param num 共几列
* @param widths 需要固定的宽度(key:列数,value:宽度)
*/
public ExportFreemakerUtil(Integer num, Map widths) {
Integer sum = 0;
for (Integer column : widths.keySet()) {
sum += widths.get(column);
}
Integer average = (SUM_TABLE_WIDTH - sum) / num;
for (int i = 0; i < num; i++) {
Integer integer = widths.get(i);
if (integer == null) {//添加平均数
table_widths.add(average);
}else {//添加手动的
table_widths.add(integer);
}
}
}
/**
* 没有宽度,加载段落使用,不能加载表格
*/
public ExportFreemakerUtil() {
}
/**
*
* @Author zhangshizhe
* @Date 2020年05月30日 9:06:03
* @Description 获取表格的开始(需手动传宽度)
* @Fcunction getTableStart
* @return String
*
*/
public String getTableStart(){
//表格固定开始
String str =
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" ";
//表格宽度设置
str += " ";
for (Integer width : table_widths) {
str += " ";
}
str += " ";
return str;
}
/**
*
* @Author zhangshizhe
* @Date 2020年05月30日 9:06:03
* @Description 获取表格的结束
* @Fcunction getTableEnd
* @return String
*
*/
public String getTableEnd(){
//表格固定结束
String str =" ";
return str;
}
/**
*
* @Author zhangshizhe
* @Date 2020年05月30日 9:06:03
* @Description 获取表格的每一行的开始
* @Fcunction getTableRowStart
* @return String
*
*/
public String getTableRowStart(){
return " \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" ";
}
/**
*
* @Author zhangshizhe
* @Date 2020年05月30日 9:06:03
* @Description 获取表格的每一行的结束
* @Fcunction getTableRowEnd
* @return String
*
*/
public String getTableRowEnd(){
return " ";
}
/**
*
* @Author zhangshizhe
* @Date 2020年05月30日 9:06:03
* @Description 获取每一列
* @Fcunction getColumn
* @param str
* @param count 第几列
* @return String
*
*/
public String getColumn(String str,Integer count){
return " \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" " + str + " \n" +
" \n" +
" \n" +
" ";
}
/**
*
* @Author zhangshizhe
* @Date 2020年05月30日 9:06:03
* @Description 获取列合并的列
* @Fcunction getMergeColumn
* @param str 文字
* @param num 合并几列
* @param count 第几列
* @return String
*
*/
public String getMergeColumn(String str,Integer num,Integer count){
Integer sum = 0;
for (int i = count; i < count + num; i++) {
if (i < table_widths.size()) {
sum += table_widths.get(i);
}
}
return " \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" " + str + " \n" +
" \n" +
" \n" +
" ";
}
/**
*
* @Author zhangshizhe
* @Date 2020年05月30日 9:06:03
* @Description 获取行合并的列(合并起始列)
* @Fcunction getMergeRowColumnStart
* @param str
* @param count 第几列
* @return String
*
*/
public String getMergeRowColumnStart(String str,Integer count){
return " \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" " + str + " \n" +
" \n" +
" \n" +
" ";
}
/**
*
* @Author zhangshizhe
* @Date 2020年05月30日 9:06:03
* @Description 获取行合并的列(合并结束列)
* @Fcunction getMergeRowColumnEnd
* @param count 第几列
* @return String
*
*/
public String getMergeRowColumnEnd(Integer count){
return " \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" ";
}
/**
*
* @Author zhangshizhe
* @Date 2020年05月30日 9:06:03
* @Description 获取空行
* @Fcunction getBlankParagraph
* @return String
*
*/
public String getBlankParagraph(){
return "\n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" ";
}
/**
*
* @Author zhangshizhe
* @Date 2020年05月30日 9:16:03
* @Description 获取word的段落
* @Fcunction getParagraph
* @param str 内容
* @param type 字体
* @return String
*
*/
public String getParagraph(String str,String type){
return "\n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" " + str + " \n" +
" \n" +
" ";
}
}
二、使用方法如下
public static void main(String[] args) {
//造数据--表头第一行第二行
Map head_map = new HashMap<>();
head_map.put("111","测试1");
head_map.put("222","测试2");
head_map.put("222","测试3");
Map head_type_map = new HashMap<>();//指标id对应类型(系统、人工)
head_map.put("111","0");
head_map.put("222","0");
head_map.put("222","1");
Map norm_calculation_map = new HashMap<>();//0系统计算,1人工录入
norm_calculation_map.put("0", new String[]{"月度计划","月度完成","超欠","增减分"});
norm_calculation_map.put("1", new String[]{"完成情况","增减分"});
//造数据--内容
List> rows = new ArrayList<>();
for (int i = 0; i < 3; i++) {//造三行数据
List row = new ArrayList<>();
row.add(i+1+"");//第一列序号
for (int j = 0; j < 11; j++) {//因为表头造的数据是12列,所以内容也造12列
row.add(j+"");
}
rows.add(row);
}
//造数据--段落
String txt = "测试段落";
//调用方法
String str = "";//导出中心内容
Map widths = new HashMap<>();//设置第一列第二列的宽度
widths.put(0, 695);
widths.put(1, 1418);
//使用工具类
ExportFreemakerUtil util = new ExportFreemakerUtil(rows.get(0).size(), widths);
//加载段落
str += new ExportFreemakerUtil().getParagraph(txt,"黑体");
//第一行
str = getTableRowOne(str, util, head_map, head_type_map, norm_calculation_map);
//第二行
str = getTableRowTwo(str, util, head_map, head_type_map, norm_calculation_map);
//内容
str = getTableRowContent(str, util, rows);
str += util.getTableEnd();//表格结束
str += util.getBlankParagraph();//添加空行
//把数据放到map中
Map map = new HashMap<>();
map.put("content", str);
map.put("org_main_name", "user1");
map.put("month_", "2020-06");
map.put("depar_head", "user2");
map.put("name_input_user", "user3");
map.put("contact", "11111");
map.put("input_time", "2020-05-31");
OutputStream outputStream = response.getOutputStream();//导出的话response是HttpServletResponse,从Controller传过来
WordGenerator.createDoc(map, "doc_table.ftl", outputStream);
}
/**
* 表头第二行
* @param str
* @param util
* @param head_map
* @param head_type_map
* @param norm_calculation_map
* @return
*/
private String getTableRowTwo(String str, ExportFreemakerUtil util, Map head_map, Map head_type_map, Map norm_calculation_map) {
Integer count;
count = -1;//计列
str += util.getTableRowStart();//行开始
count++;
str += util.getMergeRowColumnEnd(count);//第一行第一列
count++;
str += util.getMergeRowColumnEnd(count);//第一行第二列
for (String key : head_map.keySet()) {
String[] strings = norm_calculation_map.get(head_type_map.get(key));
for (String string : strings) {
count++;
str += util.getColumn(string, count);
}
}
str += util.getTableRowEnd();//行结束
return str;
}
/**
* 表头第一行
* @param str
* @param util
* @param head_map
* @param head_type_map
* @param norm_calculation_map
* @return
*/
private String getTableRowOne(String str, ExportFreemakerUtil util, Map head_map, Map head_type_map, Map norm_calculation_map) {
Integer count = -1;//计列
str += util.getTableRowStart();//行开始
count++;
str += util.getMergeRowColumnStart("序号", count);//第一行第一列
count++;
str += util.getMergeRowColumnStart("单位名称", count);//第一行第二列
for (String key : head_map.keySet()) {
count++;
String[] strings = norm_calculation_map.get(head_type_map.get(key));
int length = strings.length;
str += util.getMergeColumn(head_map.get(key), length, count);
count += length - 1;
}
str += util.getTableRowEnd();//行结束
return str;
}
/**
* 行内容
* @param str
* @param util
* @param rows
* @return
*/
private String getTableRowContent(String str, ExportFreemakerUtil util, List> rows) {
for (List row : rows) {//每一行
Integer count = -1;//计列
str += util.getTableRowStart();//行开始
for (String value : row) {//每一列
count++;
str += util.getColumn(value, count);//行结束
}
str += util.getTableRowEnd();//行结束
}
return str;
}
/**
* 模板动态替换
* @param dataMap
* @param templateName
* @param output
* @return
*/
public void createDoc(Map, ?> dataMap,String templateName,OutputStream output) throws TemplateException, IOException {
//创建配置实例
Configuration configuration = new Configuration(Configuration.VERSION_2_3_23);
//设置编码
configuration.setDefaultEncoding("UTF-8");
//空值
configuration.setClassicCompatible(true);
//ftl模板文件统一放至 com.fh.template 包下面
configuration.setClassForTemplateLoading(WordGenerator.class,"/templates/");
//获取模板
Template template = configuration.getTemplate(templateName);
//将模板和数据模型合并生成文件
Writer out = new BufferedWriter(new OutputStreamWriter(output,"UTF-8"));
//这个地方不能使用FileWriter因为需要指定编码类型否则生成的Word文档会因为有无法识别的编码而无法打开
// Writer w = new OutputStreamWriter(new FileOutputStream(f), "utf-8");
//生成文件
template.process(dataMap, out);
//关闭流
out.flush();
out.close();
}
三、doc_table.ftl模板如下,具体怎么生成模板可以参考java使用freemarker模板导出word,合并单元格,单元格内换行
tlj
dell
2
0
2020-05-19T02:05:00Z
2020-05-19T02:05:00Z
1
52
302
Microsoft
2
1
353
14
2052-11.1.0.9513
所属单位月度组织绩效考核生产经营指标完成情况
提供部门:${org_main_name}(公章)
<#-- -->
考核月份:
${month_}
${content}
部门负责人:
${depar_head}
填表人:
${name_input_user}
电话:
${contact}
${input_time}
PAGE \* MERGEFORMAT
1
四、效果如下
五、xml标签的官方文档:http://officeopenxml.com/WPtableProperties.php