java动态生成word以及下载到本地或者浏览器下载
- 我选择的是freemaker
- word操作
- 具体代码
- ftl文件结构
我选择的是freemaker
首先看一下图:
经过多重查找和对比,最终选择了xml这种模板形式。其实可能poi大家会更熟悉一些,但是它缺点是样式需要通过代码去一行一行写,这样写出来,复杂程度太高,而且样式还不好看。
word操作
将对应的文字用占位符(${})来替代
下面这个图大家要仔细看,下面是个动态的表格。就是这个 ${three}-> ${four} -> 列表是根据数据库有多少数据动态生成的
打开word,点击文件wps文字----》另存为—》保存为xml格式
最后将xml文件直接修改为ftl后缀
将文件放入项目中,如下图(其实这个ftl放的位置以及读取方法有三种,下面会一一介绍)
具体代码
@Override
public Result generateWord(int type, String code, HttpServletResponse resp) {
List<Engineering> engineeringList=new ArrayList<>();
Result result=new Result();
Map<String,Object> data=new HashMap<>();
String change;
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
if (type==1){
Inventory inventory=this.wordgenerateMapper.selectInByCode(code);
if (inventory==null){
result.setState("0");
result.setMessage("没有对应清册");
result = Result.ERROR();
return result;
}
data.put("one",inventory.getName());
data.put("two",format.format(inventory.getCreateDate()));
change="清册编码为"+code+"的主要设备材料表";
//清册工程下所有对应id所有数据
engineeringList=this.wordgenerateMapper.selectEngAllByIn(code);
for (int i=0;i<engineeringList.size();i++){
Engineering tempEn=engineeringList.get(i);
List<Inventory> inventoryList=this.wordgenerateMapper.selectInvAll(tempEn);
engineeringList.get(i).setInventoryList(inventoryList);
for (int j=0;j<inventoryList.size();j++){
Inventory tempIn=inventoryList.get(i);
List<Material> materialList=this.wordgenerateMapper.selectMatAll(tempIn.getId());
inventoryList.get(i).setMaterialList(materialList);
}
}
}else if (type==2){
Engineering engineering=this.wordgenerateMapper.selectEnByCode(code);
if (engineering==null){
result.setState("0");
result.setMessage("没有对应工程");
result = Result.ERROR();
return result;
}
data.put("one",engineering.getName());
data.put("two",format.format(engineering.getCreateDate()));
change="工程编码为"+code+"的主要设备材料表";
//工程下所有对应id所有数据
engineeringList=this.wordgenerateMapper.selectEngAll(code);
for (int i=0;i<engineeringList.size();i++){
Engineering tempEn=engineeringList.get(i);
List<Inventory> inventoryList=this.wordgenerateMapper.selectInvAll(tempEn);
engineeringList.get(i).setInventoryList(inventoryList);
for (int j=0;j<inventoryList.size();j++){
Inventory tempIn=inventoryList.get(i);
List<Material> materialList=this.wordgenerateMapper.selectMatAll(tempIn.getId());
inventoryList.get(i).setMaterialList(materialList);
}
}
}else{
Project project=this.wordgenerateMapper.selectPrByCode(code);
if (project==null){
result.setState("0");
result.setMessage("没有对应项目");
result = Result.ERROR();
return result;
}
/**
*这两个data里面put的one和two值用来替换到模板中${one},${two的位置}
*/
data.put("one",project.getName());
data.put("two",format.format(project.getCreateDate()));
change="项目编码为"+code+"的主要设备材料表";
//项目对应工程下所有对应id所有数据
engineeringList=this.wordgenerateMapper.selectEngAllByProject(code);
for (int i=0;i<engineeringList.size();i++){
Engineering tempEn=engineeringList.get(i);
Inventory tempdata=new Inventory();
tempdata.setId(code);
tempdata.setEngineeringId(tempEn.getId());
tempdata.setEngineeringCode(tempEn.getCode());
tempdata.setEngineeringName(tempEn.getName());
List<Inventory> inventoryList=this.wordgenerateMapper.selectInvAllByOnly(tempdata);
engineeringList.get(i).setInventoryList(inventoryList);
for (int j=0;j<inventoryList.size();j++){
Inventory tempIn=inventoryList.get(i);
List<Material> materialList=this.wordgenerateMapper.selectMatAll(tempIn.getId());
inventoryList.get(i).setMaterialList(materialList);
}
}
}
/**
*这个ontdata就是ftl第一个list中的集合数据
*/
data.put("onedata",engineeringList);
//configuration.setClassForTemplateLoading(UserServiceImpl.class, "/templates"); // FTL文件所存在的位置
//configuration.setServletContextForTemplateLoading(ClassLoader.getSystemClassLoader(),"/templates");
/**
*下面这个是从resource下读取文件,里面/templates代表 resource下的templates文件夹下的文件
*/ configuration.setClassLoaderForTemplateLoading(ClassLoader.getSystemClassLoader(),"/templates");
try {
/**
*下面这个是去对应路径下找到code22.ftl模板文件
*/
template = configuration.getTemplate("code22.ftl");
Writer out=null;
String urlTest1=URLEncoder.encode(change, "UTF-8");
//定义下载的类型,标明是word文件(这种是浏览器下载的方式)
resp.setContentType("APPLICATION/OCTET-STREAM");
/**
*URLEncoder.encode是中文解码用的(防止乱码)
*/
resp.setHeader("Content-Disposition", "attachment;filename="+ URLEncoder.encode(change, "UTF-8")+ ".doc");
/**
*下面注释的是下载到本地对应盘符的方式
*/
// File outFile = new File(tempDir+ change+".docx");
// File outFile = new File("D:/Config/"+ change+".docx");
// out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile),"UTF-8"));
out = new BufferedWriter(new OutputStreamWriter(resp.getOutputStream(),"UTF-8"));
/**
*template.process这个是模板的核心,将你需要替换的值data(Map类型)和out(Writer字符输出流)出入进去
*/
template.process(data, out);
out.close();
} catch (Exception e) {
e.printStackTrace();
}
result.setState("1");
result.setMessage("生成成功");
result = Result.SUCCESS();
return result;
}
ftl文件结构
占位符 ${one}、 ${two}的位置,跟之前修改word位置那里是对应的
下面是动态生成数据以及标题的地方
上面图我嵌套了3层list循环(顺序就好像这个线的顺序 红-》黄-》绿)
补充:关于list或者数据为空的情况怎么解决
数据为空
集合为空