Java自动生成word文档,用心看这篇就够了重点

Posted sunnyday0426

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java自动生成word文档,用心看这篇就够了重点相关的知识,希望对你有一定的参考价值。

1.1 概述

在网上找了好多天将数据库中信息导出到word中的解决方案,现在将这几天的总结分享一下。总的来说,Java导出word大致有5种解决方案比较。

1.2 方案比较

1、JacobJava-COM Bridge的缩写,它在Java与微软的COM组件之间构建一座桥梁。通过Jacob实现了在Java平台上对微软OfficeCOM接口进行调用。

优点:调用微软OfficeCOM接口,生成的word文件格式规范。

缺点:服务器只能是windows平台,不支持unixlinux,且服务器上必须安装微软Office

2、Apache POI包括一系列的API,它们可以操作基于MicroSoft OLE 2 Compound Document Format的各种格式文件,可以通过这些APIJava中读写ExcelWord等文件。

优点:跨平台支持windowsunixlinux

缺点:相对与对word文件的处理来说,POI更适合excel处理,对于word实现一些简单文件的操作凑合,不能设置样式且生成的word文件格式不够规范。

3、Java2word是一个在Java程序中调用 MS Office Word文档的组件(类库)。该组件提供了一组简单的接口,以便Java程序调用他的服务操作Word文档。 这些服务包括: 打开文档、新建文档、查找文字、替换文字,插入文字、插入图片、插入表格,在书签处插入文字、插入图片、插入表格等。

优点:足够简单,操作起来要比FreeMarker简单的多。

缺点:没有FreeMarker强大,不能够根据模版生成Word文档,word的文档的样式等信息都不能够很好的操作。

4、FreeMarker生成word文档的功能是由XML+FreeMarker来实现的。先把word文件另存为xml,在xml文件中插入特殊的字符串占位符,将xml翻译为FreeMarker模板,最后用Java来解析FreeMarker模板,编码调用FreeMarker实现文本替换并输出Doc

优点:比Java2word功能强大,也是纯Java编程。

缺点:生成的文件本质上是xml,不是真正的word文件格式,有很多常用的word格式无法处理或表现怪异,比如:超链、换行、乱码、部分生成的文件打不开等。

5、PageOffice生成word文件。PageOffice封装了微软Office繁琐的vba接口,提供了简洁易用的Java编程对象,支持生成word文件,同时实现了在线编辑word文档和读取word文档内容。

优点:跨平台支持windows、unixlinux,生成word文件格式标准,支持文本、图片、表格、字体、段落、颜色、超链、页眉等各种格式的操作,支持多word合并,无需处理并发,不耗费服务器资源,运行稳定。

缺点:必须在客户端生成文件(可以不显示界面),不支持纯服务器端生成文件。

1.3 Apache POI

1.3.1 参考一

1、poiword文档结构介绍之正文段落

一个文档包含多个段落,一个段落包含多个Runs,一个Runs包含多个RunRun是文档的最小单元

获取所有段落:List<XWPFParagraph> paragraphs = word.getParagraphs();

获取一个段落中的所有RunsList<XWPFRun> xwpfRuns = xwpfParagraph.getRuns();

获取一个Runs中的一个RunXWPFRun run = xwpfRuns.get(index);

2、poi之word文档结构介绍之正文表格

一个文档包含多个表格,一个表格包含多行,一行包含多列(格),每一格的内容相当于一个完整的文档

获取所有表格:List<XWPFTable> xwpfTables = doc.getTables();

获取一个表格中的所有行:List<XWPFTableRow> xwpfTableRows = xwpfTable.getRows();

获取一行中的所有列:List<XWPFTableCell> xwpfTableCells = xwpfTableRow.getTableCells();

获取一格里的内容:List<XWPFParagraph> paragraphs = xwpfTableCell.getParagraphs();

之后和正文段落一样

注:

  • 表格的一格相当于一个完整的docx文档,只是没有页眉和页脚。里面可以有表格,使用xwpfTableCell.getTables()获取等等,
  • poi文档中段落和表格是完全分开的,如果在两个段落中有一个表格,在poi中是没办法确定表格在段落中间的。只有文档的格式固定,才能正确的得到文档的结构。

3、poi之word文档结构介绍之页眉:

一个文档可以有多个页眉,页眉里面可以包含段落和表格

获取文档的页眉:List<XWPFHeader> headerList = doc.getHeaderList();

获取页眉里的所有段落:List<XWPFParagraph> paras = header.getParagraphs();

获取页眉里的所有表格:List<XWPFTable> tables = header.getTables();

4、poi之word文档结构介绍之页脚

页脚和页眉基本类似,可以获取表示页数的角标

1.3.2 参考二

(1) POI操作Word简介
POI读写Excel功能强大、操作简单。但是POI操作时,一般只用它读取word文档,POI只能能够创建简单的word文档,相对而言POI操作时的功能太少。

(2) POI创建Word文档的简单示例

XWPFDocument doc = new XWPFDocument();// 创建Word文件
XWPFParagraph p = doc.createParagraph();// 新建一个段落
p.setAlignment(ParagraphAlignment.CENTER);// 设置段落的对齐方式
p.setBorderBottom(Borders.DOUBLE);//设置下边框
p.setBorderTop(Borders.DOUBLE);//设置上边框
p.setBorderRight(Borders.DOUBLE);//设置右边框
p.setBorderLeft(Borders.DOUBLE);//设置左边框
XWPFRun r = p.createRun();//创建段落文本
r.setText("POI创建的Word段落文本");
r.setBold(true);//设置为粗体
r.setColor("FF0000");//设置颜色
p = doc.createParagraph();// 新建一个段落
r = p.createRun();
r.setText("POI读写Excel功能强大、操作简单。");
XWPFTable table= doc.createTable(3, 3);//创建一个表格
table.getRow(0).getCell(0).setText("表格1");
table.getRow(1).getCell(1).setText("表格2");
table.getRow(2).getCell(2).setText("表格3");
FileOutputStream out = newFileOutputStream("d:\\\\POI\\\\sample.doc");
doc.write(out);
out.close();

(3) POI读取Word文档里的文字

FileInputStream stream = newFileInputStream("d:\\\\POI\\\\sample.doc");
XWPFDocument doc = new XWPFDocument(stream);// 创建Word文件
for(XWPFParagraph p : doc.getParagraphs())//遍历段落

 System.out.print(p.getParagraphText());

for(XWPFTable table : doc.getTables())//遍历表格

 for(XWPFTableRow row : table.getRows())
 
 for(XWPFTableCell cell : row.getTableCells())
 
 System.out.print(cell.getText());
 
 

1.3.4 代码示例

该代码示例只是一个demo,简单的生成了一个word文件,包括word文档常规的一些样式设置,包括设置文件字体、首行缩进、设置文字大小,段落的对齐方式,换行。还有常见的表格的创建,以及表格的合并效果等等。

直接看效果图:

public void createFile(HttpServletRequest request, HttpServletResponse response) throws IOException 
        //创建文本对象
        XWPFDocument docxDocument = new XWPFDocument();
        //创建第一段落
        XWPFParagraph firstParagraphX = docxDocument.createParagraph();
        firstParagraphX.setAlignment(ParagraphAlignment.CENTER);

        XWPFRun runTitle = firstParagraphX.createRun();
        runTitle.setText("医院报告申请");
        runTitle.setBold(true);
        runTitle.setFontSize(24);
        runTitle.setFontFamily("宋体");
        runTitle.addCarriageReturn();//回车键
        runTitle.setKerning(30);

        XWPFParagraph paragraphX = docxDocument.createParagraph();

        paragraphX.setAlignment(ParagraphAlignment.LEFT);//对齐方式
        paragraphX.setFirstLineIndent(400);//首行缩进
        //创建段落中的run
        XWPFRun run = paragraphX.createRun();
        run.setText("开始新的额一页了健康卡离开了危,机容量为金融界王仁君我快速建房可谓集,有分页吗,按时交付问我问问");
        //run.addCarriageReturn();//回车键

        XWPFRun run2 = paragraphX.createRun();
        run2.setText("这是第二段了吧,接口了就废了我今儿来将危及,不知道嗯么回事了了,啦啦啦啦啦啦啦");
        run2.setText("这个不是能分段吗,测试一下试试");
        run2.setBold(true);//加粗

        //创建第二段落
        XWPFParagraph paragraphX2 = docxDocument.createParagraph();
        paragraphX2.setIndentationFirstLine(420);//首行缩进
        XWPFRun secondRun = paragraphX2.createRun();
        secondRun.setText("第二天的开始,就忙吧尽快立法捡垃圾而");
        secondRun.setColor("FFC0CB");
        secondRun.setUnderline(UnderlinePatterns.SINGLE);
        secondRun.addCarriageReturn();

        //创建表格 4行*5列(创建table 时,会有一个默认一行一列的表格)
       // XWPFTable table =  createTable( docxDocument,4,5);
        XWPFTable table = docxDocument.createTable(4,5);
        table.setWidth("95%");
        table.setWidthType(TableWidthType.PCT);//设置表格相对宽度
        table.setTableAlignment(TableRowAlign.CENTER);

        //合并单元格
        XWPFTableRow row1 = table.getRow(0);
        XWPFTableCell cell1 = row1.getCell(0);
        CTTcPr cellCtPr = getCellCTTcPr(cell1);
        cellCtPr.addNewHMerge().setVal(STMerge.RESTART);

        XWPFTableCell cell2 = row1.getCell(1);
        CTTcPr cellCtPr2 = getCellCTTcPr(cell2);
        cellCtPr2.addNewHMerge().setVal(STMerge.CONTINUE);

        //给表格填充文本
        setTableText(docxDocument);


        XWPFParagraph endParagraphX = docxDocument.createParagraph();
        endParagraphX.setAlignment(ParagraphAlignment.RIGHT);

        XWPFRun endRun = endParagraphX.createRun();
        endRun.setText("2021年11月18日");

        String path="F://home//docBoke.docx";
        File file = new File(path);
        FileOutputStream stream = new FileOutputStream(file);
        docxDocument.write(stream);
        stream.close();
        System.out.println("文件生成完成!");
    

    private void setTableText(XWPFDocument docxDocument) 
        //获取第一个表格
        XWPFTable table = docxDocument.getTableArray(0);
        List<XWPFTableRow> rows = table.getRows();
        int i=1;
        for(XWPFTableRow row :rows)
            List<XWPFTableCell> cells = row.getTableCells();
            for(XWPFTableCell cell: cells)
                cell.setText("第"+String.valueOf(i++)+"格");
                cell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);
                //cell.setWidthType(TableWidthType.PCT);
                //cell.setWidth("30%");
            
        

    

    public static CTTcPr getCellCTTcPr(XWPFTableCell cell) 
        CTTc cttc = cell.getCTTc();
        CTTcPr tcPr = cttc.isSetTcPr() ? cttc.getTcPr() : cttc.addNewTcPr();
        return tcPr;
    

1.4 FreeMarker

FreeMarker是一个基于Java的模板引擎,最初专注于使用MVC软件架构生成动态网页。但是,它是一个通用的模板引擎,不依赖于servletsHTTPhtml,因此它通常还用于生成源代码,配置文件或电子邮件。
此时,我们用它动态生成xml文件,进而导出word文档。

1.4.1 流程图

1.4.2 代码示例

以前项目常常要导出word文档,我大多时候还是用freemarker的模板来实现,现总结一下关键步骤,供大家参考。

一、模板的制作

先用Word做一个模板,如下图:

(注意,上面是有表格的,我设置了边框不可见)然后另存为XML文件,之后用工具打开这个xml文件,有人用firstobject XML Editor感觉还不如notepad++,我这里用notepad++,主要是有高亮显示,和元素自动配对,效果如下:

上面黑色的地方基本是我们之后要替换的地方,比如xytitle替换为$xytitle,对已表格要十分注意,比如选择题下面的表格,我们可以通过<w:tr>查找来定位,一对<w:tr></w:tr>代表一行,也就是一条记录(一道题),我们这里要用一对<#list></#list>来将其包括,以便后续填充数据,具体可参照Freemarker页面语法,例如这里选择题,我们是两行为一条记录,所以要<#list></#list>要包括两行,形如:<#list table1 as plan1><w:tr>题号 题目</w:tr><w:tr>选项</w:tr></#list>,然后在这其中找着对应的xzn,xztest,ans1,ans2,ans3,ans4替换为$plan1.xzn,$plan1.xztest,$plan1.ans1,$plan1.ans2,$plan1.ans3,$plan1.ans4,注意这里的table1plan1命名,table1后续填充数据要用到,其他的替换同理操作,得到效果如下:

保存后,修改后缀名为ftl,至此模板制作完毕。

二、编程实现

这里用到了freemarker-2.3.13.jar包,代码如下:

package common;
 
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.util.Map;
 
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
 
public class DocumentHandler 
 
	private Configuration configuration = null;
 
	public DocumentHandler() 
		configuration = new Configuration();
		configuration.setDefaultEncoding("utf-8");
	
 
	public void createDoc(Map<String,Object> dataMap,String fileName) throws UnsupportedEncodingException 
		//dataMap 要填入模本的数据文件
		//设置模本装置方法和路径,FreeMarker支持多种模板装载方法。可以重servlet,classpath,数据库装载,
		//这里我们的模板是放在template包下面
		configuration.setClassForTemplateLoading(this.getClass(), "/template");
		Template t=null;
		try 
			//test.ftl为要装载的模板
			t = configuration.getTemplate("fctestpaper.ftl");
		 catch (IOException e) 
			e.printStackTrace();
		
		//输出文档路径及名称
		File outFile = new File(fileName);
		Writer out = null;
		FileOutputStream fos=null;
		try 
			fos = new FileOutputStream(outFile);
			OutputStreamWriter oWriter = new OutputStreamWriter(fos,"UTF-8");
			//这个地方对流的编码不可或缺,使用main()单独调用时,应该可以,但是如果是web请求导出时导出后word文档就会打不开,并且包XML文件错误。主要是编码格式不正确,无法解析。
			//out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile)));
			 out = new BufferedWriter(oWriter); 
		 catch (FileNotFoundException e1) 
			e1.printStackTrace();
		
		 
        try 
			t.process(dataMap, out);
			out.close();
			fos.close();
		 catch (TemplateException e) 
			e.printStackTrace();
		 catch (IOException e) 
			e.printStackTrace();
		
        
        //System.out.println("---------------------------");
	

然后是准备数据调用就行,代码如下:

package com.havenliu.document;
 
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
public class Main 
 
	/**
	 * @param args
	 * @throws UnsupportedEncodingException 
	 */
	public static void main(String[] args) throws UnsupportedEncodingException ;
 
		Map<String, Object> dataMap = new HashMap<String, Object>();
		dataMap.put("xytitle", "试卷");
		int index = 1;
		// 选择题
		List<Map<String, Object>> list1 = new ArrayList<Map<String, Object>>();//题目
		List<Map<String, Object>> list11 = new ArrayList<Map<String, Object>>();//答案
		index = 1;
		for (int i = 0; i < 5; i++) 
 
			Map<String, Object> map = new HashMap<String, Object>();
			map.put("xzn", index + ".");
			map.put("

Java输入输出案例,看这篇就够了!!!

A+B(1)

import java.util.Scanner;

public class Main
    public static void main(String[] args)
        Scanner sc = new Scanner(System.in);
        while(sc.hasNext())
            int a = sc.nextInt();
            int b = sc.nextInt();
            System.out.println(a+b);
        
    

A+B(2)

import java.util.Scanner;

public class Main
    public static void main(String[] args)
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        for(int i = 0; i < n; i++)
            int a = sc.nextInt();
            int b = sc.nextInt();
            System.out.println(a+b);
        
    

A+B(3)

import java.util.Scanner;

public class Main
    public static void main(String[] args)
        Scanner sc = new Scanner(System.in);
        while(sc.hasNext())
            int a = sc.nextInt();
            int b = sc.nextInt();
            if(a == 0 || b == 0)
                return;
            System.out.println(a+b);
        
    

A+B(4)

import java.util.Scanner;

public class Main
    public static void main(String[] args)
        Scanner sc = new Scanner(System.in);
        while(!sc.hasNext("0"))
            int count = sc.nextInt();
            int sum = 0;
            for(int i =0;i < count;i++)
                sum += sc.nextInt();
            
            System.out.println(sum);
        
    

A+B(5)

import java.util.Scanner;

public class Main
    public static void main(String[] args)
        Scanner sc = new Scanner(System.in);
        int row = sc.nextInt();
        for(int i = 0 ; i < row; i++)
            int count = sc.nextInt();
            int sum = 0;
            for(int j =0;j < count;j++)
                sum += sc.nextInt();
            
            System.out.println(sum);
        
    

A+B(6)

import java.util.Scanner;

public class Main
    public static void main(String[] args)
        Scanner in = new Scanner(System.in);
         
        // 注意 hasNext 和 hasNextLine 的区别
        while (in.hasNextLine())  // 注意 while 处理多个 case
           
          String[] s1=in.nextLine().split(" ");
          int sum =-Integer.parseInt(s1[0]);
          for(String st:s1)
              if(Integer.parseInt(st)==0) return;
              sum+=Integer.parseInt(st);
          
          System.out.println(sum);
        
    

A+B(7)

import java.util.*;
 
public class Main
    public static void main(String[]args)
        Scanner sc = new Scanner(System.in);
        while(sc.hasNext())
            String[] str = sc.nextLine().split(" ");
            int sum = 0;
            for(String i:str)
                sum += Integer.parseInt(i);
            
            System.out.println(sum);
        
    

字符串排序(1)

import java.util.*;
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main 
    public static void main(String[] args)
        Scanner in = new Scanner(System.in);
        while(in.hasNextLine())
            int num =Integer.valueOf(in.nextLine());
            String strings=in.nextLine();
            String[] stringAll = strings.split(" ");
            Arrays.sort(stringAll);
            for(String s1:stringAll)
                System.out.print(s1+" ");
            
        
        System.out.println();
    

字符串排序(2)

import java.util.*;
import java.util.Scanner;
public class Main
    public static void main(String[] args)
        Scanner sc = new Scanner(System.in);
        while(sc.hasNextLine())
            String[] line = sc.nextLine().split(" ");
            Arrays.sort(line);
            for(String li : line)
                System.out.print(li+" ");
            
            System.out.println("");
        
    

字符串排序(3)

import java.util.*;

public class Main 
    public static void main(String[] args) 
        Scanner sn = new Scanner(System.in);
        while (sn.hasNext())
            String inputS = sn.next();
            String[] inputSList = inputS.split(",");
            Arrays.sort(inputSList);

            for (int i = 0; i<inputSList.length;i++)
                if (i==inputSList.length - 1) 
                    System.out.println(inputSList[i]);
                    break;
                
                else 
                    System.out.print(inputSList[i] + ",");
                
            
        
    

自测本地通过提交为0

import java.util.*;
 
public class Main
    public static void main(String[] args)
        Scanner sc=new Scanner(System.in);
        while(sc.hasNext())
            long a=sc.nextLong();
            long  b=sc.nextLong();
             System.out.println(a+b);
            
    

以上是关于Java自动生成word文档,用心看这篇就够了重点的主要内容,如果未能解决你的问题,请参考以下文章

[Asp.Net Core]ASP.NET Core WebApi使用Swagger生成api说明文档看这篇就够了

[转帖]Zookeeper入门看这篇就够了

Java输入输出案例,看这篇就够了!!!

Java输入输出案例,看这篇就够了!!!

Java输入输出案例,看这篇就够了!!!

Java输入输出案例,看这篇就够了!!!