Java多种方式动态生成doc文档
转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/5280272.html
本来是要在Android端生成doc的(这需求...),最后方法没有好的方法能够在Android上做到完美,最后还是只能搬迁到服务器。不浪费,还是记录下各框架不支持Android的原因以及他们的特点。Java相关的这类框架还是很多的,有几个还不错,可惜要么不支持Android,要么要收费还价格不低。
经过亲自测试,Android不支持Java的awt很多包不能直接在Android上用,FreeMarker挺不错的,能生成复杂漂亮的doc,可惜不支持Android。用POI在Android上能运行,但是一路因为版本,格式等走了很多坑,用WFS打开还是乱码。Jword、Aspose.word能完美支持,Jword试用期只有30天两者收费都不菲。itext没有测试,不过听说也不支持Android。
方法一:freemarker
该方法需要先手动创建一个doc模板(图片记得使用占位符),并保存为xml文件。通过动态替换特定标签${}中的内容生成。example:
先上效果图:
public class DocUtil {
public Configuration configure=null; public DocUtil(){
configure=new Configuration(Configuration.VERSION_2_3_22);
configure.setDefaultEncoding("utf-8");
}
/**
* 根据Doc模板生成word文件
* @param dataMap 需要填入模板的数据
* @param downloadType 文件名称
* @param savePath 保存路径
*/
public void createDoc(Map<String,Object> dataMap,String downloadType,String savePath){
try {
//加载需要装填的模板
Template template=null;
//设置模板装置方法和路径,FreeMarker支持多种模板装载方法。可以重servlet,classpath,数据库装载。
//加载模板文件,放在testDoc下
configure.setClassForTemplateLoading(this.getClass(), "/testDoc");
//设置对象包装器
// configure.setObjectWrapper(new DefaultObjectWrapper());
//设置异常处理器
configure.setTemplateExceptionHandler(TemplateExceptionHandler.IGNORE_HANDLER);
//定义Template对象,注意模板类型名字与downloadType要一致
template=configure.getTemplate(downloadType+".xml");
File outFile=new File(savePath);
Writer out=null;
out=new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "utf-8"));
template.process(dataMap, out);
out.close();
} catch (IOException e) {
e.printStackTrace();
} catch (TemplateException e) {
e.printStackTrace();
}
} public String getImageStr(String imgFile){
InputStream in=null;
byte[] data=null;
try {
in=new FileInputStream(imgFile);
data=new byte[in.available()];
in.read(data);
in.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
BASE64Encoder encoder=new BASE64Encoder();
return encoder.encode(data);
}
}
public class TestDoc {
public static void main(String[] args) {
DocUtil docUtil=new DocUtil();
Map<String, Object> dataMap=new HashMap<String, Object>();
dataMap.put("name", "Joanna");
dataMap.put("examNum", "111111111111");
dataMap.put("IDCard", "222222222222222222");
dataMap.put("carModel", "C1");
dataMap.put("drivingSchool", "测试驾校");
dataMap.put("busyType", "初次申领");
dataMap.put("examDate", "2016-03-10");
dataMap.put("orderCount", "第1次");
dataMap.put("userImg1", docUtil.getImageStr("D:\\Img\\userImg1.png"));
dataMap.put("userImg2", docUtil.getImageStr("D:\\Img\\userImg2.png"));
dataMap.put("firstExamTime", "12:41:17-12:44:38");
dataMap.put("firstExamScores", "0分,不及格");
dataMap.put("firstDeductItem", "12:44:15 20102 1号倒车入库,车身出线 扣100分");
dataMap.put("firstPic1", docUtil.getImageStr("D:\\Img\\firstPic1.png"));
dataMap.put("firstPic2", docUtil.getImageStr("D:\\Img\\firstPic2.png"));
dataMap.put("firstPic3", docUtil.getImageStr("D:\\Img\\firstPic3.png"));
dataMap.put("secondExamTime", "12:46:50-13:05:37");
dataMap.put("secondExamScores", "90分,通过");
dataMap.put("secondDeductItem", "");
dataMap.put("secondPic1", docUtil.getImageStr("D:\\Img\\secondPic1.png"));
dataMap.put("secondPic2", docUtil.getImageStr("D:\\Img\\secondPic2.png"));
dataMap.put("secondPic3", docUtil.getImageStr("D:\\Img\\secondPic3.png"));
docUtil.createDoc(dataMap, "baseDoc", "D:\\yanqiong.doc");
}
}
xml文件太长,就不贴了...
最后附上Android不能使用的原因:http://stackoverflow.com/questions/25929542/use-freemarker-library-in-android
补充关于动态显示list以及换行的问题
需求明确到:在上面的扣分项中,如果我有几条扣分项,我希望每显示一条换行。
直接在要显示的内容上加换行符,并没有什么效果,起不到换行的作用。
其中在加ftl标签时,如<#list></list>,就会出现一些问题,在xml中并不识别,导致项目不能运行。
解决:
在需要显示多条扣分项的位置加,并加换行符:
<#list firstDeductItem as firstItem>
<w:t>${firstItem}</w:t><w:br/>
</#list>
TestDoc.java中改为:
List<String> Strs=new ArrayList<String>();
Strs.add("1111111111111111111");
Strs.add("222222222222222");
Strs.add("333333333333333");
dataMap.put("firstDeductItem", Strs);
DocUtil.java中改为:
//定义Template对象,注意模板类型名字与downloadType要一致
template=configure.getTemplate(downloadType+".ftl");
此时xml文件会报错,当然也不能编译运行项目,需要将.xml文件改为.ftl文件保存。再编译运行,效果图:
方法二:POI
用这个方法遇到了很多版本问题,这里是基于POI3.7+Word2007的,测试能够完美运行。
你需要用Word2007手动生成文档模板(用其他的生成会报错:无法打开文件),并用${}替换需要动态更新的内容,与上面类似,但是不需要你保存为xml文档格式了。
/**
* 自定义XWPFDocument,并重写createPicture()方法
* @author Joanna.Yan
*
*/
public class CustomXWPFDocument extends XWPFDocument{
public CustomXWPFDocument(InputStream in) throws IOException{
super(in);
}
public CustomXWPFDocument(){
super();
}
public CustomXWPFDocument(OPCPackage pkg) throws IOException{
super(pkg);
}
public void createPicture(int id,int width,int height,XWPFParagraph paragraph){
final int EMU=9525;
width *=EMU;
height *=EMU;
String blipId=((POIXMLDocumentPart) getAllPictures().get(id)).getPackageRelationship().getId();
CTInline inline=paragraph.createRun().getCTR().addNewDrawing().addNewInline();
String picXml=""
+ "<a:graphic xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\">"
+ " <a:graphicData uri=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">"
+ " <pic:pic xmlns:pic=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">"
+ " <pic:nvPicPr>" + " <pic:cNvPr id=\""
+ id
+ "\" name=\"Generated\"/>"
+ " <pic:cNvPicPr/>"
+ " </pic:nvPicPr>"
+ " <pic:blipFill>"
+ " <a:blip r:embed=\""
+ blipId
+ "\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\"/>"
+ " <a:stretch>"
+ " <a:fillRect/>"
+ " </a:stretch>"
+ " </pic:blipFill>"
+ " <pic:spPr>"
+ " <a:xfrm>"
+ " <a:off x=\"0\" y=\"0\"/>"
+ " <a:ext cx=\""
+ width
+ "\" cy=\""
+ height
+ "\"/>"
+ " </a:xfrm>"
+ " <a:prstGeom prst=\"rect\">"
+ " <a:avLst/>"
+ " </a:prstGeom>"
+ " </pic:spPr>"
+ " </pic:pic>"
+ " </a:graphicData>" + "</a:graphic>";
inline.addNewGraphic().addNewGraphicData();
XmlToken xmlToken=null;
try {
xmlToken=XmlToken.Factory.parse(picXml);
} catch (XmlException e) {
e.printStackTrace();
}
inline.set(xmlToken);
inline.setDistT(0);
inline.setDistB(0);
inline.setDistL(0);
inline.setDistR(0); CTPositiveSize2D extent=inline.addNewExtent();
extent.setCx(width);
extent.setCy(height); CTNonVisualDrawingProps docPr=inline.addNewDocPr();
docPr.setId(id);
docPr.setName("图片"+id);
docPr.setDescr("测试");
}
}
/**
* 适用于word 2007
* poi版本 3.7
* @author Joanna.Yan
*
*/
public class WordUtil { public static CustomXWPFDocument generateWord(Map<String, Object> param,String template){
CustomXWPFDocument doc=null;
try {
OPCPackage pack=POIXMLDocument.openPackage(template);
doc=new CustomXWPFDocument(pack);
if(param!=null&¶m.size()>0){
//处理段落
List<XWPFParagraph> paragraphList = doc.getParagraphs();
processParagraphs(paragraphList, param, doc);
//处理表格
Iterator<XWPFTable> it = doc.getTablesIterator();
while(it.hasNext()){
XWPFTable table = it.next();
List<XWPFTableRow> rows = table.getRows();
for (XWPFTableRow row : rows) {
List<XWPFTableCell> cells = row.getTableCells();
for (XWPFTableCell cell : cells) {
List<XWPFParagraph> paragraphListTable = cell.getParagraphs();
processParagraphs(paragraphListTable, param, doc);
}
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
return doc;
} /**
* 处理段落
* @param paragraphList
* @param param
* @param doc
*/
public static void processParagraphs(List<XWPFParagraph> paragraphList,Map<String, Object> param,CustomXWPFDocument doc){
if(paragraphList!=null&¶graphList.size()>0){
for (XWPFParagraph paragraph : paragraphList) {
List<XWPFRun> runs=paragraph.getRuns();
for (XWPFRun run : runs) {
String text=run.getText(0);
if(text!=null){
boolean isSetText=false;
for (Entry<String, Object> entry : param.entrySet()) {
String key=entry.getKey();
if(text.indexOf(key)!=-1){
isSetText=true;
Object value=entry.getValue();
if(value instanceof String){//文本替换
text=text.replace(key, value.toString());
}else if(value instanceof Map){//图片替换
text=text.replace(key, "");
Map pic=(Map) value;
int width=Integer.parseInt(pic.get("width").toString());
int height=Integer.parseInt(pic.get("height").toString());
int picType=getPictureType(pic.get("type").toString());
byte[] byteArray = (byte[]) pic.get("content");
ByteArrayInputStream byteInputStream = new ByteArrayInputStream(byteArray);
try {
int ind = doc.addPicture(byteInputStream,picType);
doc.createPicture(ind, width , height,paragraph);
} catch (InvalidFormatException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
if(isSetText){
run.setText(text, 0);
}
}
}
}
}
} /**
* 根据图片类型获取对应的图片类型代码
* @param picType
* @return
*/
public static int getPictureType(String picType){
int res = CustomXWPFDocument.PICTURE_TYPE_PICT;
if(picType!=null){
if(picType.equalsIgnoreCase("png")){
res=CustomXWPFDocument.PICTURE_TYPE_PNG;
}else if(picType.equalsIgnoreCase("dib")){
res = CustomXWPFDocument.PICTURE_TYPE_DIB;
}else if(picType.equalsIgnoreCase("emf")){
res = CustomXWPFDocument.PICTURE_TYPE_EMF;
}else if(picType.equalsIgnoreCase("jpg") || picType.equalsIgnoreCase("jpeg")){
res = CustomXWPFDocument.PICTURE_TYPE_JPEG;
}else if(picType.equalsIgnoreCase("wmf")){
res = CustomXWPFDocument.PICTURE_TYPE_WMF;
}
}
return res;
}
}
public class TestPoi { public static void main(String[] args) throws IOException {
Map<String, Object> param=new HashMap<String, Object>();
param.put("${name}", "Joanna.Yan");
param.put("${examNum}", "000000000001");
param.put("${IDCard}", "111111111111111111");
param.put("${carModel}", "C1");
CustomXWPFDocument doc=WordUtil.generateWord(param, "D:\\joanna.docx");
FileOutputStream fopts = new FileOutputStream("D:\\yan.docx");
doc.write(fopts);
fopts.close();
}
}
如果此文对您有帮助,微信打赏我一下吧~
Java多种方式动态生成doc文档的更多相关文章
- 利用Java动态生成 PDF 文档
利用Java动态生成 PDF 文档,则需要开源的API.首先我们先想象需求,在企业应用中,客户会提出一些复杂的需求,比如会针对具体的业务,构建比较典型的具备文档性质的内容,一般会导出PDF进行存档.那 ...
- C# 动态生成word文档 [C#学习笔记3]关于Main(string[ ] args)中args命令行参数 实现DataTables搜索框查询结果高亮显示 二维码神器QRCoder Asp.net MVC 中 CodeFirst 开发模式实例
C# 动态生成word文档 本文以一个简单的小例子,简述利用C#语言开发word表格相关的知识,仅供学习分享使用,如有不足之处,还请指正. 在工程中引用word的动态库 在项目中,点击项目名称右键-- ...
- IText 中文字体解决方案 生成doc文档
IText生成doc文档需要三个包:iTextAsian.jar,iText-rtf-2.1.4.jar,iText-2.1.4.jar 亲测无误,代码如下: import com.lowagie.t ...
- C#动态生成Word文档并填充数据
C#也能动态生成Word文档并填充数据 http://www.cnblogs.com/qyfan82/archive/2007/09/14/893293.html 引用http://blog.csdn ...
- 使用C#动态生成Word文档/Excel文档的程序测试通过后,部署到IIS服务器上,不能正常使用的问题解决方案
使用C#动态生成Word文档/Excel文档的程序功能调试.测试通过后,部署到服务器上,不能正常使用的问题解决方案: 原因: 可能asp.net程序或iis访问excel组件时权限不够(Ps:Syst ...
- java标识符,关键字,注释及生成Doc文档
# java语法基础 ## 标识符,关键字与注释 ### 标识符 1.类名,变量名,方法名都称为标识符. 2.命名规则:(1):所有的标识符都应该以字母(AZ,或者az)美元符($)或者下划线(_)开 ...
- Java eclipse生成doc文档
这里讲解下eclipse成为doc文档,首先代码: /** * @author szy * @version 1.0 */ package com.founder.sun; class Cat{ pu ...
- JAVA Freemarker + Word 模板 生成 Word 文档 (普通的变量替换,数据的循环,表格数据的循环,以及图片的东替换)
1,最近有个需求,动态生成 Word 文当并供前端下载,网上找了一下,发现基本都是用 word 生成 xml 然后用模板替换变量的方式 1.1,这种方式虽然可行,但是生成的 xml 是在是太乱了,整理 ...
- java基础---->使用Itext生成数据库文档
这里简单的介绍一下使用Itext生成数据库表的文档.于是我们领教了世界是何等凶顽,同时又得知世界也可以变得温存和美好. 生成数据库的文档 一.maven项目需要引入的jar依赖 <depende ...
随机推荐
- canvas与html5实现视频截图功能
这段时间一直在研究canvas,突发奇想想做一个可以截屏视频的功能,然后把图片拉去做表情包,哈哈哈哈哈哈~~ 制作方法: 1.在页面中加载视频 在使用canvas制作这个截图功能时,首先必须保证页面上 ...
- VS2015在创建项目时的一些注意事项
一.下面是在创建一个新的项目是我最常用的,现在对他们一一做一个详细的介绍: 1.Win32控制台应用程序我平时编写小的C/C++程序都用它,它应该是用的最多的. 2.名称和解决方案名称的区别:名称是项 ...
- 设计模式之单例模式(Singleton)
设计模式之单例模式(Singleton) 设计模式是前辈的一些经验总结之后的精髓,学习设计模式可以针对不同的问题给出更加优雅的解答 单例模式可分为俩种:懒汉模式和饿汉模式.俩种模式分别有不同的优势和缺 ...
- Maven搭建SpringMVC+Hibernate项目详解 【转】
前言 今天复习一下SpringMVC+Hibernate的搭建,本来想着将Spring-Security权限控制框架也映入其中的,但是发现内容太多了,Spring-Security的就留在下一篇吧,这 ...
- SVN的使用
- 简历生成平台项目开发-STEP1问卷设计
周五课程结束完后,小组建立QQ群和微信群,着手讨论项目问题.一开始的大概想法:就业信息平台,收集企业招聘信息和就业生资料,提供给学生和企业的校企对接平台.后来发现群里谭卓同学也有个相关的思路,经过商量 ...
- SQL数据类型
1.Character 字符串: 数据类型 描述 存储 char(n) 固定长度的字符串.最多8,000个字符. n varchar(n) 可变长度的字符串.最多8,000个字符. varchar ...
- Linux实战教学笔记05:远程SSH连接服务与基本排错(新手扫盲篇)
第五节 远程SSH连接服务与基本排错 标签(空格分隔):Linux实战教学笔记-陈思齐 第1章 远程连接LInux系统管理 1.1 为什么要远程连接Linux系统 在实际的工作场景中,虚拟机界面或物理 ...
- ubuntu14 安装及卸载vmware
原帖http://blog.sina.com.cn/s/blog_73dac6b50101gp4f.html 适用于ubuntu14和vmware player 12.5
- EQueue 2.3.2版本发布(支持高可用)
前言 前段时间针对EQueue的完善终于告一段落了,实在值得庆祝,自己的付出和坚持总算有了成果.这次新版本主要为EQueue实现了集群功能,基本实现了Broker的高可用.另外还增加了很多实用的功能, ...