一.导入freemaker和Echarts的jar包
下载地址:https://mvnrepository.com/
二. 制作模板
1.把需要替换的内容或图片用xxx替换(也可以直接用${xxx}格式,不过转xml的时候会被拆分开)。
2.表格只需要画一行,循环在xml中配置
3.如果多张图片的话,一定要选择不同的图片,不能为了省事使用同一张图片!
4.模板画好以后另存为xml格式,然后关掉word。
(一定要选Word 2003 XML文档!!!血的教训啊!!!)
5.用notepad++打开你保存的xml格式的文档 Ctrl+F找到你之前定义的单词,用${}包住。如图:
替换图片,搜索<pkg:binaryData>,把文档中的这些内容(这些内容就是插入图片的BASE64字符串)删掉 换成${imageName}这种名称的
循环生成表格
找到表格的<w:tr>标签,在<w:tr>标签前加上<#list listName as list>,在</w:tr>后边加上</#list>,list标签可以使标签内的表格自动循环生成相应的行数,listName就是你后台的数据, list是个别名,中间每个字段需要改成${list.xxx}格式。
完成模板,保存并关闭xml,修改文件的名称,改成.ftl格式的。(最后保存一份xml,方便以后修改,xml模板千万不要用word打开!!!)
三.Java代码
1.生成数据并返回集合
public static Map<String, Object> parseToMap(String date, String jrgl,
List<Map<String, Object>> list_CBQS) {
Map<String, Object> datas = new HashMap();
datas.put("rb_date", date);
datas.put("text_JRGL", jrgl);
datas.put("text_CBQS", text_CBQS);
datas.put("text_XXFB", text_XXFB);
datas.put("text_QGQX", text_QGQX);
此处把需要放入到word里边的数据都放到集合中并返回,图片需要转换成BASE64格式的字符串
String imgPath_CBQS = MakeImages(map_CBQS, "line", parm, queryType, request);
return datas;
}
//生成图表的json格式文件
public String MakeImages(List<Map<String,Object>> map, String type, Map<String,Object> parm, String queryType, HttpServletRequest request){
GsonOption option = new GsonOption();
String[] arrAxis;
if(type.equals("line")) {//折线图
Line line = new Line();
CategoryAxis category = new CategoryAxis(); //轴分类
if(queryType.equals("day")) {
arrAxis = new String[24];
for(int a = 0; a < 24; a++) {
String axis = StringUtils.leftPad(a + "", 2, "0");
arrAxis[a] = axis + ":00";
String value = "0";
for (Map<String, Object> data : map) {
if(axis.equals((data.get("sj") + ""))){
value = data.get("count") + "";
}
}
line.data(value);
}
category.data(arrAxis);
}
else if(queryType.equals("week") || queryType.equals("month")) {
String startTime = parm.get("startTime") + "";
String endTime = parm.get("endTime") + "";
Date startDate = new Date();
Date endDate = new Date();
SimpleDateFormat sdfa = new SimpleDateFormat("yyyy-MM-dd");
SimpleDateFormat sdf2 = new SimpleDateFormat("MM月dd日");
try {
if(startTime.length()>0) {
startDate = sdfa.parse(startTime);
}
if(endTime.length()>0) {
endDate = sdfa.parse(endTime);
}
Date tmp = startDate;
Calendar dd = Calendar.getInstance();
dd.setTime(startDate);
int days = WordGeneratorUtils.getDaysOfMonth(startDate);
int aLength = queryType.equals("week") ? 7 : days;
arrAxis = new String[aLength];
int i = 0;
do {
tmp = dd.getTime();
String axis = sdf2.format(tmp) + "";
String value = "0";
arrAxis[i] = axis;
for (Map<String, Object> data : map) {
if(axis.equals((data.get("sj") + ""))){
value = data.get("count") + "";
break;
}
}
line.data(value);
// 天数加上1
dd.add(Calendar.DAY_OF_MONTH, 1);
i++;
} while (tmp.getTime() < endDate.getTime());
category.data(arrAxis);
}
catch(Exception ex) {
}
}
category.boundaryGap(false);//起始和结束两端空白策略
option.series(line);
option.xAxis(category);//x轴
option.yAxis(new ValueAxis());
}
else if(type.equals("bar")) {//柱状图
Bar bar = new Bar();
CategoryAxis category = new CategoryAxis(); //轴分类
arrAxis = new String[legend.size()];
int i = 0;
for(String s : legend) {
String axis = s;
arrAxis[i] = axis;
Map<String,Object> item = new HashMap<>();
item.put("name", s);
String value = "0";
for (Map<String, Object> data : map) {
if(s.equals(data.get("category"))) {
value = data.get("count") + "";
}
}
item.put("value", value);
bar.data(item);
i++;
}
//5.设置显示工具
option.tooltip().show(true).
formatter("{a}</br>{b}:{c}");//设置显示的格式 当鼠标放到柱状图上时的显示格式
category.data(arrAxis);
//category.boundaryGap(false);//起始和结束两端空白策略
option.series(bar);
option.xAxis(category);//x轴
option.yAxis(new ValueAxis());
}
else if(type.equals("pie")) {//饼图
Pie pie = new Pie();//创建饼图对象
String[] searchs = {"正面", "负面", "中立"};
int i = 0;
for (Map<String, Object> data : map) {
Map<String,Object> item = new HashMap<>();
item.put("value",data.get("count"));
item.put("name",data.get("sentiment"));
pie.data(item);
searchs[i] = data.get("sentiment") + "";
i++;
}
//设置工具栏 展示 能标记
option.toolbox().show(true).feature(Tool.mark);
//设置图例 图例位置 图例对齐方式 竖列对齐
option.legend().data(searchs).x("right").orient(Orient.vertical);
option.series(pie);
}
String json = new Gson().toJson(option);
String fileDate = parm.get("fileDate") + "";
Map<String,Object> resultMap=new HashMap<>();
return generateEChart(json, resultMap, fileDate, type, request);
}
private static final String JSpath = "C:\\echarts\\echarts-convert\\echarts-convert1.js";
private static final Logger logger = Logger.getLogger(ReportContentRequest.class);
public static String generateEChart(String options, Map<String,Object> resultMap, String date, String type, HttpServletRequest request) {
String dataPath = writeFile(options, request);
String fileName= type + date + ".png";
String serverPath = request.getServletContext().getRealPath("/");
//String path = "C:/echarts/test/" +fileName;// /template/images/
String path = request.getServletContext().getRealPath("/") + "/template/images/" + fileName;
try {
File file = new File(path); //文件路径(路径+文件名)
if (!file.exists()) { //文件不存在则创建文件,先创建目录
File dir = new File(file.getParent());
dir.mkdirs();
file.createNewFile();
}
String cmd = "phantomjs " + JSpath + " -infile " + dataPath + " -outfile " + path;
Process process = Runtime.getRuntime().exec(cmd);
BufferedReader input = new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8"));
String line = "";
while ((line = input.readLine()) != null) {
logger.info(line);
}
input.close();
//是否删除json数据?
} catch (IOException e) {
e.printStackTrace();
}
return path;
}
public static String writeFile(String options, HttpServletRequest request) {
String dataPath = request.getServletContext().getRealPath("/") + "/template/json/"
+ UUID.randomUUID().toString().substring(0, 8) +".json";
try {
/* 写入Txt文件 */
File writename = new File(dataPath); // 相对路径,如果没有则要建立一个新的output.txt文件
if (!writename.exists()) { //文件不存在则创建文件,先创建目录
File dir = new File(writename.getParent());
dir.mkdirs();
writename.createNewFile(); // 创建新文件
}
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(writename), "UTF-8"));
out.write(options); // \r\n即为换行
out.flush(); // 把缓存区内容压入文件
out.close(); // 最后记得关闭文件
} catch (IOException e) {
e.printStackTrace();
}
return dataPath;
}
图片转Base64格式的方法
public static String ImageToBase64(String imgPath) {
InputStream in = null;
byte[] data = null;
try {
in = new FileInputStream(imgPath);
data = new byte[in.available()];
in.read(data);
in.close();
} catch(Exception ex) {
ex.printStackTrace();
}
Base64Encoder encoder = new Base64Encoder();
return encoder.encode(data);
}
Base64Encoder如果报错,就项目名右键,buildpath,选择JRE System Library 选中Access rules 点击Edit ,如图
public class WordGeneratorUtils {
private static Configuration configuration = null;
private static Map<String, Template> allTemplates = null;
private static class FreemarkerTemplate {
public static final String POVERTY = "template_RB";
public static final String POVERTY_ZB = "template_ZB";
public static final String POVERTY_YB = "template_YB";
}
static {
configuration = new Configuration(Configuration.VERSION_2_3_28);
configuration.setDefaultEncoding("utf-8");
configuration.setClassForTemplateLoading(WordGeneratorUtils.class, "/template");//存放模板的路径,在项目名/src下,template为包名称
allTemplates = new HashMap();
try {
allTemplates.put(FreemarkerTemplate.POVERTY, configuration.getTemplate(FreemarkerTemplate.POVERTY + ".ftl"));
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
public static File createDoc(Map<String, Object> dataMap, Map<String, Object> parm, HttpServletRequest request) {
try {
int max=1000000000,min=1;
int ran2 = (int) (Math.random()*(max-min)+min);
String serverPath = request.getServletContext().getRealPath("/");
String name = "";// /template/word/
String queryType = parm.get("queryKey") + "";
Template t = null;
if(queryType.equals("day")) {
name = serverPath + "/template/word/Report_RB" + parm.get("fileDate") + ran2 + ".doc";
//name = "F:/Report_RB" + parm.get("fileDate") + ran2 + ".doc";
t = allTemplates.get(FreemarkerTemplate.POVERTY);
}
File f = new File(name);
//t = allTemplates.get(FreemarkerTemplate.POVERTY);
// 这个地方不能使用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文档失败");
}
}
OK,利用freemaker导出到word就完成啦!