一.導入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 {
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就完成啦!