转载请注明出处: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&&param.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&&paragraphList.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();
}
}

如果此文对您有帮助,微信打赏我一下吧~

最新文章

  1. vuex 初体验
  2. asp.net mvc bootstrap datatable 服务端分页
  3. 现代程序设计 网页前端开发作业(to 邹欣老师)
  4. What’s the difference between data mining and data warehousing?
  5. 万网云解析设置二级域名解析到同IP不同端口
  6. python tornado框架使用
  7. Oracle 查看表空间剩余与创建空间语法
  8. iOS开发——开发必备OC篇&amp;UITableView设置界面完整封装(三)
  9. C++ 中的“ !” 运算
  10. android88 录音机
  11. 第一个Servlet程序及分析
  12. 在Node.js中使用RabbitMQ系列二 任务队列
  13. spring_02工具及接口案例
  14. python颜色及背景
  15. MySQL open_files_limit相关设置
  16. 【本地服务器】利用openssl生成证书
  17. C#调用非托管dll
  18. Linux 系统级别优化_【all】
  19. AVAudioFoundation(3):音视频编辑
  20. HashMap源代码解析

热门文章

  1. 【.net 深呼吸】序列化中的“引用保留”
  2. Markdown 图片助手-MarkdownPicPicker
  3. 关于全局ID,雪花(snowflake)算法的说明
  4. .Net Core MVC 网站开发(Ninesky) 2.3、项目架构调整(续)-使用配置文件动态注入
  5. Java学习之反射机制及应用场景
  6. .Net Core上也可以使用的二维码组件
  7. MySQL 系列(一) 生产标准线上环境安装配置案例及棘手问题解决
  8. 利用注册表在右键添加VS15的快捷方式打开文件夹
  9. 免费道路 bzoj 3624
  10. Js 数组返回去重后的数据