精华内容
下载资源
问答
  • 利用python(Win32com)获取word图表数据修改图表信息 起因咸鱼个人问word怎么修改图表信息,想用docx库找不到关于图表的方法。 import time import win32com.client as win32 app = win32.Dispatch('Word....

    利用python获取word图表数据和修改图表信息

    起因咸鱼有个人问word怎么修改图表信息,想用docx库找不到关于图表的方法,这里用了Win32com。

    import time
    import win32com.client as win32
    app = win32.Dispatch('Word.Application')
    app.Visible = 0  # 后台运行
    Document = app.Documents.Open( r"C:\Users\Administrator\Desktop\Doc1.docx")#打开文档
    Document = Document.InlineShapes(1).Chart.ChartData.Workbook.Worksheets("Sheet1")#打开图表关联的excel表格
    time.sleep(2)
    k = Document.Cells(2, 2).Value = 156#修改表格内单元格数据
    

    VBA参考
    Microsoft.Office.Interop.Word
    Microsoft.Office.Interop.Excel

    展开全文
  • 前端报表导出成word文档(含echarts图表

    万次阅读 热门讨论 2018-06-23 22:33:56
    然后又考虑客户可能需要修改报表的一些内容,因此需要导出成word文档解决跨页截断和满足修改报表内容的问题。前期解决方案预研时试过jacob、poi方案,但jacob只能用于windows平台(要引用一个dll文...

    前端报表导出成word文档(含echarts图表)

    一、问题背景:

    前端vue做的各种维度的报表,原来是通过前端整体截屏导出成PDF,但部分报表在遇到跨页时会被截断,客户体验极差。然后又考虑客户可能需要修改报表中的一些内容,因此需要导出成word文档解决跨页截断和满足修改报表内容的问题。前期解决方案预研时试过jacob、poi方案,但jacob只能用于windows平台(要引用一个dll文件),并且jacob和poi都存在样式方面的难题。后来通过其他渠道了解了freemarker,于是通过freemarker的把前端请求的报表数据填充到模板文件,生成word文档(导出功能由后端java实现)

    二、效果图

    首先上一张效果图,由于数据保密性,故前端页面的报表原样就不展示,导出的word文档的效果图和页面报表几乎一样
    效果图

    #三、功能点

    1. 文档标题
    2. 文档标题下方生成日期
    3. 文档总体情况概述
    4. 每个echarts图表的标题、图片、图注
    5. 水印
      #四、解决方案
      利用freemarker将前端传入的json格式数据填充入事先设计好的模板文件并生成word文档
      #五、实现流程
    Created with Raphaël 2.2.0 开始 新建word文档 按照页面报表布局与样式设计文档模板 替换内容为占位符 另存为xml文件 xml模板占位符是否分离 占位符完整 将图表生成的base64编码手动替换成占位符 将文档保存到工程resource/freemarker/template目录 编写代码调用freemarker api生成word文档 访问swagger接口页面测试 下载,打开查看效果 yes no

    #六、实现步骤
    ##1. 设计模板
    按照前端报表展示样式,设计模板,并将模板中需要动态被参数填充的部分使用占位符代替,如标题使用${title},图表标题使用${title_1}、${title_2}、${title_3},图表总结词用${summary_1},${summary_2},${summary_3},以此类推.下图为使用占位符替换之后的word模板
    占位符替换后的模板
    ##2. 另存模板为xml
    上一步设计好模板并替换关键内容为占位符后,需要保存成xml模板文件,然后将xml模板文件中的图片base64编码替换成占位符,例如下面模板片段

     <pkg:part pkg:name="/word/media/image16.png" pkg:contentType="image/png" pkg:compression="store">
            <pkg:binaryData>${base64_11}</pkg:binaryData>
        </pkg:part>
        <pkg:part pkg:name="/word/media/image11.png" pkg:contentType="image/png" pkg:compression="store">
            <pkg:binaryData>${base64_9_1}</pkg:binaryData>
        </pkg:part>
        <pkg:part pkg:name="/word/media/image9.png" pkg:contentType="image/png" pkg:compression="store">
            <pkg:binaryData>${base64_8_2}</pkg:binaryData>
        </pkg:part>
        <pkg:part pkg:name="/word/media/image10.png" pkg:contentType="image/png" pkg:compression="store">
            <pkg:binaryData>${base64_8_3}</pkg:binaryData>
        </pkg:part>
        <pkg:part pkg:name="/word/media/image8.png" pkg:contentType="image/png" pkg:compression="store">
            <pkg:binaryData>${base64_8_1}</pkg:binaryData>
        </pkg:part>
    

    ##3. 新建maven工程
    本人使用的开发工具是Idea 2018.1版本,创建maven项目并创建包名,结构如下:

    export-doc
    └─src
    │  ├─main
    │  │  ├─java
    │  │  │  └─com
    │  │  │      └─zhuxl
    │  │  │          └─exportdoc
    │  │  │              │
    │  │  │              ├─component
    │  │  │              │  └─handler
    │  │  │              │
    │  │  │              ├─configuration
    │  │  │              │
    │  │  │              ├─controller
    │  │  │              │
    │  │  │              ├─entity
    │  │  │              │
    │  │  │              ├─service
    │  │  │              │  │
    │  │  │              │  └─impl
    │  │  │              │
    │  │  │              └─util
    │  │  │
    │  │  └─resources
    │  │
    │  └─test
    │      └─java
    └─pom.xml
    

    ##4. 添加相关依赖

    • 添加spring boot依赖
      本demo项目基于spring boot框架,因此需要添加spring-boot-starter-web依赖,并且创建启动类Application.java
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <version>1.5.13.RELEASE</version>
        <optional>true</optional>
    </dependency>
    
    @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
    public class Application {
        public static void main(String[] args) {
            SpringApplication.run(Application.class, args);
        }
    }
    

    (exclude = {DataSourceAutoConfiguration.class}) 参数表示不自动加载参数连接数据库,因为本demo无数据库连接,仅演示service里调用工具类方法导出word,不需要操作数据库,因此需要添加这个参数,否则启动会报连接数据库异常。

    • 添加swagger依赖
      本demo导出word报表请求参数为json格式,数据量非常大(因为有echarts报表base64编码),请求方式为POST,为了便于测试,因此集成swagger
    <dependency>
        <groupId>com.didispace</groupId>
        <artifactId>spring-boot-starter-swagger</artifactId>
        <version>1.4.1.RELEASE</version>
    </dependency>
    
    • 添加lombok依赖
      demo中请求参数使用lombok注解@Data或@Getter,@Setter,可以不用写请求对象的getter和setter方法,在项目编译阶段会自动生成getter和setter方法。
    <!-- LOMBOK begin -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.16.20</version>
    </dependency>
    <!-- LOMBOK end -->
    
    • 添加fastjson依赖
      demo可能会使用到JSONObject类来设置异常时接口返回的数据
    <!-- FASTJSON begin -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.31</version>
    </dependency>
    <!-- FASTJSON end -->
    
    • 添加freemarker依赖
      该依赖为本次功能实现的核心,主要利用freemarker的api将请求数据构造的map和模板文件作为参数生成word文件,并返回File文件对象,最后使用response的输出流将文件返回
    <!-- FREEMARKER begin -->
    <dependency>
       <groupId>org.freemarker</groupId>
       <artifactId>freemarker</artifactId>
       <version>2.3.28</version>
    </dependency>
    <!-- FREEMARKER end -->
    

    ##5. 创建接口请求参数对象类
    使用java类来接收请求的json数据

    @Data
    @ApiModel(value = "贫困人群报表导出请求对象")
    public class ReportExportWordRequest {
    
        @ApiModelProperty(value = "区域级别", name = "unitLevel")
        private Integer unitLevel;
    
        @ApiModelProperty(value = "区域编码", name = "unitCode")
        private String unitCode;
    
        @ApiModelProperty(value = "报表类型", name = "type", notes = "poverty:贫困人群报告;disable:残疾人群报告;poverty_disable:贫困且残疾人群报告")
        private String type;
    
        @ApiModelProperty(value = "报表标题", name = "title")
        private String title;
    
        @ApiModelProperty(value = "报告水印", name = "watermark")
        private String watermark;
    
        @ApiModelProperty(value = "报表生成日期", name = "date")
        private String date;
    
        @ApiModelProperty(value = "该区域报表描述第一段", name = "description1")
        private String description1;
    
        @ApiModelProperty(value = "该区域报表描述第二段", name = "description2")
        private String description2;
    
        @ApiModelProperty(value = "报表中每个图表的内容列表", name = "reports")
        private List<ReportContentRequest> reports;
    }
    
    @Data
    @ApiModel("单个图表请求对象")
    public class ReportContentRequest {
    
        @ApiModelProperty(value = "报表中排列序号", name = "serial")
        private Integer serial;
    
        @ApiModelProperty(value = "单个图表标题", name = "title")
        private String title;
    
        @ApiModelProperty(value = "单个图表base64编码值", name = "base64")
        private String base64;
    
        @ApiModelProperty(value = "单个图表内容总结", name = "summary")
        private String summary;
    
        @ApiModelProperty(value = "该标题下存在多个报表", name = "children")
    	private List<ReportContentRequest> children;
    }
    

    6. 创建导出word工具类

    该工具类是实现导出word功能的核心类,读取模板文件,格式化请求参数,填充模板生成word文档的功能都在此工具类完成

    public class WordGeneratorUtils {
        private static Configuration configuration = null;
        private static Map<String, Template> allTemplates = null;
    
        private static class FreemarkerTemplate {
            public static final String POVERTY = "poverty";
    
        }
    
        static {
            configuration = new Configuration(Configuration.VERSION_2_3_28);
            configuration.setDefaultEncoding("utf-8");
            configuration.setClassForTemplateLoading(WordGeneratorUtils.class, "/freemarker/template");
            allTemplates = new HashMap();
            try {
                allTemplates.put(FreemarkerTemplate.POVERTY, configuration.getTemplate(FreemarkerTemplate.POVERTY + ".ftl"));
            } catch (IOException e) {
                e.printStackTrace();
                throw new RuntimeException(e);
            }
        }
    
        private WordGeneratorUtils() {
            throw new AssertionError();
        }
    
        public static File createDoc(Map<String, String> dataMap) {
            try {
                String name = dataMap.get("title") + dataMap.get("date") + ".doc";
                File f = new File(name);
                Template t = allTemplates.get(dataMap.get("template"));
                // 这个地方不能使用FileWriter因为需要指定编码类型否则生成的Word文档会因为有无法识别的编码而无法打开
                Writer w = new OutputStreamWriter(new FileOutputStream(f), "utf-8");
                t.process(dataMap, w);
                w.close();
                return f;
            } catch (Exception ex) {
                ex.printStackTrace();
                throw new RuntimeException("生成word文档失败");
            }
        }
    
        public static Map<String, String> parseToMap(ReportExportWordRequest request) {
            Map<String, String> datas = new HashMap(32);
            //主标题
            datas.put("title", request.getTitle());
            datas.put("date", request.getDate());
            datas.put("watermark", request.getWatermark());
            datas.put("description1", request.getDescription1());
            datas.put("description2", request.getDescription2());
    
    
            //遍历设置报表
            List<ReportContentRequest> contents = request.getReports();
            datas.put("template", request.getType());
            for (ReportContentRequest c : contents) {
                if (c.getChildren() == null || c.getChildren().size() == 0) {
                    //无子报表
                    datas.put("title_" + c.getSerial(), c.getTitle());
                    datas.put("base64_" + c.getSerial(), c.getBase64());
                    datas.put("summary_" + c.getSerial(), c.getSummary());
                } else {
                    //有多个子报表
                    datas.put("title_" + c.getSerial(), c.getTitle());
                    for (ReportContentRequest subc : c.getChildren()) {
                        datas.put("title_" + c.getSerial() + "_" + subc.getSerial(), subc.getTitle());
                        datas.put("base64_" + c.getSerial() + "_" + subc.getSerial(), subc.getBase64());
                        datas.put("summary_" + c.getSerial() + "_" + subc.getSerial(), subc.getSummary());
                    }
                }
            }
            return datas;
        }
    }
    

    ##7. 创建业务接口与实现类
    ReportService接口类

    public interface ReportService {
        File exportWord(ReportExportWordRequest exportWordRequest);
    }
    

    ReportServiceImpl实现类

    @Service
    public class ReportServiceImpl implements ReportService {
    
        @Override
        public File exportWord(ReportExportWordRequest exportWordRequest) {
    
            //解析参数
            Map<String, String> datas = WordGeneratorUtils.parseToMap(exportWordRequest);
    
            //导出
            File word = WordGeneratorUtils.createDoc(datas);
            return word;
        }
    }
    

    8. 创建Controller类

    @Slf4j
    @RestController
    @RequestMapping("/api/v1/report")
    public class ReportController {
    
        @Autowired
        private ReportService reportService;
    
    
        @ApiOperation(value = "贫困人群综合分析报告导出word文档", notes = "贫困人群综合分析报告导出word文档")
        @PostMapping("/poverty_export_word.ajax")
        public void povertyExportWord(HttpServletRequest request, HttpServletResponse response,
                                      @Valid @RequestBody ReportExportWordRequest exportWordRequest) {
    
            File file = reportService.exportWord(exportWordRequest);
    
            InputStream fin = null;
            OutputStream out = null;
            try {
                // 调用工具类WordGeneratorUtils的createDoc方法生成Word文档
                fin = new FileInputStream(file);
    
                response.setCharacterEncoding("utf-8");
                response.setContentType("application/msword");
                // 设置浏览器以下载的方式处理该文件
                // 设置文件名编码解决文件名乱码问题
                response.addHeader("Content-Disposition", "attachment;filename=" + new String(file.getName().getBytes(), "iso-8859-1"));
    
                out = response.getOutputStream();
                byte[] buffer = new byte[512];
                int bytesToRead = -1;
                // 通过循环将读入的Word文件的内容输出到浏览器中
                while ((bytesToRead = fin.read(buffer)) != -1) {
                    out.write(buffer, 0, bytesToRead);
                }
            } catch (Exception e) {
                throw new RuntimeException("导出失败", e);
            } finally {
                try {
                    if (fin != null) {
                        fin.close();
                    }
                    if (out != null) {
                        out.close();
                    }
                    if (file != null) {
                        file.delete();
                    }
                } catch (IOException e) {
                    throw new RuntimeException("导出失败", e);
                }
            }
    
        }
    
    }
    

    ##9. 创建spring boot 启动类与yml配置
    启动类在前面已经创建,此处只贴出application.yml基本配置

    server:
      port: 8080
      context-path: /zhuxl
    

    ##10. 创建swagger配置

    @Configuration
    @EnableSwagger2
    public class SwaggerConfiguration {
    
        @Bean
        public Docket api() {
            ParameterBuilder parameterBuilder = new ParameterBuilder();
            parameterBuilder.name("Access-Token")
                    .description("令牌")
                    .modelRef(new ModelRef("string"))
                    .parameterType("header")
                    .required(false)
                    .build();
    
            List<Parameter> parameters = new ArrayList<>();
            parameters.add(parameterBuilder.build());
    
            return new Docket(DocumentationType.SWAGGER_2).select()
                    .apis(RequestHandlerSelectors.any())
                    .paths(PathSelectors.regex("/api/v1/.*"))
                    .build()
                    .globalOperationParameters(parameters)
                    .apiInfo(apiInfo());
        }
    }
    

    11. 运行,访问swagger页面测试

    执行Applicaton类的main方法运行demo,访问swagger接口页面,在本demo中访问地址为:http://localhost:8080/zhuxl/swagger-ui.html

    12. 构造参数测试获得报表word文件

    构造json参数,点击try it out按钮,即可进行测试并将文件下载,由于请求参数中base64编码内容过于复杂,因此贴出的参数中图片base64编码省略

    {
    	"unitLevel":"4",
    	"unitCode":"513429100000",
    	"type":"poverty",
    	"title":"XXXX地区贫困人群总体情况报告",
    	"watermark":"张三13800138000",
    	"date":"2018年6月",
    	"description1":"报告正文开始的第一部分增加对该区域整体描述,描述中加入总关注人群数等信息",
    	"description2":"报告正文开始的第一部分增加对该区域整体描述,描述中加入总关注人群数等信息,报告正文开始的第一部分增加对该区域整体描述,描述中加入总关注人群数等信息,报告正文开始的第一部分增加对该区域整体描述,描述中加入总关注人群数等信息,报告正文开始的第一部分增加对该区域整体描述,描述中加入总关注人群数等信息,报告正文开始的第一部分增加对该区域整体描述,描述中加入总关注人群数等信息,报告正文开始的第一部分增加对该行政区域整体描述,描述中加入总关注人群数等信息,报告正文开始的第一部分增加对该行政区域整体描述,描述中加入总关注人群数等信息,报告正文开始的第一部分增加对该行政区域整体描述,描述中加入总关注人群数等信息",
    	"reports":[
    		{
    			"serial":1,
    			"title":"一、贫困人口占比排名",
    			"base64":"xxxx",
    			"summary":"截止2018年6月,贫困人口占比最高的是XXX,占比达到60.8233%;占比最低的是XXXX,占比为11.6273%。",
    			"children":[]
    		},
    		{
    			"serial":2,
    			"title":"二、贫困人口关注等级分析",
    			"base64":"xxxxxxxx",
    			"summary":"截止2018年6月,总贫困人口中,一般关注等级0人,中度关注等级68156人,重点关注等级1人。三类人群分别占总人口的0%,34.2872%,0.0005%;占贫困总人口的0%,99.9985%,0.0014%。",
    			"children":[]
    		},
    		{
    			"serial":3,
    			"title":"三、致贫原因分析",
    			"base64":"xxxxx",
    			"summary":"截止2018年6月,贫困人口中,自身发展动力不足原因致贫的人数最多,占总贫困人口的37.0583%;其它原因致贫的人数最少,占总贫困人口的0.0161%。",
    			"children":[]
    		},
    		{
    			"serial":4,
    			"title":"四、贫困人群性别分析",
    			"base64":"xxxx",
    			"summary":"xxxxxxxxxxxxxxxxxxxxx",
    			"children":[]
    		},
    		{
    			"serial":5,
    			"title":"五、贫困人群年龄分析",
    			"base64":"xxxxx",
    			"summary":"",
    			"children":[]
    		},
    		{
    			"serial":6,
    			"title":"六、贫困人群学历分析",
    			"base64":"xxxxxx",
    			"summary":"",
    			"children":[]
    		},
    		{
    			"serial":7,
    			"title":"七、贫困人群民族分析",
    			"base64":"xxxxx",
    			"summary":"",
    			"children":[]
    		},
    		{
    			"serial":8,
    			"title":"八、贫困人群脱贫能力分析",
    			"base64":"",
    			"summary":"",
    			"children":[
    				{
    					"serial":1,
    					"title":"1、文化程度分析",
    					"base64":"xxxxx",
    					"summary":"截止2018年6月,贫困人口中,中度关注等级中的文盲或半文盲,学龄前学历人数最多,占总贫困人口的30.7232%;重度关注等级中的大专及以上学历人数最少,占总贫困人口的0%。"
    				},
    				{
    					"serial":2,
    					"title":"2、劳动能力分析",
    					"base64":"xxxxxx",
    					"summary":"截止2018年6月,贫困人口中,中度关注等级中的丧失劳动力劳动力人数最多,占总贫困人口的51.1466%;重度关注等级中的技能劳动力劳动力人数最少,占总贫困人口的0%。"
    				},
    				{
    					"serial":3,
    					"title":"3、健康情况分析",
    					"base64":"xxxxx",
    					"summary":"截止2018年6月,贫困人口中,中度关注等级中的健康健康状况人数最多,占总贫困人口的96.5653%;重度关注等级中的残疾健康状况人数最少,占总贫困人口的0%。"
    				}
    			]
    		},{
    			"serial":9,
    			"title":"九、资产和收入分析",
    			"base64":"",
    			"summary":"",
    			"children":[
    				{
    					"serial":1,
    					"title":"1、家庭收入分析",
    					"base64":"xxxxx",
    					"summary":"截止2018年6月,贫困人口中,中度关注等级中的5k-10k收入人数最多,占总贫困人口的9.0365%;重度关注等级中的15k以上收入人数最少,占总贫困人口的0%"
    				},
    				{
    					"serial":2,
    					"title":"2、房产情况分析",
    					"base64":"xxxxx",
    					"summary":"截止2018年6月,贫困人口中,中度关注等级中的房屋面积50-100房产人数最多,占总贫困人口的18.8565%;重度关注等级中的房屋面积100平以上房产人数最少,占总贫困人口的0%"
    				},
    				{
    					"serial":3,
    					"title":"3、耕地林地情况分析",
    					"base64":"xxxxx",
    					"summary":"截止2018年6月,贫困人口中,中度关注等级中拥有耕地面积5.32亩以上亩的人数最多,占总贫困人口的7.7556%;重度关注等级中拥有耕地面积5.32亩以上亩的人数最少,占总贫困人口的0%"
    				},
    				{
    					"serial":4,
    					"title":"4、新农合、养老保险情况分析",
    					"base64":"xxxx",
    					"summary":"截止2018年6月,贫困人口中,中度关注等级中办理已参加新农合保险的人数最多,占总贫困人口的99.9956%;重度关注等级中办理已办理养老保险保险的人数最少,占总贫困人口的0%"
    				}
    			]
    		},
    		{
    			"serial":10,
    			"title":"十、预脱贫分析",
    			"base64":"xxxx",
    			"summary":"截止2018年6月,预脱贫人口中,2020年预脱贫的人数最多,占总贫困人口的2.4134%",
    			"children":[]
    		},
    		{
    			"serial":11,
    			"title":"十一、生活状况分析",
    			"base64":"xxxx",
    			"summary":"截止2018年6月,贫困人口家庭中,没有实现卫生厕所的贫困家庭数量占比最高,占比为80.7526%",
    			"children":[]
    		}
    	]
    }
    

    ##13. 打开文件验证
    将swagger接口页面Response Body请求返回的doc文档下载并打开,效果图见文章顶部
    #七、问题排查

    1. doc模板设计保存成xml模板文件占位符分离,如${title_1}可能被分离成$、title_、1、}或者${title_、1}或者其他情况

    方案一:手动修改xml中被分离的占位符,但缺点是如果模板需要做一点改动,保存的xml又需要手动修改,增加无谓的工作量

    方案二:将整个占位符的样式设置成一样,但事实上同样存在被分离的情况
    方案三:该方案可完美解决占位符分离情况,避免修改doc模板保存时重复修改占位符,点击查看详细方案
    #八、git clone
    传送门:去star

    git clone https://github.com/v5zhu/export-doc.git
    

    九、联系方式

    QQ:2810010108

    展开全文
  • java 写入修改word 文档,附简单代码 package com.example.demo; import java.util.ArrayList; import java.util.List; import com.jacob.activeX.ActiveXComponent; import com.jacob.com.Dispatch; import ...

    java 写入修改word 文档,附简单代码

    package com.example.demo;
    
    import java.util.ArrayList;
    import java.util.List;
    
    import com.jacob.activeX.ActiveXComponent;
    import com.jacob.com.Dispatch;
    import com.jacob.com.Variant;
    
    public class WordTest {
    	// word文档
    	private Dispatch doc;
    
    	// word运行程序对象
    	private ActiveXComponent word;
    
    	// 所有word文档集合
    	private Dispatch documents;
    
    	// 选定的范围或插入点
    	private Dispatch selection;
    
    	private boolean saveOnExit = true;
    
    	/**
    	 * 
    	 * @param visible
    	 *            为true表示word应用程序可见
    	 */
    	public WordTest(boolean visible) {
    		if (word == null) {
    			word = new ActiveXComponent("Word.Application");
    			word.setProperty("Visible", new Variant(visible));
    		}
    		if (documents == null)
    			documents = word.getProperty("Documents").toDispatch();
    	}
    
    	/**
    	 * 设置退出时参数
    	 * 
    	 * @param saveOnExit
    	 *            boolean true-退出时保存文件,false-退出时不保存文件
    	 */
    	public void setSaveOnExit(boolean saveOnExit) {
    		this.saveOnExit = saveOnExit;
    	}
    
    	/**
    	 * 创建一个新的word文档
    	 * 
    	 */
    	public void createNewDocument() {
    		doc = Dispatch.call(documents, "Add").toDispatch();
    		selection = Dispatch.get(word, "Selection").toDispatch();
    	}
    
    	/**
    	 * 打开一个已存在的文档
    	 * 
    	 * @param docPath
    	 */
    	public void openDocument(String docPath) {
    		closeDocument();
    		doc = Dispatch.call(documents, "Open", docPath).toDispatch();
    		selection = Dispatch.get(word, "Selection").toDispatch();
    	}
    
    	/**
    	 * 把选定的内容或插入点向上移动
    	 * 
    	 * @param pos
    	 *            移动的距离
    	 */
    	public void moveUp(int pos) {
    		if (selection == null)
    			selection = Dispatch.get(word, "Selection").toDispatch();
    		for (int i = 0; i < pos; i++)
    			Dispatch.call(selection, "MoveUp");
    
    	}
    
    	/**
    	 * 把选定的内容或者插入点向下移动
    	 * 
    	 * @param pos
    	 *            移动的距离
    	 */
    	public void moveDown(int pos) {
    		if (selection == null)
    			selection = Dispatch.get(word, "Selection").toDispatch();
    		for (int i = 0; i < pos; i++)
    			Dispatch.call(selection, "MoveDown");
    	}
    
    	/**
    	 * 把选定的内容或者插入点向左移动
    	 * 
    	 * @param pos
    	 *            移动的距离
    	 */
    	public void moveLeft(int pos) {
    		if (selection == null)
    			selection = Dispatch.get(word, "Selection").toDispatch();
    		for (int i = 0; i < pos; i++) {
    			Dispatch.call(selection, "MoveLeft");
    		}
    	}
    
    	/**
    	 * 把选定的内容或者插入点向右移动
    	 * 
    	 * @param pos
    	 *            移动的距离
    	 */
    	public void moveRight(int pos) {
    		if (selection == null)
    			selection = Dispatch.get(word, "Selection").toDispatch();
    		for (int i = 0; i < pos; i++)
    			Dispatch.call(selection, "MoveRight");
    	}
    
    	/**
    	 * 把插入点移动到文件首位置
    	 * 
    	 */
    	public void moveStart() {
    		if (selection == null)
    			selection = Dispatch.get(word, "Selection").toDispatch();
    		Dispatch.call(selection, "HomeKey", new Variant(6));
    	}
    
    	public void moveEnd() {
    		if (selection == null)
    			selection = Dispatch.get(word, "Selection").toDispatch();
    		Dispatch.call(selection, "EndKey", new Variant(6));
    	}
    
    	/**
    	 * 从选定内容或插入点开始查找文本
    	 * 
    	 * @param toFindText
    	 *            要查找的文本
    	 * @return boolean true-查找到并选中该文本,false-未查找到文本
    	 */
    	public boolean find(String toFindText) {
    		if (toFindText == null || toFindText.equals(""))
    			return false;
    		// 从selection所在位置开始查询
    		Dispatch find = word.call(selection, "Find").toDispatch();
    
    		// 设置要查找的内容
    		Dispatch.put(find, "Text", toFindText);
    		// 向前查找
    		Dispatch.put(find, "Forward", "True");
    		// 设置格式
    		Dispatch.put(find, "Format", "True");
    		// 大小写匹配
    		Dispatch.put(find, "MatchCase", "True");
    		// 全字匹配
    		Dispatch.put(find, "MatchWholeWord", "True");
    		// 查找并选中
    		return Dispatch.call(find, "Execute").getBoolean();
    	}
    
    	/**
    	 * 把选定选定内容设定为替换文本
    	 * 
    	 * @param toFindText
    	 *            查找字符串
    	 * @param newText
    	 *            要替换的内容
    	 * @return
    	 */
    	public boolean replaceText(String toFindText, String newText) {
    		if (!find(toFindText))
    			return false;
    		Dispatch.put(selection, "Text", newText);
    		return true;
    	}
    
    	/**
    	 * 全局替换文本
    	 * 
    	 * @param toFindText
    	 *            查找字符串
    	 * @param newText
    	 *            要替换的内容
    	 */
    	public void replaceAllText(String toFindText, String newText) {
    		while (find(toFindText)) {
    			Dispatch.put(selection, "Text", newText);
    			Dispatch.call(selection, "MoveRight");
    		}
    	}
    
    	/**
    	 * 在当前插入点插入字符串
    	 * 
    	 * @param newText
    	 *            要插入的新字符串
    	 */
    	public void insertText(String newText) {
    		Dispatch.put(selection, "Text", newText);
    	}
    
    	/**
    	 * 
    	 * @param toFindText
    	 *            要查找的字符串
    	 * @param imagePath
    	 *            图片路径
    	 * @return
    	 */
    	public boolean replaceImage(String toFindText, String imagePath) {
    		if (!find(toFindText))
    			return false;
    		Dispatch.call(Dispatch.get(selection, "InLineShapes").toDispatch(), "AddPicture", imagePath);
    		return true;
    	}
    
    	/**
    	 * 全局替换图片
    	 * 
    	 * @param toFindText
    	 *            查找字符串
    	 * @param imagePath
    	 *            图片路径
    	 */
    	public void replaceAllImage(String toFindText, String imagePath) {
    		while (find(toFindText)) {
    			Dispatch.call(Dispatch.get(selection, "InLineShapes").toDispatch(), "AddPicture", imagePath);
    			Dispatch.call(selection, "MoveRight");
    		}
    	}
    
    	/**
    	 * 在当前插入点插入图片
    	 * 
    	 * @param imagePath
    	 *            图片路径
    	 */
    	public void insertImage(String imagePath) {
    		Dispatch.call(Dispatch.get(selection, "InLineShapes").toDispatch(), "AddPicture", imagePath);
    	}
    
    	/**
    	 * 合并单元格
    	 * 
    	 * @param tableIndex
    	 * @param fstCellRowIdx
    	 * @param fstCellColIdx
    	 * @param secCellRowIdx
    	 * @param secCellColIdx
    	 */
    	public void mergeCell(int tableIndex, int fstCellRowIdx, int fstCellColIdx, int secCellRowIdx, int secCellColIdx) {
    		// 所有表格
    		Dispatch tables = Dispatch.get(doc, "Tables").toDispatch();
    		// 要填充的表格
    		Dispatch table = Dispatch.call(tables, "Item", new Variant(tableIndex)).toDispatch();
    		Dispatch fstCell = Dispatch.call(table, "Cell", new Variant(fstCellRowIdx), new Variant(fstCellColIdx))
    				.toDispatch();
    		Dispatch secCell = Dispatch.call(table, "Cell", new Variant(secCellRowIdx), new Variant(secCellColIdx))
    				.toDispatch();
    		Dispatch.call(fstCell, "Merge", secCell);
    	}
    
    	/**
    	 * 在指定的单元格里填写数据
    	 * 
    	 * @param tableIndex
    	 * @param cellRowIdx
    	 * @param cellColIdx
    	 * @param txt
    	 */
    	public void putTxtToCell(int tableIndex, int cellRowIdx, int cellColIdx, String txt) {
    		// 所有表格
    		Dispatch tables = Dispatch.get(doc, "Tables").toDispatch();
    		// 要填充的表格
    		Dispatch table = Dispatch.call(tables, "Item", new Variant(tableIndex)).toDispatch();
    		Dispatch cell = Dispatch.call(table, "Cell", new Variant(cellRowIdx), new Variant(cellColIdx)).toDispatch();
    		Dispatch.call(cell, "Select");
    		Dispatch.put(selection, "Text", txt);
    	}
    
    	/**
    	 * 在当前文档拷贝数据
    	 * 
    	 * @param pos
    	 */
    	public void copy(String toCopyText) {
    		moveStart();
    		if (this.find(toCopyText)) {
    			Dispatch textRange = Dispatch.get(selection, "Range").toDispatch();
    			Dispatch.call(textRange, "Copy");
    		}
    	}
    
    	/**
    	 * 在当前文档粘帖剪贴板数据
    	 * 
    	 * @param pos
    	 */
    	public void paste(String pos) {
    		moveStart();
    		if (this.find(pos)) {
    			Dispatch textRange = Dispatch.get(selection, "Range").toDispatch();
    			Dispatch.call(textRange, "Paste");
    		}
    	}
    
    	/**
    	 * 在当前文档指定的位置拷贝表格
    	 * 
    	 * @param pos
    	 *            当前文档指定的位置
    	 * @param tableIndex
    	 *            被拷贝的表格在word文档中所处的位置
    	 */
    	public void copyTable(String pos, int tableIndex) {
    		Dispatch tables = Dispatch.get(doc, "Tables").toDispatch();
    		Dispatch table = Dispatch.call(tables, "Item", new Variant(tableIndex)).toDispatch();
    		Dispatch range = Dispatch.get(table, "Range").toDispatch();
    		Dispatch.call(range, "Copy");
    		if (this.find(pos)) {
    			Dispatch textRange = Dispatch.get(selection, "Range").toDispatch();
    			Dispatch.call(textRange, "Paste");
    		}
    	}
    
    	/**
    	 * 在当前文档末尾拷贝来自另一个文档中的段落
    	 * 
    	 * @param anotherDocPath
    	 *            另一个文档的磁盘路径
    	 * @param tableIndex
    	 *            被拷贝的段落在另一格文档中的序号(从1开始)
    	 */
    	public void copyParagraphFromAnotherDoc(String anotherDocPath, int paragraphIndex) {
    		Dispatch wordContent = Dispatch.get(doc, "Content").toDispatch(); // 取得当前文档的内容
    		Dispatch.call(wordContent, "InsertAfter", "$selection$"); // 插入特殊符定位插入点
    		copyParagraphFromAnotherDoc(anotherDocPath, paragraphIndex, "$selection$");
    	}
    
    	/**
    	 * 在当前文档指定的位置拷贝来自另一个文档中的段落
    	 * 
    	 * @param anotherDocPath
    	 *            另一个文档的磁盘路径
    	 * @param tableIndex
    	 *            被拷贝的段落在另一格文档中的序号(从1开始)
    	 * @param pos
    	 *            当前文档指定的位置
    	 */
    	public void copyParagraphFromAnotherDoc(String anotherDocPath, int paragraphIndex, String pos) {
    		Dispatch doc2 = null;
    		try {
    			doc2 = Dispatch.call(documents, "Open", anotherDocPath).toDispatch();
    			Dispatch paragraphs = Dispatch.get(doc2, "Paragraphs").toDispatch();
    
    			Dispatch paragraph = Dispatch.call(paragraphs, "Item", new Variant(paragraphIndex)).toDispatch();
    			Dispatch range = Dispatch.get(paragraph, "Range").toDispatch();
    			Dispatch.call(range, "Copy");
    			if (this.find(pos)) {
    				Dispatch textRange = Dispatch.get(selection, "Range").toDispatch();
    				Dispatch.call(textRange, "Paste");
    			}
    		} catch (Exception e) {
    			e.printStackTrace();
    		} finally {
    			if (doc2 != null) {
    				Dispatch.call(doc2, "Close", new Variant(saveOnExit));
    				doc2 = null;
    			}
    		}
    	}
    
    	/**
    	 * 在当前文档指定的位置拷贝来自另一个文档中的表格
    	 * 
    	 * @param anotherDocPath
    	 *            另一个文档的磁盘路径
    	 * @param tableIndex
    	 *            被拷贝的表格在另一格文档中的序号(从1开始)
    	 * @param pos
    	 *            当前文档指定的位置
    	 */
    	public void copyTableFromAnotherDoc(String anotherDocPath, int tableIndex, String pos) {
    		Dispatch doc2 = null;
    		try {
    			doc2 = Dispatch.call(documents, "Open", anotherDocPath).toDispatch();
    			Dispatch tables = Dispatch.get(doc2, "Tables").toDispatch();
    			Dispatch table = Dispatch.call(tables, "Item", new Variant(tableIndex)).toDispatch();
    			Dispatch range = Dispatch.get(table, "Range").toDispatch();
    			Dispatch.call(range, "Copy");
    			if (this.find(pos)) {
    				Dispatch textRange = Dispatch.get(selection, "Range").toDispatch();
    				Dispatch.call(textRange, "Paste");
    			}
    		} catch (Exception e) {
    			e.printStackTrace();
    		} finally {
    			if (doc2 != null) {
    				Dispatch.call(doc2, "Close", new Variant(saveOnExit));
    				doc2 = null;
    			}
    		}
    	}
    
    	/**
    	 * 在当前文档指定的位置拷贝来自另一个文档中的图片
    	 * 
    	 * @param anotherDocPath
    	 *            另一个文档的磁盘路径
    	 * @param shapeIndex
    	 *            被拷贝的图片在另一格文档中的位置
    	 * @param pos
    	 *            当前文档指定的位置
    	 */
    	public void copyImageFromAnotherDoc(String anotherDocPath, int shapeIndex, String pos) {
    		Dispatch doc2 = null;
    		try {
    			doc2 = Dispatch.call(documents, "Open", anotherDocPath).toDispatch();
    			Dispatch shapes = Dispatch.get(doc2, "InLineShapes").toDispatch();
    			Dispatch shape = Dispatch.call(shapes, "Item", new Variant(shapeIndex)).toDispatch();
    			Dispatch imageRange = Dispatch.get(shape, "Range").toDispatch();
    			Dispatch.call(imageRange, "Copy");
    			if (this.find(pos)) {
    				Dispatch textRange = Dispatch.get(selection, "Range").toDispatch();
    				Dispatch.call(textRange, "Paste");
    			}
    		} catch (Exception e) {
    			e.printStackTrace();
    		} finally {
    			if (doc2 != null) {
    				Dispatch.call(doc2, "Close", new Variant(saveOnExit));
    				doc2 = null;
    			}
    		}
    	}
    
    	/**
    	 * 创建表格
    	 * 
    	 * @param pos
    	 *            位置
    	 * @param cols
    	 *            列数
    	 * @param rows
    	 *            行数
    	 */
    	public void createTable(int numCols, int numRows) { // (String pos, int
    														// numCols, int numRows)
    														// {
    		// if (!find(pos)) {
    		Dispatch tables = Dispatch.get(doc, "Tables").toDispatch();
    		Dispatch range = Dispatch.get(selection, "Range").toDispatch();
    		Dispatch newTable = Dispatch.call(tables, "Add", range, new Variant(numRows), new Variant(numCols))
    				.toDispatch();
    		Dispatch.call(selection, "MoveRight");
    		moveEnd();
    		// }
    	}
    
    	/**
    	 * 在指定行前面增加行
    	 * 
    	 * @param tableIndex
    	 *            word文件中的第N张表(从1开始)
    	 * @param rowIndex
    	 *            指定行的序号(从1开始)
    	 */
    	public void addTableRow(int tableIndex, int rowIndex) {
    		// 所有表格
    		Dispatch tables = Dispatch.get(doc, "Tables").toDispatch();
    		// 要填充的表格
    		Dispatch table = Dispatch.call(tables, "Item", new Variant(tableIndex)).toDispatch();
    		// 表格的所有行
    		Dispatch rows = Dispatch.get(table, "Rows").toDispatch();
    		Dispatch row = Dispatch.call(rows, "Item", new Variant(rowIndex)).toDispatch();
    		Dispatch.call(rows, "Add", new Variant(row));
    	}
    
    	/**
    	 * 在第1行前增加一行
    	 * 
    	 * @param tableIndex
    	 *            word文档中的第N张表(从1开始)
    	 */
    	public void addFirstTableRow(int tableIndex) {
    		// 所有表格
    		Dispatch tables = Dispatch.get(doc, "Tables").toDispatch();
    		// 要填充的表格
    		Dispatch table = Dispatch.call(tables, "Item", new Variant(tableIndex)).toDispatch();
    		// 表格的所有行
    		Dispatch rows = Dispatch.get(table, "Rows").toDispatch();
    		Dispatch row = Dispatch.get(rows, "First").toDispatch();
    		Dispatch.call(rows, "Add", new Variant(row));
    	}
    
    	/**
    	 * 在最后1行前增加一行
    	 * 
    	 * @param tableIndex
    	 *            word文档中的第N张表(从1开始)
    	 */
    	public void addLastTableRow(int tableIndex) {
    		// 所有表格
    		Dispatch tables = Dispatch.get(doc, "Tables").toDispatch();
    		// 要填充的表格
    		Dispatch table = Dispatch.call(tables, "Item", new Variant(tableIndex)).toDispatch();
    		// 表格的所有行
    		Dispatch rows = Dispatch.get(table, "Rows").toDispatch();
    		Dispatch row = Dispatch.get(rows, "Last").toDispatch();
    		Dispatch.call(rows, "Add", new Variant(row));
    	}
    
    	/**
    	 * 增加一行
    	 * 
    	 * @param tableIndex
    	 *            word文档中的第N张表(从1开始)
    	 */
    	public void addRow(int tableIndex) {
    		Dispatch tables = Dispatch.get(doc, "Tables").toDispatch();
    		// 要填充的表格
    		Dispatch table = Dispatch.call(tables, "Item", new Variant(tableIndex)).toDispatch();
    		// 表格的所有行
    		Dispatch rows = Dispatch.get(table, "Rows").toDispatch();
    		Dispatch.call(rows, "Add");
    	}
    
    	/**
    	 * 增加一列
    	 * 
    	 * @param tableIndex
    	 *            word文档中的第N张表(从1开始)
    	 */
    	public void addCol(int tableIndex) {
    		// 所有表格
    		Dispatch tables = Dispatch.get(doc, "Tables").toDispatch();
    		// 要填充的表格
    		Dispatch table = Dispatch.call(tables, "Item", new Variant(tableIndex)).toDispatch();
    		// 表格的所有行
    		Dispatch cols = Dispatch.get(table, "Columns").toDispatch();
    		Dispatch.call(cols, "Add").toDispatch();
    		Dispatch.call(cols, "AutoFit");
    	}
    
    	/**
    	 * 在指定列前面增加表格的列
    	 * 
    	 * @param tableIndex
    	 *            word文档中的第N张表(从1开始)
    	 * @param colIndex
    	 *            指定列的序号 (从1开始)
    	 */
    	public void addTableCol(int tableIndex, int colIndex) {
    		// 所有表格
    		Dispatch tables = Dispatch.get(doc, "Tables").toDispatch();
    		// 要填充的表格
    		Dispatch table = Dispatch.call(tables, "Item", new Variant(tableIndex)).toDispatch();
    		// 表格的所有行
    		Dispatch cols = Dispatch.get(table, "Columns").toDispatch();
    		System.out.println(Dispatch.get(cols, "Count"));
    		Dispatch col = Dispatch.call(cols, "Item", new Variant(colIndex)).toDispatch();
    		// Dispatch col = Dispatch.get(cols, "First").toDispatch();
    		Dispatch.call(cols, "Add", col).toDispatch();
    		Dispatch.call(cols, "AutoFit");
    	}
    
    	/**
    	 * 在第1列前增加一列
    	 * 
    	 * @param tableIndex
    	 *            word文档中的第N张表(从1开始)
    	 */
    	public void addFirstTableCol(int tableIndex) {
    		Dispatch tables = Dispatch.get(doc, "Tables").toDispatch();
    		// 要填充的表格
    		Dispatch table = Dispatch.call(tables, "Item", new Variant(tableIndex)).toDispatch();
    		// 表格的所有行
    		Dispatch cols = Dispatch.get(table, "Columns").toDispatch();
    		Dispatch col = Dispatch.get(cols, "First").toDispatch();
    		Dispatch.call(cols, "Add", col).toDispatch();
    		Dispatch.call(cols, "AutoFit");
    	}
    
    	/**
    	 * 在最后一列前增加一列
    	 * 
    	 * @param tableIndex
    	 *            word文档中的第N张表(从1开始)
    	 */
    	public void addLastTableCol(int tableIndex) {
    		Dispatch tables = Dispatch.get(doc, "Tables").toDispatch();
    		// 要填充的表格
    		Dispatch table = Dispatch.call(tables, "Item", new Variant(tableIndex)).toDispatch();
    		// 表格的所有行
    		Dispatch cols = Dispatch.get(table, "Columns").toDispatch();
    		Dispatch col = Dispatch.get(cols, "Last").toDispatch();
    		Dispatch.call(cols, "Add", col).toDispatch();
    		Dispatch.call(cols, "AutoFit");
    	}
    
    	/**
    	 * 自动调整表格
    	 * 
    	 */
    	public void autoFitTable() {
    		Dispatch tables = Dispatch.get(doc, "Tables").toDispatch();
    		int count = Dispatch.get(tables, "Count").toInt();
    		for (int i = 0; i < count; i++) {
    			Dispatch table = Dispatch.call(tables, "Item", new Variant(i + 1)).toDispatch();
    			Dispatch cols = Dispatch.get(table, "Columns").toDispatch();
    			Dispatch.call(cols, "AutoFit");
    		}
    	}
    
    	/**
    	 * 调用word里的宏以调整表格的宽度,其中宏保存在document下
    	 * 
    	 */
    	public void callWordMacro() {
    		Dispatch tables = Dispatch.get(doc, "Tables").toDispatch();
    		int count = Dispatch.get(tables, "Count").toInt();
    		Variant vMacroName = new Variant("Normal.NewMacros.tableFit");
    		Variant vParam = new Variant("param1");
    		Variant para[] = new Variant[] { vMacroName };
    		for (int i = 0; i < para.length; i++) {
    			Dispatch table = Dispatch.call(tables, "Item", new Variant(i + 1)).toDispatch();
    			Dispatch.call(table, "Select");
    			Dispatch.call(word, "Run", "tableFitContent");
    		}
    	}
    
    	/**
    	 * 设置当前选定内容的字体
    	 * 
    	 * @param boldSize
    	 * @param italicSize
    	 * @param underLineSize
    	 *            下划线
    	 * @param colorSize
    	 *            字体颜色
    	 * @param size
    	 *            字体大小
    	 * @param name
    	 *            字体名称
    	 */
    	public void setFont(boolean bold, boolean italic, boolean underLine, String colorSize, String size, String name) {
    		Dispatch font = Dispatch.get(selection, "Font").toDispatch();
    		Dispatch.put(font, "Name", new Variant(name));
    		Dispatch.put(font, "Bold", new Variant(bold));
    		Dispatch.put(font, "Italic", new Variant(italic));
    		Dispatch.put(font, "Underline", new Variant(underLine));
    		Dispatch.put(font, "Color", colorSize);
    		Dispatch.put(font, "Size", size);
    	}
    
    	/**
    	 * 文件保存或另存为
    	 * 
    	 * @param savePath
    	 *            保存或另存为路径
    	 */
    	public void save(String savePath) {
    		Dispatch.call((Dispatch) Dispatch.call(word, "WordBasic").getDispatch(), "FileSaveAs", savePath);
    	}
    
    	/**
    	 * 关闭当前word文档
    	 * 
    	 */
    	public void closeDocument() {
    		if (doc != null) {
    			Dispatch.call(doc, "Save");
    			Dispatch.call(doc, "Close", new Variant(saveOnExit));
    			doc = null;
    		}
    	}
    
    	/**
    	 * 关闭全部应用
    	 * 
    	 */
    	public void close() {
    		closeDocument();
    		if (word != null) {
    			Dispatch.call(word, "Quit");
    			word = null;
    		}
    		selection = null;
    		documents = null;
    	}
    
    	/**
    	 * 打印当前word文档
    	 * 
    	 */
    	public void printFile() {
    		if (doc != null) {
    			Dispatch.call(doc, "PrintOut");
    		}
    	}
            /**
    	 * 插入word图表
             * 包含组合图表
             * t 图表类型
    	 * list 图表数据源
             * charttitletext 图表标题
    	 */
    	public void inLine(int t, List<Object[]> list, String chartTitleText) {
    		// List<Object[]> list=new ArrayList<Object[]>();
    		// Object[]
    		// o={"","广州电力设计院","广州汇隽电力工程设计有限公司","广州南方电力建设集团电力设计有限公司","广州市电力工程设计有限公司","广州新研电力设计有限公司"};
    		// Object[] o1={"前三季度平均值","68","139","84","124","42"};
    		// Object[] o2={"第四季度","163","247","13","363","66"};
    		// list.add(o);
    		// list.add(o1);
    		// list.add(o2);
    
    		// 插入ole对象
    		Dispatch inLine = Dispatch.get(selection, "InlineShapes").toDispatch();
    		Dispatch graph = Dispatch.call(inLine, "AddOLEObject", "MSGraph.Chart.8").toDispatch();
    		// 设置图表的高度
    		Dispatch.put(graph, "Height", new Variant(300.00));
    		// 设置表的宽度
    		Dispatch.put(graph, "Width", new Variant(400.00));
    		// 格式化图表
    		Dispatch oleFormat = Dispatch.call(graph, "OLEFormat").toDispatch();
    		Dispatch obj = Dispatch.call(oleFormat, "Object").toDispatch();
    		// 设置背景墙颜色
    		Dispatch walls = Dispatch.get(obj, "Walls").toDispatch();
    		Dispatch interiorWall = Dispatch.get(walls, "Interior").toDispatch();
    		Dispatch.put(interiorWall, "ColorIndex", new Variant(2));
    		// 设置图表区的外边框颜色和背景色
    		Dispatch chartArea = Dispatch.get(obj, "ChartArea").toDispatch();
    		Dispatch interior = Dispatch.get(chartArea, "Interior").toDispatch();
    		Dispatch.put(interior, "ColorIndex", new Variant(2));
    		Dispatch border = Dispatch.get(chartArea, "Border").toDispatch();
    		Dispatch.put(border, "ColorIndex", new Variant(1));
    		Dispatch.put(obj, "HasLegend", new Variant(false));
    		Dispatch.put(obj, "HasTitle", new Variant(true));
    		// 设置图形的类型
    		/*
    		 * 图形样式 可能的样式有:柱图代码为51,52,53,54,55,56;柱状图还含有堆积图 折线代码为65,66;
    		 * 饼图代码有70,-4102,5,69;等等)
    		 */
    		Dispatch.put(obj, "ChartType", 51);
    		Dispatch SeriesCollection = Dispatch.call(obj, "SeriesCollection", 2).toDispatch();
    		Dispatch.put(SeriesCollection, "ChartType", 4);
    
    		// 设置图形Y轴图形样式
    		Dispatch axes = Dispatch.call(obj, "Axes", 2).toDispatch();
    		Dispatch.put(axes, "HasMajorGridlines", true);// 设置图形的横向网络线是否显示
    		// 设置图形左侧坐标轴字体样式
    		Dispatch font_y = Dispatch.get(Dispatch.get(axes, "TickLabels").toDispatch(), "Font").toDispatch();
    		Dispatch.put(font_y, "Name", "宋体");
    		Dispatch.put(font_y, "Size", "9");
    		// 设置图标标题
    		Dispatch chartTitle = Dispatch.get(obj, "ChartTitle").toDispatch();
    		Dispatch.put(chartTitle, "Text", chartTitleText);
    		Dispatch font = Dispatch.get(chartTitle, "Font").toDispatch();
    		Dispatch.put(font, "Size", "18");
    		Dispatch.put(font, "Name", "黑体");
    		Dispatch dataSheet = Dispatch.get(obj, "Application").toDispatch();
    		Dispatch dataSheet2 = Dispatch.get(dataSheet, "dataSheet").toDispatch();
    
    		// 显示图形的数据表
    		Dispatch.put(obj, "HasDataTable", true);
    		Dispatch dataTable = Dispatch.get(obj, "DataTable").toDispatch();
    		// 设置是否显示数据表的标识(这里设置为显示数据表的标识)
    		Dispatch.put(dataTable, "ShowLegendKey", true);
    		// 获得数据表对象的字体属性,并设置字体和字号等
    		Dispatch fontTable = Dispatch.get(dataTable, "Font").toDispatch();
    		Dispatch.put(fontTable, "Name", "宋体");
    		Dispatch.put(fontTable, "Size", "9");
    
    		// 得到数据表的单元格
    		Dispatch cells = Dispatch.get(dataSheet2, "Cells").toDispatch();
    		Dispatch.call(cells, "Clear");
    		// for循环添加数据
    		for (int i = 0; i < list.size(); i++) {
    			Object[] o11 = list.get(i);
    
    			for (int j = 0; j < o11.length; j++) {
    				Dispatch item = Dispatch.call(cells, "Item", new Variant(i + 1), new Variant(j + 1)).toDispatch();
    				Dispatch.put(item, "value", o11[j]);
    			}
    
    		}
    		Dispatch.call(graph, "Select"); // 选中图表
    		// Dispatch.put(fullSeriesCollection, "ChartType", 4);
    		Dispatch ShapeRange = Dispatch.call(graph, "ConvertToShape").toDispatch(); // 取得图片区域
    		Dispatch WrapFormat = Dispatch.get(ShapeRange, "WrapFormat").toDispatch(); // 取得图片的格式对象
    		// 设置环绕格式(0 - 7)下面是参数说明
    		// wdWrapInline 7 将形状嵌入到文字中。
    		// wdWrapNone 3 将形状放在文字前面。请参阅 wdWrapFront 。
    		// wdWrapSquare 0 使文字环绕形状。行在形状的另一侧延续。
    		// wdWrapThrough 2 使文字环绕形状。
    		// wdWrapTight 1 使文字紧密地环绕形状。
    		// wdWrapTopBottom 4 将文字放在形状的上方和下方。
    		// wdWrapBehind 5 将形状放在文字后面。
    		// wdWrapFront 6 将形状放在文字前面。
    		Dispatch.put(WrapFormat, "Type", 1);
    
    	}
    
    	public static void main(String args[]) throws Exception {
    		//
    		// WordTest msWordManager = new WordTest(true);
    		// msWordManager.createNewDocument();
    		//
    		// String latex = "$$\\sqrt {{a^2} + {b^2}} *3$$";
    		//
    		// msWordManager.insertText(latex);
    		//
    		// msWordManager.moveEnd();
    		//
    		// msWordManager.close();
    
    	}
    
    }

     

    展开全文
  • 工作经常用到会一些生成统计报告、请假等word的功能需求,小编之前做了一些报表的生成,使用过freemarker和poi,但是使用freemarker生成word有一些麻烦的点: 需要先将模板word转化为xml,而且模板word中写...

    先给大家一个效果图:

    左侧是word模板,右侧是生成后的word文档。

     

    在工作中经常用到会有一些生成统计报告、请假等word的功能需求,小编之前做了一些报表的生成,使用过freemarker和poi,但是使用freemarker生成word有一些麻烦的点:

    1. 需要先将模板word转化为xml,而且在模板word中写好的占位符${obj}也会在转化为xml后被拆分开,还需要人工处理一次
    2. 在表格循环的时候,需要使用freemarker的<#list list as item>标签进行遍历
    3. 统计图表(饼图、折线图、柱状图等),图片适配度地,操作麻烦,图表需要人工修改大量xml中的标签已达到动态修改图表数据的效果,而word转为xml时,图片是已base64进行存储,在模板替换中我们需要将图片的base64码替换为占位符

    这就意味着使用freemarker需要我们预先编写好word模板再转化为xml,再对xml进行freemaker的标签、占位符等的处理后才能进行word生成,而且图表支持度很低。

    这里小编使用easypoi+jfree的形式进行word生成,使用jfree生成统计图表(饼图、折线图、柱状图等)图片,使用easypoi进行占位符替换、表格循环、图片插入已达到根据word模板生成word的效果。通过这个方式生成word只需要预先编写好word模板就可以进行word生成。

    但这个解决方案有一种缺点就是只支持07以后的word,也就是后缀为.docx的word文档。

    下面我就以Spring Boot项目为例举一个例子:

    开发工具:IntelliJ IDEA

    JDK:1.8

    以及项目目录结构:

    1、添加依赖:

            <dependency>
    			<groupId>cn.afterturn</groupId>
    			<artifactId>easypoi-base</artifactId>
    			<version>4.1.0</version>
    		</dependency>
    		<dependency>
    			<groupId>org.jfree</groupId>
    			<artifactId>jcommon</artifactId>
    			<version>1.0.24</version>
    		</dependency>
    		<dependency>
    			<groupId>org.jfree</groupId>
    			<artifactId>jfreechart</artifactId>
    			<version>1.5.0</version>
    		</dependency>

    2、编写jfreeutil工具类

    作为例子,我只封装了将图片转为字节数组和根据具有生成饼状图Image实体的两个方法,各位自行参考

    import cn.afterturn.easypoi.entity.ImageEntity;
    import lombok.extern.slf4j.Slf4j;
    import org.jfree.chart.ChartFactory;
    import org.jfree.chart.ChartUtils;
    import org.jfree.chart.JFreeChart;
    import org.jfree.chart.StandardChartTheme;
    import org.jfree.chart.labels.StandardPieSectionLabelGenerator;
    import org.jfree.chart.plot.PiePlot;
    import org.jfree.data.general.DefaultPieDataset;
    import org.springframework.util.Assert;
    import java.awt.*;
    import java.io.*;
    import java.util.Map;
    
    /**
     * @author 何昌杰
     *
     * 参考API博客 https://blog.csdn.net/dagecao/article/details/86536680
     */
    @Slf4j
    public class JfreeUtil {
    
        private static String tempImgPath="D:\\tempJfree.jpeg";
    
        /**
         * 将图片转化为字节数组
         * @return 字节数组
         */
        private static byte[] imgToByte(){
            File file = new File(tempImgPath);
            byte[] buffer = null;
            try {
                FileInputStream fis = new FileInputStream(file);
                ByteArrayOutputStream bos = new ByteArrayOutputStream(1000);
                byte[] b = new byte[1000];
                int n;
                while ((n = fis.read(b)) != -1) {
                    bos.write(b, 0, n);
                }
                fis.close();
                bos.close();
                buffer = bos.toByteArray();
            } catch (IOException e) {
                log.error(e.getMessage());
            }
            //删除临时文件
            file.delete();
            return buffer;
        }
    
        public static ImageEntity pieChart(String title, Map<String, Integer> datas, int width, int height) {
    
            //创建主题样式
            StandardChartTheme standardChartTheme = new StandardChartTheme("CN");
            //设置标题字体
            standardChartTheme.setExtraLargeFont(new Font("宋体", Font.BOLD, 20));
            //设置图例的字体
            standardChartTheme.setRegularFont(new Font("宋体", Font.PLAIN, 15));
            //设置轴向的字体
            standardChartTheme.setLargeFont(new Font("宋体", Font.PLAIN, 15));
            //设置主题样式
            ChartFactory.setChartTheme(standardChartTheme);
    
            //根据jfree生成一个本地饼状图
            DefaultPieDataset pds = new DefaultPieDataset();
            datas.forEach(pds::setValue);
            //图标标题、数据集合、是否显示图例标识、是否显示tooltips、是否支持超链接
            JFreeChart chart = ChartFactory.createPieChart(title, pds, true, false, false);
            //设置抗锯齿
            chart.setTextAntiAlias(false);
            PiePlot plot = (PiePlot) chart.getPlot();
            plot.setNoDataMessage("暂无数据");
            //忽略无值的分类
            plot.setIgnoreNullValues(true);
            plot.setBackgroundAlpha(0f);
            //设置标签阴影颜色
            plot.setShadowPaint(new Color(255,255,255));
            //设置标签生成器(默认{0})
            plot.setLabelGenerator(new StandardPieSectionLabelGenerator("{0}({1})/{2}"));
            try {
                ChartUtils.saveChartAsJPEG(new File(tempImgPath), chart, width, height);
            } catch (IOException e1) {
                log.error("生成饼状图失败!");
            }
            ImageEntity imageEntity = new ImageEntity(imgToByte(), width, height);
            Assert.notNull(imageEntity.getData(),"生成饼状图对象失败!");
            return imageEntity;
        }
    }

    关于jfree的一些API接口,和图形图表属性设置各位可参考这篇博客

    注:@Slf4j注解需要添加lombok的依赖

    3、编写wordutil工具类

    import cn.afterturn.easypoi.word.WordExportUtil;
    import org.apache.poi.xwpf.usermodel.XWPFDocument;
    import org.springframework.util.Assert;
    import java.io.File;
    import java.io.FileOutputStream;
    import java.util.Map;
    
    /**
     * @author 何昌杰
     */
    public class WordUtil {
        /**
         * 导出word
         * <p>第一步生成替换后的word文件,只支持docx</p>
         * <p>第二步下载生成的文件</p>
         * <p>第三步删除生成的临时文件</p>
         * 模版变量中变量格式:{{foo}}
         *
         * @param templatePath word模板地址
         * @param temDir       生成临时文件存放地址
         * @param fileName     文件名
         * @param params       替换的参数
         */
        public static void exportWord(String templatePath, String temDir, String fileName, Map<String, Object> params) {
            Assert.notNull(templatePath, "模板路径不能为空");
            Assert.notNull(temDir, "临时文件路径不能为空");
            Assert.notNull(fileName, "导出文件名不能为空");
            Assert.isTrue(fileName.endsWith(".docx"), "word导出请使用docx格式");
            if (!temDir.endsWith("/")) {
                temDir = temDir + File.separator;
            }
            File dir = new File(temDir);
            if (!dir.exists()) {
                dir.mkdirs();
            }
            try {
                XWPFDocument doc = WordExportUtil.exportWord07(templatePath, params);
                String tmpPath = temDir + fileName;
                FileOutputStream fos = new FileOutputStream(tmpPath);
                doc.write(fos);
                fos.flush();
                fos.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    4、编写word模板

    关于word中的更多表达式各位可参考easypoi文档的3节内容。

    5、编写测试类

    import java.util.ArrayList;
    import java.util.HashMap;
    import cn.afterturn.easypoi.entity.ImageEntity;
    import com.springclouddemo.freemarkerdemo.utils.JfreeUtil;
    import com.springclouddemo.freemarkerdemo.utils.WordUtil;
    
    /**
     * @author 何昌杰
     */
    public class WordDemo1 {
    
        public static void main(String[] args) {
            HashMap<String, Object> map = new HashMap<>(4);
    
            //模拟饼状图数据
            HashMap<String, Integer> datas = new HashMap<>(3);
            datas.put("一号",10);
            datas.put("二号",20);
            datas.put("三号",40);
            ImageEntity imageEntity = JfreeUtil.pieChart("测试",datas, 500, 300);
             map.put("picture", imageEntity);
    
            //模拟其它普通数据
            map.put("username", "张三");
            map.put("date", "2019-10-10");
            map.put("desc", "测试");
            map.put("boo", true);
    
            //模拟表格数据
            ArrayList<HashMap<String, String>> list = new ArrayList<>(2);
            HashMap<String, String> temp = new HashMap<>(3);
            temp.put("sn","1");
            temp.put("name","第一个人");
            temp.put("age","23");
            list.add(temp);
            temp = new HashMap<>(3);
            temp.put("sn","2");
            temp.put("name","第二个人");
            temp.put("age","24");
            list.add(temp);
            map.put("personlist",list);
            //word模板相对路径、word生成路径、word生成的文件名称、数据源
            WordUtil.exportWord("template/demo1.docx", "D:/", "生成文件.docx", map);
        }
    }

    6、运行测试

    生成后的word文档

    展开全文
  • word的筛选什么地方1.按快捷键Ctrl+A全选文档内容,然后快捷键Ctrl+H打开【查找和替换】窗口。2.鼠标单击【查找内容】文本框,输入“(3.然后点击【替换为】文本框,输入"\1\2" ,单击勾选下面【使用通配符】前的...
  • 方法一1、用WORD根据文章的章节自动生成目录--1.[格式]中选[样式与格式]--2.出现右边的一条“样式格式”栏,这里面主要就是用到标题1,标题2,标题3。把标题1,标题2,标题3分别应用到文中各个章节的标题上,设置...
  • 参考文章的基础上,增加了扩展。感谢被参考的老哥。 代码直接从日记复制过来的,不方便复制的可以私信发示例代码,不知道怎么上传附件了。...说明:poi3.x的版本,没有对图表的支持,至少目前为止没...
  • POI_4.1.0 word模板导出...  开始前,你一定要知道,word中图表,其实是通过一个内置excel来提供数据的。并且=一定要搞清楚以下几个概念:系列,分类,值。下面以一个折线图来举例说明。   通过这个折线图可以
  • 之前项目1通过GSM短信采集项目 本版采用了TCP服务器模式,来接收数据。还有数据格式有些变化 1.先上图(其实也支持串口,因为暂时不用,被我隐藏了) 很简单,没什么要说的。
  • 刷爆全网的动态条形图,原来5行Python代码就能实现!这是小F国庆之前写的一篇文章,全网阅读累计达到3万+。确实没想到影响这么大,当然还是得多感谢各方大佬的支持~既然了Python...
  • 第三章:Tableau绘图1 认识Tableau2 数据连接2.1 Excel CSV 和PDF数据2.1.1 连接Excel数据源2.1.2 连接文本文件数据源2.1.3 连接PDF数据源2.2 数据库连接3 维度与度量4 绘制条形图5 绘制堆叠图5.1 垂直堆叠条状图5.2...
  • 原贴:http://www.itwen.com/03office/01word/word20060413/43117.html 编排目录去掉页脚的关键是把文档分成几块几块的,然后单独来处理!插入分隔符!点击下一页,每次的分隔符都是首页设计的不一样;且要自动生成...
  • unity修改飞行数据Two and a half thousand years ago, the ancient Greeks used to visit a temple in Delphi to hear the Oracle of Apollo issue gnomic predictions about their futures. 两千半年前,古希腊人...
  • Python把docx文档的题库导入SQLite数据库 使用Python判断文件是否为PE文件 Python操作高版本Excel文件:颜色、边框、合并单元格 Python使用模糊哈希值比较文件相似度 Python压缩新文件到已有ZIP文件 Python生成...
  • 了Aphace POI,我们可以java读写excel文件,还可以使用 Java 读写 MS Word 和 MS PowerPoint。 这是Aphace POI官网下载链接: https://poi.apache.org/download.html 下载完后,进入解压目录,必须提取所需...
  • Python实现Office办公自动化Pycharm 2018(Mac版)的下载功能快捷键如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右...,丰富你的文章UML 图表FLowchart流程图导出与导入导出导入...
  • 1.6.1 从已有的主题选择自定义主题的效果 18 1.6.2 理解RGB颜色码 19 1.6.3 将十六进制转换为RGB 20 1.6.4 查找互补色 20 1.6.5 指定主题的颜色 21 1.6.6 指定主题的字体 22 1.6.7 保存自定义的主题...
  • 1.6.1 从已有的主题选择自定义主题的效果 18 1.6.2 理解RGB颜色码 19 1.6.3 将十六进制转换为RGB 20 1.6.4 查找互补色 20 1.6.5 指定主题的颜色 21 1.6.6 指定主题的字体 22 1.6.7 保存自定义的主题...
  • 1.6.1 从已有的主题选择自定义主题的效果 18 1.6.2 理解RGB颜色码 19 1.6.3 将十六进制转换为RGB 20 1.6.4 查找互补色 20 1.6.5 指定主题的颜色 21 1.6.6 指定主题的字体 22 1.6.7 保存自定义的主题...
  • 1.6.1 从已有的主题选择自定义主题的效果 18 1.6.2 理解RGB颜色码 19 1.6.3 将十六进制转换为RGB 20 1.6.4 查找互补色 20 1.6.5 指定主题的颜色 21 1.6.6 指定主题的字体 22 1.6.7 保存自定义的主题...
  • 1.6.1 从已有的主题选择自定义主题的效果 18 1.6.2 理解RGB颜色码 19 1.6.3 将十六进制转换为RGB 20 1.6.4 查找互补色 20 1.6.5 指定主题的颜色 21 1.6.6 指定主题的字体 22 1.6.7 保存自定义的主题...
  • 1.6.1 从已有的主题选择自定义主题的效果 18 1.6.2 理解RGB颜色码 19 1.6.3 将十六进制转换为RGB 20 1.6.4 查找互补色 20 1.6.5 指定主题的颜色 21 1.6.6 指定主题的字体 22 1.6.7 保存自定义的主题...
  • 1.6.1 从已有的主题选择自定义主题的效果 18 1.6.2 理解RGB颜色码 19 1.6.3 将十六进制转换为RGB 20 1.6.4 查找互补色 20 1.6.5 指定主题的颜色 21 1.6.6 指定主题的字体 22 1.6.7 保存自定义的主题...
  • 1.6.1 从已有的主题选择自定义主题的效果 18 1.6.2 理解RGB颜色码 19 1.6.3 将十六进制转换为RGB 20 1.6.4 查找互补色 20 1.6.5 指定主题的颜色 21 1.6.6 指定主题的字体 22 1.6.7 保存自定义的主题...
  • C# 使用Word文档对图像进行操作

    千次阅读 2015-02-02 14:31:27
    这篇文章我们可以学到C#程序使用一个Word文档对图像的各种操作。图像会比阅读文字更吸引力,而且图像是与内容紧密相关的。有时图像可以将内容描述的更为清晰,就像使用图表显示某一周期内的数据变化。  ...
  • (全文共计1485字,预计阅读时间为4分钟)导读:经典回顾:【强烈推荐】2天让你学会撰写影像组学SCI论文#内含福利#科研论文插图/数据处理和图表制作学习会2019年12月27-29日上海26号报到现场赠送8G优盘和高清视频...
  • 中文版Excel.2007图表宝典 1/2

    热门讨论 2012-04-06 18:49:24
    John前两版的基础上,升华已有的精粹,并结合Excel 2007的全新特性,为读者编著了一部技术含量高、实践性强的经典著作。  本书详细介绍了Excel 2007的全部图表功能,并且通过不同的示例展示了如何根据需要来选择...
  • 中文版Excel.2007图表宝典 2/2

    热门讨论 2012-04-06 19:01:36
    John前两版的基础上,升华已有的精粹,并结合Excel 2007的全新特性,为读者编著了一部技术含量高、实践性强的经典著作。  本书详细介绍了Excel 2007的全部图表功能,并且通过不同的示例展示了如何根据需要来选择...
  • 使用 SigaPlot 画出精密的图形是件极容易的事,目前已有超过十万的使用者,特别适合科学家使用。本软件允许用户自行建立任何所需的图形,可插入多条水平轴或垂直轴,指定误差棒(error bar)的方向,让你的图更光彩...
  • 测试题二测试题二 210 Word 打印预览窗口 可通过浏览文档观察文章段落页面上的整体布局 但 不能对其编辑修改 211 Word 用拆分窗口的方法可以同时看到一篇长文档的开头和结尾 212 Word 文档中 可以...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 6,269
精华内容 2,507
关键字:

如何在word中修改已有图表数据