Originally, we wanted to generate docs on the Android side (this requires...). In the end, there is no good method that can be perfect on Android, and in the end, we can only move to the server. Don't waste it, but record the reasons why each framework does not support Android and their characteristics. There are still many such frameworks related to Java, and some are not bad, but unfortunately they either do not support Android, or they charge for a fee and have a low price.
After personal testing, many awt packages that do not support Java cannot be used directly on Android. FreeMarker is quite good and can generate complex and beautiful docs, but unfortunately it does not support Android. It can run on Android using POI, but it has gone through many pitfalls along the way due to version, format, etc., and it is still garbled to open with WFS. Jword and Aspose.word can be perfectly supported, and the Jword probation period is only 30 days, both charge for both. Itext has no test, but it is said that it does not support Android.
Method 1: freemarker
This method requires manually creating a doc template (remember to use placeholders for the picture) and saving it as an xml file. Generate by dynamically replacing the content in the specific tag ${}. example:
First, let’s take the renderings:
public class DocUtil { public Configuration configuration=null; public DocUtil(){ configuration=new Configuration(Configuration.VERSION_2_3_22); configure.setDefaultEncoding("utf-8"); } /** * Generate word file based on Doc template* @param dataMap The data that needs to be filled in the template* @param downloadType File name* @param savePath Save path*/ public void createDoc(Map<String,Object> dataMap,String downloadType,String savePath){ try { //Load the template that needs to be loaded Template template=null; //Set the template device method and path, FreeMarker supports multiple template loading methods. You can reload servlet, classpath, and database mount. //Load the template file and place it under testDoc configure.setClassForTemplateLoading(this.getClass(), "/testDoc"); //Set the object wrapper// configure.setObjectWrapper(new DefaultObjectWrapper()); //Set the exception handler configure.setTemplateExceptionHandler(TemplateExceptionHandler.IGNORE_HANDLER); //Define the Template object, note that the template type name should be consistent with the 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", "11111111111111"); dataMap.put("IDCard", "2222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222; dataMap.put("carModel", "C1"); dataMap.put("drivingSchool", "test driving school"); dataMap.put("busyType", "first application"); dataMap.put("examDate", "2016-03-10"); dataMap.put("orderCount", "first time"); 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 points, failed"); dataMap.put("firstDeductItem", "12:44:15 20102 No. 1 reversing into the garage, and 100 points deducted from the body out"); 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 points, pass"); 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"); }} The xml file is too long, so I won't post it...
Finally, the reason why Android cannot be used: http://stackoverflow.com/questions/25929542/use-freemarker-library-in-android
Additional questions about dynamic display of lists and line breaks
The requirement is clear: in the above deduction item, if I have several deduction items, I want each line break to be displayed.
Adding newlines directly to the content to be displayed has no effect and will not function as a newline.
When adding ftl tags, such as <#list></list>, some problems will arise, which are not recognized in the XML, resulting in the project being unable to run.
solve:
Add and add line breaks to the position where multiple deduction items need to be displayed:
<#list firstDeductItem as firstItem>
<w:t>${firstItem}</w:t><w:br/>
</#list>
Change it to:
List<String> Strs=new ArrayList<String>();
Strs.add("111111111111111111");
Strs.add("2222222222222222222222222);
Strs.add("3333333333333");
dataMap.put("firstDeductItem", Strs);
Change it to DocUtil.java:
//Define the Template object, note that the template type name should be consistent with the downloadType
template=configure.getTemplate(downloadType+".ftl"); At this time, the xml file will report an error, and of course, it is impossible to compile and run the project. You need to change the .xml file to .ftl file to save. Then compile and run, renderings:
Method 2: POI
I encountered many version problems using this method. This is based on POI3.7+Word2007, and the test can run perfectly.
You need to manually generate the document template with Word2007 (using other generations will cause an error: the file cannot be opened), and replace the content that needs to be updated dynamically with ${}, similar to the above, but you do not need to save it as an XML document format.
/** * Customize XWPFDocument and override createPicture() method* @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("Image"+id); docPr.setDescr("Test"); }} /** * Suitable for word 2007 * poi version 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){ //Processing paragraph List<XWPFParagraph> paragraphList = doc.getParagraphs(); processParagraphs(paragraphList, param, doc); //Processing table 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; } /** * Process paragraph* @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 replacement text=text.replace(key, value.toString()); }else if(value instanceof Map){//Picture replacement 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); } } } } } } } } /** * Get the corresponding image type code according to the image type* @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}", "00000000000001"); param.put("${IDCard}", "111111111111111111111111111111"); param.put("${carModel}", "C1"); CustomXWPFDocument doc=WordUtil.generateWord(param, "D://joanna.docx"); FileOutputStream fopts = new FileOutputStream("D://yan.docx"); doc.write(fopts); fopts.close(); }}The above is all the content of this article. I hope it will be helpful to everyone's learning and I hope everyone will support Wulin.com more.