这几天再弄一个报表,要统计一些信息最终的部分展示结果如下:

基本工具freemarker,jfreechart

工程的部分结构如下

与生成Word有关的类主要有FreemarkerConfiguration和WordGenerator代码如下:

import com.bqs.ares.common.utils.CommonUtils;
import freemarker.template.Configuration;import java.io.File;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;/*** Created by lenovo on 2016/9/27.*/
public class FreemarkerConfiguration {private static Logger log = LoggerFactory.getLogger(FreemarkerConfiguration.class);private final static String filepath = "/freemarkerTemplate";private static Configuration configuration=null;public static Configuration getConfiguration(){if(configuration==null){configuration=new Configuration();try {configuration.setDirectoryForTemplateLoading(new File(CommonUtils.class.getResource(filepath).getFile()));}catch (Exception e){log.error(e.getMessage());}}return  configuration;}
}
import com.bqs.risk.dvp.common.PDFUtils.freemarker.FreemarkerConfiguration;
import freemarker.template.Configuration;
import freemarker.template.Template;import java.io.*;
import java.util.Map;/*** Created by lenovo on 2016/10/9.*/
public class WordGenerator {/*** Generate html string.** @param template   the name of freemarker teamlate.* @param variables  the data of teamlate.* @return htmlStr* @throws Exception*/public static void generate(String template, Map<String,Object> variables, String htmlName) throws Exception{String basePath=HtmlGenerator.class.getResource("/").getPath()+"/freemarkerTemplate/word/";Configuration config = FreemarkerConfiguration.getConfiguration();config.setDefaultEncoding("UTF-8");Template tp = config.getTemplate(template);tp.setEncoding("UTF-8");String htmlPath=basePath+htmlName+".doc";File file = new File(htmlPath);if (!file.exists())file.createNewFile();Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), "utf-8"));tp.process(variables, out);out.flush();out.close();}
}

用jfreeChart生成折线图和饼图的代码如下:

import com.bqs.risk.dvp.common.InfoPoint;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.labels.ItemLabelAnchor;
import org.jfree.chart.labels.ItemLabelPosition;
import org.jfree.chart.labels.StandardCategoryItemLabelGenerator;
import org.jfree.chart.labels.StandardPieSectionLabelGenerator;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.PiePlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.renderer.category.LineAndShapeRenderer;
import org.jfree.chart.title.TextTitle;
import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.data.general.DefaultPieDataset;
import org.jfree.ui.TextAnchor;import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.text.NumberFormat;
import java.util.*;
import java.util.List;/*** Created by lenovo on 2016/9/28.*/
public class JfreeChartUtils {private static Map<String,String> relationNameMap=null;private static DefaultCategoryDataset createDataset(int[] data) {DefaultCategoryDataset linedataset = new DefaultCategoryDataset();// 曲线名称String series = "时间-次数";  // series指的就是报表里的那条数据线//因此 对数据线的相关设置就需要联系到serise//比如说setSeriesPaint 设置数据线的颜色// 横轴名称(列名称)String[] time = new String[24];for (int i = 0; i < 24; i++) {time[i] = i + "";}//添加数据值for (int i = 0; i < data.length; i++) {linedataset.addValue(data[i],  //值series,  //哪条数据线time[i]); // 对应的横轴}return linedataset;}//生成事件统计图public static String createChart(String eventTypevalue, int[] data, String imageName) {String returnImagePath = "";Calendar calendar = Calendar.getInstance();calendar.setTime(new Date());calendar.add(Calendar.MONTH, -1);if (data == null || data.length <= 0) {return null;}if (imageName == null || imageName.equals("")) {return null;}try {//定义图标对象JFreeChart chart = ChartFactory.createLineChart(null,// 报表题目,字符串类型"时间", // 横轴"次数", // 纵轴createDataset(data), // 获得数据集PlotOrientation.VERTICAL, // 图标方向垂直false, // 显示图例false, // 不用生成工具false // 不用生成URL地址);chart.setTitle(calendar.get(Calendar.YEAR) + "年" + (calendar.get(Calendar.MONTH) + 1) + "月" + eventTypevalue + "统计 ");chart.setTitle(new TextTitle(chart.getTitle().getText(),new Font("宋体", 1, 13)));//整个大的框架属于chart  可以设置chart的背景颜色// 生成图形CategoryPlot plot = chart.getCategoryPlot();// 图像属性部分plot.setBackgroundPaint(Color.WHITE);plot.setDomainGridlinesVisible(true);  //设置背景网格线是否可见plot.setDomainGridlinePaint(Color.BLACK); //设置背景网格线颜色plot.setRangeGridlinePaint(Color.WHITE);plot.setNoDataMessage("没有数据");//没有数据时显示的文字说明。// 数据轴属性部分NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();rangeAxis.setLabelFont(new Font("宋体", 1, 12));rangeAxis.setTickLabelFont((new Font("宋体", 1, 12)));rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());rangeAxis.setAutoRangeIncludesZero(true); //自动生成rangeAxis.setUpperMargin(0.20);rangeAxis.setLabelAngle(Math.PI / 2.0);rangeAxis.setAutoRange(false);// 数据渲染部分 主要是对折线做操作LineAndShapeRenderer renderer = (LineAndShapeRenderer) plot.getRenderer();renderer.setBaseItemLabelsVisible(true);renderer.setSeriesPaint(0, Color.CYAN);    //设置折线的颜色renderer.setBaseShapesFilled(true);renderer.setBaseItemLabelsVisible(true);renderer.setBasePositiveItemLabelPosition(new ItemLabelPosition(ItemLabelAnchor.OUTSIDE12, TextAnchor.BASELINE_LEFT));renderer.setBaseItemLabelGenerator(new StandardCategoryItemLabelGenerator());renderer.setBaseItemLabelFont(new Font("Dialog", 1, 10));  //设置提示折点数据形状plot.setRenderer(renderer);// 创建文件输出流String imagePath = JfreeChartUtils.class.getResource("/").getPath() + "/freemarkerTemplate/images/" + imageName + ".jpg";File fos_jpg = new File(imagePath);if (!fos_jpg.exists()) {fos_jpg.createNewFile();}// 输出到哪个输出流ChartUtilities.saveChartAsJPEG(fos_jpg, chart, // 统计图表对象1100, // 宽400 // 高);returnImagePath = imagePath;} catch (IOException e) {e.printStackTrace();}return returnImagePath;}/*** 用户设备关联图,每一张图有三条线** @param titleName:* @param relatioContentList* @return 图片的地址*/public static String createChart(String imageName, String titleName, Map<String, Map<String, String>> relatioContentList) {String imageFilePath = "";Calendar calendar = Calendar.getInstance();calendar.setTime(new Date());calendar.add(Calendar.MONTH, -1);//定义图标对象try {JFreeChart chart = ChartFactory.createLineChart(null,// 报表题目,字符串类型"数量", // 横轴"计数", // 纵轴createDataset(relatioContentList), // 获得数据集PlotOrientation.VERTICAL, // 图标方向垂直true, // 显示图例false, // 不用生成工具false // 不用生成URL地址);chart.setTitle(calendar.get(Calendar.YEAR) + "年" + (calendar.get(Calendar.MONTH) + 1) + "月" + titleName + "统计 ");chart.setTitle(new TextTitle(chart.getTitle().getText(),new Font("宋体", 1, 13)));//整个大的框架属于chart  可以设置chart的背景颜色// 生成图形CategoryPlot plot = chart.getCategoryPlot();// 图像属性部分plot.setBackgroundPaint(Color.WHITE);plot.setDomainGridlinesVisible(true);  //设置背景网格线是否可见plot.setDomainGridlinePaint(Color.BLACK); //设置背景网格线颜色plot.setRangeGridlinePaint(Color.WHITE);plot.setNoDataMessage("没有数据");//没有数据时显示的文字说明。// 数据轴属性部分NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();rangeAxis.setLabelFont((new Font("宋体", 1, 12)));rangeAxis.setTickLabelFont((new Font("宋体", 1, 12)));rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());rangeAxis.setAutoRangeIncludesZero(true); //自动生成rangeAxis.setUpperMargin(0.20);rangeAxis.setLabelAngle(Math.PI / 2.0);rangeAxis.setAutoRange(false);// 数据渲染部分 主要是对折线做操作LineAndShapeRenderer renderer = (LineAndShapeRenderer) plot.getRenderer();renderer.setBaseItemLabelsVisible(true);renderer.setSeriesPaint(0, Color.CYAN);    //设置折线的颜色renderer.setBaseShapesFilled(true);renderer.setBaseItemLabelsVisible(true);renderer.setBasePositiveItemLabelPosition(new ItemLabelPosition(ItemLabelAnchor.OUTSIDE12, TextAnchor.BASELINE_LEFT));renderer.setBaseItemLabelGenerator(new StandardCategoryItemLabelGenerator());renderer.setBaseItemLabelFont(new Font("Dialog", 1, 10));  //设置提示折点数据形状plot.setRenderer(renderer);// 创建文件输出流imageFilePath = JfreeChartUtils.class.getResource("/").getPath() + "/freemarkerTemplate/images/" + imageName + ".jpg";File fos_jpg = new File(imageFilePath);if (!fos_jpg.exists()) {fos_jpg.createNewFile();}// 输出到哪个输出流ChartUtilities.saveChartAsJPEG(fos_jpg, chart, // 统计图表对象1100, // 宽400 // 高);} catch (IOException e) {e.printStackTrace();}return imageFilePath;}private static DefaultCategoryDataset createDataset(Map<String, Map<String, String>> relatioContentList) {if(relationNameMap==null){relationNameMap=new HashMap<>();//此处省略}DefaultCategoryDataset linedataset = new DefaultCategoryDataset();for (Map.Entry<String, Map<String, String>> relation : relatioContentList.entrySet()) {//得到hbase中一列数据就是一条线String relationName =relationNameMap.get(relation.getKey());Map<String, String> relationContent = relation.getValue();List<Point> points = new ArrayList<>();//点for (Map.Entry<String, String> numCounts : relationContent.entrySet()) {int x = Integer.parseInt(numCounts.getKey());int y = Integer.parseInt(numCounts.getValue());Point p = new Point(x, y);points.add(p);}points.sort((p1, p2) -> p1.getX() - p2.getX());//添加数据值if (points != null && points.size() > 0) {for (Point p : points) {linedataset.addValue(p.getY(),  //值relationName,//哪条数据线p.getX() + ""); // 对应的横轴}}}return linedataset;}public static List<InfoPoint> getTop20Points(Map<String, String> values) {if (values == null || values.size() < 0) {return null;}List<InfoPoint> pointList = new ArrayList<>();for (Map.Entry<String, String> value : values.entrySet()) {String info = value.getKey();int num = Integer.parseInt(value.getValue());InfoPoint infoPoint = new InfoPoint(info, num);pointList.add(infoPoint);}pointList.sort((p1, p2) -> p2.getNum() - p1.getNum());if (pointList.size() > 20) {for (int i = 20; i < pointList.size(); i++) {pointList.remove(i);}}return pointList;}//生成城市分布的饼图public static String creatLocationPieChart(String imageName, String typeInfo, Map<String, String> locationInfo) {if (locationInfo == null || locationInfo.size() <= 0) {return null;}String imageFilePath="";try {//设置饼图数据集DefaultPieDataset dataset = new DefaultPieDataset();List<InfoPoint> infoPoints=new ArrayList<>();for (Map.Entry<String, String> info : locationInfo.entrySet()) {String city = info.getKey();int num = Integer.parseInt(info.getValue());InfoPoint point=new InfoPoint();point.setInfo(city);point.setNum(num);infoPoints.add(point);}if(infoPoints!=null&&infoPoints.size()>8){infoPoints=infoPoints.subList(0,8);}for(InfoPoint infoPoint:infoPoints){dataset.setValue(infoPoint.getInfo(),infoPoint.getNum());}//通过工厂类生成JFreeChart对象JFreeChart chart = ChartFactory.createPieChart(typeInfo + "分布图", dataset, true, true, false);chart.setTitle(new TextTitle(chart.getTitle().getText(),new Font("宋体", 1, 13)));//加个副标题PiePlot pieplot = (PiePlot) chart.getPlot();pieplot.setLabelFont(new Font("宋体", 0, 11));//设置饼图是圆的(true),还是椭圆的(false);默认为truepieplot.setCircular(true);StandardPieSectionLabelGenerator standarPieIG = new StandardPieSectionLabelGenerator("{0}:({1},{2})", NumberFormat.getNumberInstance(), NumberFormat.getPercentInstance());pieplot.setLabelGenerator(standarPieIG);//没有数据的时候显示的内容pieplot.setNoDataMessage("无数据显示");pieplot.setLabelGap(0.02D);imageFilePath = JfreeChartUtils.class.getResource("/").getPath() + "/freemarkerTemplate/images/" + imageName + ".jpg";File fos_jpg = new File(imageFilePath);if (!fos_jpg.exists()) {fos_jpg.createNewFile();}// 输出到哪个输出流ChartUtilities.saveChartAsJPEG(fos_jpg, chart, // 统计图表对象800, // 宽800 // 高);}catch (Exception e){e.printStackTrace();}return imageFilePath;}
}//折线中的点
class Point {private int x;private int y;public Point() {}public Point(int x, int y) {this.x = x;this.y = y;}public int getX() {return x;}public void setX(int x) {this.x = x;}public int getY() {return y;}public void setY(int y) {this.y = y;
<span style="font-size:14px;">    }
}
</span>

图片得到之后就是生成Word了,基本思路是先用Word做好模板,另存为xml,然后使用freemarker标签来替换,最后改成ftl文件就是模板,图片也只是替换那一大堆编码而已

 <w:pict><w:binData w:name="wordml://03000003${imagePath_index}.png" xml:space="preserve">${imagePath}</w:binData><v:shape id="_x0000_i1028" type="#_x0000_t75" style="width:440pt;height:440pt"><v:imagedata src="wordml://03000003${imagePath_index}.png" o:title="6350.tmp"/></v:shape></w:pict>

但这里确实花了我很多时间,主要的坑如下:

1.freemarker标签的使用:尤其要注意是否为空的情况所以对于list还是map最好都加上这一句:

<#if infoLocationList??&&infoLocationList?size gt 0>

是否存在,至于具体的循环遍历网上有不再赘述

2.Word模板另存为xml文件时一定要注意,如果是较高一点的版本有两种格式xml和2003xml这个在处理图片时有较大差别,我是使用2003xml版本(高版本的在处理图片时有错误),它在处理的时候需要将图片转成base64码具体代码如下:

 private String getImageStr(String imagePath) {String imgFile = imagePath;InputStream in = null;byte[] data = null;try {in = new FileInputStream(imgFile);data = new byte[in.available()];in.read(data);in.close();} catch (IOException e) {e.printStackTrace();}BASE64Encoder encoder = new BASE64Encoder();return encoder.encode(data);}

3.多张图片插入时会遇到图片重复记得改name和src,从List中取出数据并且实现插入多张图片:

<w:p wsp:rsidR="00C46D75" wsp:rsidRDefault="00C46D75" wsp:rsidP="00AC571C"/><#if infoLocationList??&&infoLocationList?size gt 0><w:p wsp:rsidR="0051625F" wsp:rsidRDefault="007F46BC" wsp:rsidP="00AC571C"><w:r><w:rPr><w:rFonts w:hint="fareast"/><wx:font wx:val="宋体"/></w:rPr><w:t>半年内手机号、身份证号、IP、GPS归属地信息分布</w:t></w:r></w:p><#list infoLocationList as imagePath><w:p wsp:rsidR="007F46BC" wsp:rsidRDefault="00E75FA4" wsp:rsidP="00AC571C"><w:r><w:tab/></w:r><w:r wsp:rsidR="00946545" wsp:rsidRPr="00946545"><w:rPr><w:noProof/></w:rPr><w:pict><w:binData w:name="wordml://03000003${imagePath_index}.png" xml:space="preserve">${imagePath}</w:binData><v:shape id="_x0000_i1028" type="#_x0000_t75" style="width:440pt;height:440pt"><v:imagedata src="wordml://03000003${imagePath_index}.png" o:title="6350.tmp"/></v:shape></w:pict></w:r></w:p></#list></#if>

4.如果模板太大转成的xml文件太大,看着是密密麻麻的一大片根本无法进一步处理,建议使用IDE进行代码格式化,想eclipse等等一般都可以,如果发现工具也无法格式化可以直接百度xml格式化,然后会有在线的工具

5.有时候会遇到成功生成Word文档但是无法打开的情况,这时候可以根据错误提示用文本编辑工具来具体到哪一行去看看,如果遇到什么结束元素标签名称与开始标签名称不匹配多半是ftl中标签配对有问题(这个有时候即使没有改过也会出错,所以最好借助工具好好补齐标签)

6.乱码问题,主要是在Linux服务器上会出现,具体方法网上也有

以上是自己的一些经验之谈,更多是在整个流程以及自己所遇到的坑上,具体说每一步怎么处理网上都会有

freemarker+Jfreechart生成Word文档(含图片)相关推荐

  1. Java使用FreeMarker自动生成Word文档(带图片和表单)

    Java使用FreeMarker自动生成Word文档(带图片和表单) 1 背景 2 目标效果 3 创建Word模板 3.1 创建模板文档 3.2 转换模板文档 3.3 处理模板文档中的占位符 3.4 ...

  2. 使用FreeMarker自动生成Word文档

    使用FreeMarker自动生成Word文档 获取文件路径 创建一个word文档,然后再文档中在文档中写标识,对应代码中的map数据 2.将word转为xml后缀文件,再转为.ftl文件 3.保存路径 ...

  3. 使用FreeMarker生成word文档(带图片),word转pdf,预览pdf,pdf下载工具类

    一.下载或配置: 下载jar包 :freemaker的jar包下载 下载jar包 :aspose-words的jar包下载 或者配置maven依赖: pom.xml添加aspose的依赖包(maven ...

  4. Springboot中使用freemarker动态生成word文档

    文章目录 freemarker模板动态生成word文档 前言 准备 简单模板准备 <一> `word 2003` 新建`.doc` 模板 <二> 另存为`.xml` 文件,格式 ...

  5. java根据 freemarker 生成word文档包含图片和动态表格

    需求 根据提供的模板样式,生成相对应的word文档,之前可以用xdoc生成,但是目前这个需求 是需要动态生成excel表格,有的单元格需要隐藏不展示,所以这边利用freemarker标签解析, 根据数 ...

  6. 使用freemarker模板生成word文档

    项目中最近用到这个东西,做下记录. 如下图,先准备好一个(office2003)word文档当做模板.文档中图片.姓名.性别和生日已经使用占位符代替,生成过程中将会根据实际情况进行替换. 然后将wor ...

  7. java利用freemarker动态生成word文档及动态表格

    这里写自定义目录标题 目标 准备 实现 处理模板 java实现 验证 目标 根据给定word模板,动态填充指定内容,并输出为新的word文档. 准备 1.模板: 准备一份目标格式的word文档,如:w ...

  8. Java使用FreeMarker自动生成Word文档

    背景:根据模板填充导出word 一.添加依赖 1 <dependency> 2 <groupId>org.freemarker</groupId> 3 <ar ...

  9. freemarker模板生成word文档踩坑记录

    在使用freemarker的过程中遇到的问题: 1.报错: Caused by: freemarker.core.InvalidReferenceException: The following ha ...

最新文章

  1. 【机器学习入门】(7) 线性回归算法:原理、公式推导、损失函数、似然函数、梯度下降
  2. android 打卡app,日常小打卡app
  3. 利用mybatis-generator自动生成代码
  4. python二维数组排序_Python实现二维数组按照某行或列排序的方法【numpy lexsort】...
  5. oracle入库的速度能到多少_倒车入库别练复杂了,其实就这两点
  6. LwIP之ARP协议
  7. thinkphp福娃源码交易网站源码
  8. vue-cli搭建项目(笔记)
  9. Hexo 入门指南(一) - 简介 准备
  10. 网络爬虫:中国大学排名定向爬虫
  11. 人的差别在于业余时间——细细品味 ==程序员学习能力提升三要素 ==》程序员学习能力提升三要素 ==编程从业五年的十四条经验,句句朴实
  12. nachos-虚拟内存管理
  13. cad导出pdf_CAD如何导出高分辨率图片
  14. python 整合excel_使用python将多个excel文件合并到同一个文件的方法
  15. Windows11 无法打开应用商店
  16. qq离线文件服务器是怎么实现秒传,一招教你提高QQ文件传输速度的方法
  17. 大数据:互联网大数据和物联网大数据有何不同?
  18. SH7218T拆解手记(4)修改外屏大时钟
  19. 怎么查自己电脑ip地址
  20. java(jdk 1.8 64位)连接中控考勤机

热门文章

  1. 微信授权,修改本地 host
  2. 【MySQL】记录锁?间隙锁?临键锁?到底锁了些什么?这一篇帮你捋清楚( ̄∇ ̄)/
  3. 实现带头结点单链表的就地逆置问题。
  4. linux运行gpg软件,Linux实用工具之GPG
  5. Python操作Excel自动插入图片
  6. alter table *** add constraint *** 用法
  7. 网站选择关键词需要遵循哪些原则呢?
  8. e575 viminfo 错误.
  9. Trap命令使用说明
  10. UDA一致正则化和熵最小化