一 pom 文件引入:
<!-- 目前的版本对应 poi 4.1.2 和 xmlbeans 3.1.0 , poi 3.17 和 xmlbeans 2.6.0 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>org.apache.xmlbeans</groupId>
<artifactId>xmlbeans</artifactId>
<version>3.1.0</version>
</dependency>
<!-- easypoi导出word -->
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-spring-boot-starter</artifactId>
<version>4.4.0</version>
</dependency>
二 DownloadReportController 层
/**
*下载word
* @param response
* @throws Exception
*/
@ApiOperation("下载word")
@PostMapping("/exportToWord")
public void exportToWord(HttpServletResponse response, @RequestBody DownloadReportSearchVo downloadReportSearchVo) {
String secCode = SecurityContextHolder.getUserStockCode();
HengShenCompanyInfoDto companyInfoDto = remoteBasicService.getCompanyInfoByCode(secCode).getData();
String companyReferred = companyInfoDto.getCompanyReferred();
String day = DateUtil.format(new Date(),"yyyyMMdd");
String wordFileName = companyReferred+"("+secCode+")"+"市值诊断报告_"+day+".docx";
try {
downloadReportSearchVo.setSecCode(secCode);
Map<String, Object> wordInitDataMaps = downloadReportService.exportToWord(downloadReportSearchVo);
// 前端调用下面初始化word数据方法,下载时候从缓存取word map类型替换数据;
// Map<String, Object> wordInitDataMaps = redisService.getCacheMap(DOWNLOADREPORT_WORDDATA+secCode);
//读取模板 并 一次性提交maps里要替换的文字和图片内容,然后导出word;
XWPFDocument word = null;
try {
word = WordExportUtil.exportWord07(phantomjsRoot+"/市值诊断报告_YYYYMMDD.docx", wordInitDataMaps);
} catch (Exception e) {
e.printStackTrace();
}
response.setHeader("content-disposition", "attachment;filename="+ URLEncoder.encode(wordFileName,"UTF-8"));
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
ServletOutputStream outputStream = response.getOutputStream();
word.write(outputStream);
outputStream.close();
word.close();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
三 service 层
@Override
public Map<String, Object> exportToWord(DownloadReportSearchVo downloadReportSearchVo) {
String secCode = downloadReportSearchVo.getSecCode();
Map<String, Object> maps=new HashMap<>();
// 1-1 诊断结果>市值表现
// 1-2 诊断结果>流动性情况
//获取本模块4个echart图形数据和文字描述
LiquidityAnalysisVO liquidityAnalysisVO = liquiditySituationService.analysisResult(secCode);
//生成echart图片,并替换图片和文字
maps = liquiditySituationService.analysisResultToEchartImg(liquidityAnalysisVO,maps);
// 1-3 诊断结果>股东结构分析
//2-1 A股市值表现>市值对比
//2-2 A股市值表现>估值对比
//2-3 A股市值表现>股价对比
return maps;
}
/**
* 根据原图表数据,封装echart json option 格式,并生成echart图片
*
* @param liquidityAnalysisVO
*/
@Override
public Map<String, Object> analysisResultToEchartImg(LiquidityAnalysisVO liquidityAnalysisVO, Map<String, Object> maps) {
List<String> colorList = Arrays.asList("rgb(52,113,219)", "rgb(46,167,224)", "rgb(16,197,121)", "rgb(248,180,0)");
String suggest = liquidityAnalysisVO.getSuggest();
String yearAvgSuggest = liquidityAnalysisVO.getYearAvgSuggest();
// 1 第一张echart图 生成echart option
//换手率 替换第一张图片和文字
List<OverviewVO> listYearAvgAnalysis = liquidityAnalysisVO.getYearAvgAnalysis();
List<String> indexkeyYearAvgAnalysis = listYearAvgAnalysis.stream().map(overviewVO -> overviewVO.getIndexKey()).collect(Collectors.toList());
List<BigDecimal> indexValueYearAvgAnalysis = listYearAvgAnalysis.stream().map(overviewVO -> overviewVO.getIndexValue()).collect(Collectors.toList());
maps.put(DownloadReportEnum.DIAGNOSTIC_RESULT_FLOW_SUGGEST.getName(), suggest);
maps.put(DownloadReportEnum.DIAGNOSTIC_RESULT_FLOW_1_YEARAVGSUGGEST.getName(), yearAvgSuggest.replaceAll("<span>", "").replaceAll("</span>", ""));
String option = "{\n" +
" title: {\n" +
" text: '换手率'\n" +
" },\n" +
" tooltip: {\n" +
" trigger: 'axis',\n" +
" axisPointer: {\n" +
" type: 'shadow'\n" +
" }\n" +
" },\n" +
" legend: {},\n" +
" grid: {\n" +
" left: '3%',\n" +
" right: '4%',\n" +
" bottom: '3%',\n" +
" containLabel: true\n" +
" },\n" +
" xAxis: {\n" +
" type: 'value',\n" +
" boundaryGap: [0, 0.01]\n" +
" },\n" +
" yAxis: {\n" +
" type: 'category',\n" +
" data: ['" + StringUtils.join(indexkeyYearAvgAnalysis, "','") + "'] \n" +
" },\n" +
" series: [\n" +
" {\n" +
" barWidth:30, " +
" name: '当年度年平均换手率(%)',\n" +
" type: 'bar',\n" +
" data: [ \n ";
for (int i = 0; i < indexValueYearAvgAnalysis.size(); i++) {
BigDecimal value = indexValueYearAvgAnalysis.get(i);
String color = colorList.get(i);
option += " { " +
"value: " + numberUtils.formatToBigDecimal(value) + ", " +
"itemStyle: { " +
"color: '" + color + "' " +
"} " +
"}, ";
}
option += " ]} \n" +
" ]\n" +
"};\n";
String echartImgPath1 = eChartImgService.generateEChartImg(option);
// 2 生成要代替word里图像英文单词字符串
ImageEntity imageEntity = new ImageEntity();
imageEntity.setUrl(echartImgPath1);
imageEntity.setWidth(500);
imageEntity.setHeight(300); // 这里的宽高一定要设置,不然图片出不来
maps.put(DownloadReportEnum.DIAGNOSTIC_RESULT_FLOW_1_IMG1.getName(), imageEntity);//替换图片
}
四: phantomjs 插件生成echart 图片
package com.realize.market.value.service.impl;
import com.realize.market.value.service.IEChartImgService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.io.*;
import java.util.UUID;
@Service
@Slf4j
public class EChartImgServiceImpl implements IEChartImgService {
private static final Logger logger = LoggerFactory.getLogger(EChartImgServiceImpl.class);
private static String phantomjsRoot;
private static String phantomjsWindowPath;
private static String phantomjsLinuxPath;
private static String JSpath;
@Value("${phantomjs.root}")
public void setSender(String phantomjs) {
phantomjsRoot = phantomjs;
phantomjsWindowPath=phantomjsRoot+"/phantomjs-2.1.1-windows/bin/phantomjs.exe";
phantomjsLinuxPath=phantomjsRoot+"/phantomjs-2.1.1-linux-x86_64/bin/phantomjs";
JSpath=phantomjsRoot+"/echarts-convert/echarts-convert1.js";
}
@Override
public String generateEChartImg(String options) {
// 1此处可根据操作系统获取对应phantomjs文件路径(phantomjs.exe对应Windows,phantomjs对应Linux)
String phantomjsPath = "";
String os = System.getProperty("os.name").toLowerCase();
if (os.contains("windows")) {
phantomjsPath = phantomjsWindowPath;
}else{
phantomjsPath = phantomjsLinuxPath;
}
// 2根据各模块传递过来的 echart json, 生成服务器本地 echart json文件
//String inputDataPath = writeLocalJsonFile(options);
String filename = UUID.randomUUID().toString().replaceAll("-","");
String inputDataPath=phantomjsRoot+"/data/"+filename+".json";
try {
/* 写入json文件 */
File writename = new File(inputDataPath); // 相对路径,如果没有则要建立一个新的output.json文件
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();
}
// 3读取本地echart json 格式文件生成 echart 图片
String outfilePath = phantomjsRoot+"/Echart/" +filename+ ".png";
try {
File file = new File(outfilePath); //文件路径(路径+文件名)
if (!file.exists()) { //文件不存在则创建文件,先创建目录
File dir = new File(file.getParent());
dir.mkdirs();
file.createNewFile();
}
// 执行 phantomjs 插件命令,输入json ,输出echart图片生成;
String cmd = phantomjsPath+" " + JSpath + " -infile " + inputDataPath + " -outfile " + outfilePath;
excuteCMDBatFile(cmd,filename);
//Process process = Runtime.getRuntime().exec(cmd);
//BufferedReader input = new BufferedReader(new InputStreamReader(process.getInputStream()));
//input.close();
} catch (IOException e) {
e.printStackTrace();
}finally{
return outfilePath;
}
}
/**
* 1.将执行的命名写入到sh/cmd文件中,没有用 Runtime 直接执行命令,避免系统阻塞卡顿
* @param exportFile
* @param content
* @return
*/
public boolean writeFile(File exportFile, String content) {
if (exportFile == null || StringUtils.isEmpty(content)) {
return false;
}
if (!exportFile.exists()) {
try {
exportFile.getParentFile().mkdirs();
exportFile.createNewFile();
} catch (IOException e) {
e.printStackTrace();
logger.error("create local json file exception: " + e.getMessage());
return false;
}
}
BufferedWriter bufferedWriter = null;
try {
FileOutputStream os = new FileOutputStream(exportFile);
FileDescriptor fd = os.getFD();
bufferedWriter = new BufferedWriter(new OutputStreamWriter(os, "UTF-8"));
bufferedWriter.write(content);
//Flush the data from the streams and writes into system buffers
//The data may or may not be written to disk.
bufferedWriter.flush();
//block until the system buffers have been written to disk.
//After this method returns, the data is guaranteed to have
//been written to disk.
fd.sync();
//设置文件权限
exportFile.setExecutable(true);
exportFile.setReadable(true);
exportFile.setWritable(true);
} catch (UnsupportedEncodingException e) {
logger.error("saveDBData#catch an UnsupportedEncodingException (" + e.getMessage() + ")");
return false;
} catch (FileNotFoundException e) {
logger.error("saveDBData#catch an FileNotFoundException (" + e.getMessage() + ")");
return false;
} catch (IOException e) {
logger.error("saveDBData#catch an IOException (" + e.getMessage() + ")");
return false;
} catch (Exception e) {
logger.error("saveDBData#catch an exception (" + e.getMessage() + ")");
return false;
} finally {
try {
if (bufferedWriter != null) {
bufferedWriter.close();
bufferedWriter = null;
}
} catch (IOException e) {
logger.error("writeJsonToFile#catch an exception (" + e.getMessage() + ")");
}
}
return true;
}
//2.执行命令 phantomjs 插件生成echart 图片
public boolean excuteCMDBatFile(String cmd,String filename) {
String os = System.getProperty("os.name").toLowerCase();
String batFilePath="";
if (os.contains("windows")) {
batFilePath = phantomjsRoot+"/data/"+filename+".bat";
}else{
batFilePath = phantomjsRoot+"/data/"+filename+".sh";
}
final String METHOD_NAME = "excuteCMDBatFile#";
boolean result = true;
Process p;
File batFile = new File(batFilePath);
//System.out.println(batFile.getAbsolutePath());
//命令写入bat文件
boolean isSuccess = writeFile(batFile, cmd);
if(!isSuccess) {
logger.error(METHOD_NAME + "write cmd to File failed.");
return false;
}
logger.info("cmd path:" + batFilePath);
try {
//执行命令 bat文件
p = Runtime.getRuntime().exec(batFilePath);
InputStream fis = p.getErrorStream();//p.getInputStream();
InputStreamReader isr = new InputStreamReader(fis, System.getProperty("file.encoding"));
BufferedReader br = new BufferedReader(isr);
String line = null;
StringBuilder builder = new StringBuilder();
while ((line = br.readLine()) != null) {
builder.append(line);
}
p.waitFor();
int i = p.exitValue();
logger.info(METHOD_NAME + "exitValue = " + i);
if (i != 0) {
result = false;
logger.error(METHOD_NAME + "excute cmd failed, [result = " + result + ", error message = " + builder.toString() + "]");
//System.out.println(METHOD_NAME + "excute cmd failed, [result = " + result + ", error message = " + builder.toString() + "]");
}else {
// logger.debug(METHOD_NAME + "excute cmd result = " + result);
System.out.println(METHOD_NAME + "result = " + result);
}
} catch (Exception e) {
result = false;
e.printStackTrace();
logger.error(METHOD_NAME + "fail to excute bat File [ErrMsg=" + e.getMessage() + "]");
}
return result;
}
/*public static void main(String[] args) {
//String cmd="F:/usr/local/plugin/phantomjs-2.1.1-windows/bin/phantomjs.exe F:/usr/local/plugin/echarts-convert/echarts-convert1.js -infile F:/usr/local/plugin/data/37da9189.json -outfile F:/usr/local/plugin/Echart/37da9189-1.png";
String cmd="/usr/local/plugin/phantomjs-2.1.1-linux-x86_64/bin/phantomjs /usr/local/plugin/echarts-convert/echarts-convert1.js -infile /usr/local/plugin/data/37da9189.json -outfile /usr/local/plugin/Echart/37da9189-1.png";
excuteCMDBatFile(cmd);
}*/
}
插件包含内容:
1 phantomjs-2.1.1-windows 执行转化图片命令
2 echarts-convert js生成ecahrt 图片