本来是要在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:
先上效果图:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
|
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); } } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
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文档格式了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
|
/** * 自定义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( "测试" ); } } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
|
/** * 适用于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; } } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
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(); } } |
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:http://www.cnblogs.com/Joanna-Yan/p/5280272.html