SpringBoot純后臺生成Echarts圖片(一)
在实际的生产应用中,我们常常需要将数据进行可视化,生成一些图文报表以供前端使用与查看。而我们使用的最多的图表生成插件工具就是Echarts。为了生成相关的图文报表,我们可以通过前端结合js等来生成,另外也可以使用纯后台(Java代码)来生成。这里我们就介绍使用SpringBoot框架通过API传递参数的方式,纯Java代码而不使用前端来生成相关的图表。
本篇以生成柱状图为例:
一、项目的工程结构
二、项目依赖说明
(1)pom.xml依赖配置如下:
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-freemarker</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient --> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.9</version> </dependency> <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson --> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.59</version> </dependency> <!-- https://mvnrepository.com/artifact/com.github.abel533/ECharts --> <dependency> <groupId>com.github.abel533</groupId> <artifactId>ECharts</artifactId> <version>3.0.0.6</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.7</version> </dependency> <!-- 添加swagger2 --> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.9.2</version> </dependency> <!-- swagger2-UI --> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.9.2</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
(2)application.properties属性文件配置
server.port=8095 img-url=image/ request-url=http://127.0.0.1:6666 img-url-path=F:/echarts/ #HttpServletRequest 的属性是否可以覆盖 controller 中 model 的同名项 spring.freemarker.allow-request-override=false #HttpSession 的属性是否可以覆盖 controller 中 model 的同名项 spring.freemarker.allow-session-override=false #是否开启缓存 spring.freemarker.cache=false #模板文件编码 spring.freemarker.charset=UTF-8 #是否检查模板位置 spring.freemarker.check-template-location=true #Content-Type 的值 spring.freemarker.content-type=text/html #是否将 HttpServletRequest 中的属性添加到 Model 中 spring.freemarker.expose-request-attributes=false #是否将 HttpSession 中的属性添加到 Model 中 spring.freemarker.expose-session-attributes=false #模板文件后缀 spring.freemarker.suffix=.ftl #模板文件位置 spring.freemarker.template-loader-path=classpath: /templates/
三、项目代码说明
(1)common模块-JsonResult.java
package com.lhf.springboot.common;
/**
* @ClassName: JsonResult
* @Author: liuhefei
* @Description: TODD
* @Date: 2019/8/13 17:55
*/
public class JsonResult<T> {
private int status = 0;
private T data;
private String errMsg;
public JsonResult(T data) {
this.data = data;
}
public JsonResult(int status, String errMsg) {
this.status = status;
this.errMsg = errMsg;
}
public JsonResult(int status, T data, String errMsg) {
this.status = status;
this.data = data;
this.errMsg = errMsg;
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public String getErrMsg() {
return errMsg;
}
public void setErrMsg(String errMsg) {
this.errMsg = errMsg;
}
}(2)config模块-SwaggerConfig.java
package com.lhf.springboot.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
/**
* @ClassName: SwaggerConfig
* @Author: liuhefei
* @Description: TODD
* @Date: 2019/5/29 19:26
*/
@Configuration
@EnableSwagger2
public class SwaggerConfig {
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.lhf.springboot"))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder().title("Api接口接口")
.description("api接口描述信息")
.contact(new Contact("liuhefei", "http://www.xianlaiwan.cn/u/1323320", "[email protected]"))
.termsOfServiceUrl("https://swagger.io/swagger-ui/")
.version("1.0")
.build();
}
}(3)echarts-pojo模块(数据模型)-BarData.java
package com.lhf.springboot.echarts.pojo;
import lombok.Data;
/**
* @ClassName: BarData
* @Author: liuhefei
* @Description: TODD
* @Date: 2019/8/15 16:08
*/
public class BarData {
private String title; //标题
private BarParam barParamList;
private Boolean isHorizontal; //是否水平放置
//省略get/set方法
}(4)echarts-pojo模块(数据模型)-BarParam.java
package com.lhf.springboot.echarts.pojo;
/**
* @ClassName: BarParam
* @Author: liuhefei
* @Description: TODD
* @Date: 2019/8/15 16:11
*/
public class BarParam {
private Object[] barName;
private Object[] barValue;
private String legendName;
//省略get/set方法
}(5)echarts模块-EchartsConfig.java(接口)
package com.lhf.springboot.echarts;
/**
* @ClassName: EchartsConfig
* @Author: liuhefei
* @Description: TODD
* @Date: 2019/8/22 18:16
*/
public interface EchartsConfig {
/**
* 测试文件生成的目录
*/
String EXPORT_PATH = "";
/**
* 通过view控制所有测试是否打开浏览器
*/
Boolean VIEW = true;
}(6)echarts模块-EnhancedOption.java(实现类,对GsonOption.java做一层封装)
package com.lhf.springboot.echarts;
import com.github.abel533.echarts.json.GsonOption;
import com.github.abel533.echarts.json.GsonUtil;
import com.github.abel533.echarts.json.OptionUtil;
/**
* @ClassName: EnhancedOption
* @Author: liuhefei
* @Description: TODD
* @Date: 2019/8/22 18:15
*/
public class EnhancedOption extends GsonOption implements EchartsConfig {
private String filepath;
/**
* 输出到控制台
*/
public void print() {
GsonUtil.print(this);
}
/**
* 输出到控制台
*/
public void printPretty() {
GsonUtil.printPretty(this);
}
/**
* 在浏览器中查看
*/
public void view() {
if (!VIEW) {
return;
}
if (this.filepath != null) {
try {
OptionUtil.browse(this.filepath);
} catch (Exception e) {
this.filepath = OptionUtil.browse(this);
}
} else {
this.filepath = OptionUtil.browse(this);
}
}
/**
* 导出到指定文件名
*
* @param fileName
* @return 返回html路径
*/
public String exportToHtml(String fileName) {
return exportToHtml(EXPORT_PATH, fileName);
}
}(7)echarts-option模块(组装图表option)-EchartBar.java(组装柱状图option)(核心)
package com.lhf.springboot.echarts.option;
import com.github.abel533.echarts.Legend;
import com.github.abel533.echarts.axis.AxisLabel;
import com.github.abel533.echarts.axis.AxisLine;
import com.github.abel533.echarts.axis.CategoryAxis;
import com.github.abel533.echarts.axis.ValueAxis;
import com.github.abel533.echarts.code.Magic;
import com.github.abel533.echarts.code.Position;
import com.github.abel533.echarts.code.Tool;
import com.github.abel533.echarts.feature.MagicType;
import com.github.abel533.echarts.json.GsonOption;
import com.github.abel533.echarts.series.Bar;
import com.github.abel533.echarts.series.Series;
import com.github.abel533.echarts.style.ItemStyle;
import com.github.abel533.echarts.style.LineStyle;
import com.github.abel533.echarts.style.TextStyle;
import com.github.abel533.echarts.style.itemstyle.Normal;
import com.lhf.springboot.echarts.EnhancedOption;
import com.lhf.springboot.echarts.pojo.BarData;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* @ClassName: EchartBar
* @Author: liuhefei
* @Description: TODD
* @Date: 2019/8/15 15:26
*/
public class EchartBar {
/**
* 生成单柱状图
* @param //isHorizontal 是否水平放置
* @param //color 柱状图颜色,可以不设置,默认为红色
* @param //title 柱状图标题
* @param //xdatas 横轴数据
* @param //ydatas 纵轴数据
* @return
*/
public static GsonOption createBar(BarData barData){
/*String[] citis = { "广州", "深圳", "珠海", "汕头", "韶关", "佛山" };
int[] datas = { 6030, 7800, 5200, 3444, 2666, 5708 };
String title = "地市数据";
String[] colors = { "rgb(2,111,230)", "rgb(186,73,46)", "rgb(78,154,97)", "rgb(2,111,230)", "rgb(186,73,46)", "rgb(78,154,97)" };*/
String title = barData.getTitle();
boolean isHorizontal = barData.getHorizontal();
Object[] xdatas = barData.getBarParamList().getBarName();
Object[] ydatas = barData.getBarParamList().getBarValue();
String legendName = barData.getBarParamList().getLegendName();
Bar bar = new Bar(); //图类别(柱状图)
//title
EnhancedOption option = new EnhancedOption();
option.title(title); //标题
option.title().textStyle().fontSize(15).color("red").fontWeight("bolder");
//工具栏 toolbox
/*option.toolbox().show(true).feature(Tool.mark, //辅助线
Tool.dataView, //数据视图
new MagicType(Magic.line, Magic.bar), //线图,柱状图切换
Tool.restore, //还原
Tool.saveAsImage //保存图片
);
option.toolbox().show(true).feature();*/
//tooltip
option.tooltip().show(true).formatter("{a}<br/> : {c}"); //显示工具提示,设置提示格式
//legend
Legend legend = new Legend();
TextStyle textStyle = new TextStyle();
textStyle.color("red");
textStyle.fontSize(15);
textStyle.fontWeight("bolder");
legend.setData(Collections.singletonList(legendName));
legend.setTextStyle(textStyle);
option.setLegend(legend); //图例
//axisLabel
AxisLabel axisLabel = new AxisLabel();
TextStyle textStyle1 = new TextStyle();
textStyle1.fontSize(15);
textStyle1.fontWeight("bolder");
axisLabel.show(true);
axisLabel.textStyle(textStyle1);
//axisLine
AxisLine axisLine = new AxisLine();
LineStyle lineStyle = new LineStyle();
lineStyle.color("#315070");
lineStyle.width(4);
axisLine.lineStyle(lineStyle);
//xAxis
CategoryAxis category = new CategoryAxis();// 轴分类
category.data(xdatas);// 轴数据类别
category.axisLabel(axisLabel); // x轴文字样式
category.axisLine(axisLine); //x轴样式
//yAxis
ValueAxis valueAxis = new ValueAxis();
valueAxis.axisLabel().show(true).textStyle().fontSize(15).fontWeight("bolder"); //y轴文字样式
valueAxis.axisLine().lineStyle().color("#315070").width(4); //y轴样式
//series
bar.name(legendName);
Normal normal = new Normal();
normal.setShow(true);
if(barData.getHorizontal() == false){
normal.position(Position.inside);
}else {
normal.position(Position.top);
}
normal.color("green");
normal.textStyle().color("red").fontSize(15).fontWeight("bolder");
//bar.setBarWidth("40"); //柱条宽度
//bar.setBarMaxWidth(100); //柱条最大宽度
//bar.setBarMinHeight(10); //柱条最小高度
bar.label().normal(normal);
//循环数据
for(int i = 0;i < xdatas.length;i++){
int data = (int) ydatas[i];
String color = "rgb(2,111,230)";
//类目对应的柱状图
Map<String, Object> map = new HashMap<>(2);
map.put("value", data);
map.put("itemStyle", new ItemStyle().normal(new Normal().color(color)));
bar.data(map);
}
if(isHorizontal){ //横轴为类别,纵轴为值
option.xAxis(category); //x轴
option.yAxis(valueAxis); //y轴
}else { //横轴为值,纵轴为类别
option.xAxis(valueAxis); //x轴
option.yAxis(category); //y轴
}
option.series(bar);
return option;
}
}(8)util模块工具类:这些工具类都是比较常用的,也可以用到其他地方,因此这里我都列举出来
EchartsUtil.java:将option转化为图片编码base64
package com.lhf.springboot.util;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.http.client.ClientProtocolException;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* @ClassName: EchartsUtil
* @Author: liuhefei
* @Description: 生成echarts工具类:将生成的option转化为base64编码
* @Date: 2019/8/15 12:10
*/
public class EchartsUtil {
//private static String url = "http://localhost:6666";
private static final String SUCCESS_CODE = "1";
public static String generateEchartsBase64(String option, String url) throws ClientProtocolException, IOException {
String base64 = "";
if (option == null) {
return base64;
}
option = option.replaceAll("\\s+", "").replaceAll("\"", "'");
// 将option字符串作为参数发送给echartsConvert服务器
Map<String, String> params = new HashMap<>();
params.put("opt", option);
String response = HttpUtil.post(url, params, "utf-8");
// 解析echartsConvert响应
JSONObject responseJson = JSON.parseObject(response);
String code = responseJson.getString("code");
// 如果echartsConvert正常返回
if (SUCCESS_CODE.equals(code)) {
base64 = responseJson.getString("data");
}
// 未正常返回
else {
String string = responseJson.getString("msg");
throw new RuntimeException(string);
}
return base64;
}
}FileUtil.java: 将图片base64编码转化为图片文件
package com.lhf.springboot.util;
import sun.misc.BASE64Decoder;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
/**
* @ClassName: FileUtil
* @Author: liuhefei
* @Description: 将图片base64编码转化为图片
* @Date: 2019/8/15 18:52
*/
public class FileUtil {
public static File generateImage(String base64, String path) throws IOException {
BASE64Decoder decoder = new BASE64Decoder();
File file = new File(path);
String fileName = file.getName();
System.out.println("file = " + file);
//创建临时文件
//File tempFile = File.createTempFile(fileName, ".png");
//FileOutputStream fos = new FileOutputStream(tempFile);*/
try (OutputStream out = new FileOutputStream(path)){
// 解密
byte[] b = decoder.decodeBuffer(base64);
for (int i = 0; i < b.length; ++i) {
if (b[i] < 0) {
b[i] += 256;
}
}
out.write(b);
out.flush();
return file;
}
/* finally {
//关闭临时文件
fos.flush();
fos.close();
try {
Thread.sleep(10000);
tempFile.deleteOnExit();//程序退出时删除临时文件
} catch (InterruptedException e) {
e.printStackTrace();
}
}
*/
}
public static void deleteFile(File file) {
//File file = new File();
String fileName = file.getName();
// 如果文件路径所对应的文件存在,并且是一个文件,则直接删除
if (file.exists() && file.isFile()) {
if (file.delete()) {
System.out.println("删除单个文件" + fileName + "成功!");
} else {
System.out.println("删除单个文件" + fileName + "失败!");
}
} else {
System.out.println("删除单个文件失败:" + fileName + "不存在!");
}
}
}HttpUtil.java:Http请求工具类
package com.lhf.springboot.util;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.*;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
/**
* @ClassName: HttpUtil
* @Author: liuhefei
* @Description: Http工具类
* @Date: 2019/8/15 12:10
*/
public class HttpUtil {
private static Logger logger = LoggerFactory.getLogger(HttpUtil.class);
/**
* 发送post请求
* @param url
* @param params
* @param charset
* @return
* @throws ClientProtocolException
* @throws IOException
*/
public static String post(String url, Map<String, String> params, String charset)
throws ClientProtocolException, IOException {
logger.info("httpPostRequest url : " + url + " paramMap : " + params);
String responseEntity = "";
// 创建CloseableHttpClient对象
CloseableHttpClient client = HttpClients.createDefault();
// 创建post方式请求对象
HttpPost httpPost = new HttpPost(url);
// 生成请求参数
List<NameValuePair> nameValuePairs = new ArrayList<>();
if (params != null) {
for (Entry<String, String> entry : params.entrySet()) {
nameValuePairs.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
}
}
// 将参数添加到post请求中
httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs, charset));
// 发送请求,获取结果(同步阻塞)
CloseableHttpResponse response = client.execute(httpPost);
// 获取响应实体
HttpEntity entity = response.getEntity();
if (entity != null) {
// 按指定编码转换结果实体为String类型
responseEntity = EntityUtils.toString(entity, charset);
}
// 释放资源
EntityUtils.consume(entity);
response.close();
//System.out.println("responseEntity = " + responseEntity);
return responseEntity;
}
public static String postUrl(String url, Map<String, Object> params, String charset) {
String responseEntity = "";
// 创建CloseableHttpClient对象
CloseableHttpClient client = HttpClients.createDefault();
// 创建post方式请求对象
HttpPost httpPost = new HttpPost(url);
// 将参数添加到post请求中
httpPost.setEntity(new StringEntity(JSON.toJSONString(params), charset));
// 发送请求,获取结果(同步阻塞)
CloseableHttpResponse response = null;
try {
response = client.execute(httpPost);
// 获取响应实体
HttpEntity entity = response.getEntity();
if (entity != null) {
// 按指定编码转换结果实体为String类型
responseEntity = EntityUtils.toString(entity, charset);
}
// 释放资源
EntityUtils.consume(entity);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
response.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return responseEntity;
}
/**
* post请求(用于请求json格式的参数)
* @param url
* @param params
* @return
*/
public static String doPost(String url, String params) throws Exception {
logger.info("httpPostRequest url : " + url + " paramMap : " + params);
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpPost httpPost = new HttpPost(url);// 创建httpPost
httpPost.setHeader("Accept", "application/json");
httpPost.setHeader("Content-Type", "application/json");
String charSet = "UTF-8";
StringEntity entity = new StringEntity(params, charSet);
//logger.info("entity = " + entity);
httpPost.setEntity(entity);
CloseableHttpResponse response = null;
try {
response = httpclient.execute(httpPost);
//logger.info("response = " + response);
StatusLine status = response.getStatusLine();
int state = status.getStatusCode();
if (state == HttpStatus.SC_OK) {
HttpEntity responseEntity = response.getEntity();
String jsonString = EntityUtils.toString(responseEntity);
logger.info("post请求响应结果:{}", jsonString);
return jsonString;
}
else{
logger.error("请求返回:"+state+"("+url+")");
}
}
finally {
if (response != null) {
try {
response.close();
} catch (IOException e) {
logger.error(e.getMessage());
}
}
try {
httpclient.close();
} catch (IOException e) {
logger.error(e.getMessage());
}
}
return null;
}
/**
* http发送POST请求
*
* @author J.M.C
* @since 2019年1月16日
* @param url 长连接URL
* @param paramsJson 请求参数body
* @return result 字符串
*/
public static String doPostJson(String url, JSONObject paramsJson) {
logger.info("httpPostRequest url : " + url + " paramMap : " + paramsJson);
if(StringUtils.isBlank(url)){
logger.error("httpPostRequest url is null");
return null;
}
String result = "";
try {
// 创建httpClient实例
CloseableHttpClient httpClient = HttpClients.createDefault();
// 创建httpPost远程连接实例
HttpPost httpPost = new HttpPost(url);
// 配置请求参数实例
RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(10000)// 设置连接主机服务超时时间
.setConnectionRequestTimeout(10000)// 设置连接请求超时时间
.setSocketTimeout(30000)// 设置读取数据连接超时时间
.build();
// 为httpPost实例设置配置
httpPost.setConfig(requestConfig);
// 设置请求头
httpPost.addHeader("content-type", "application/json;charset=utf-8");
// 封装post请求参数
httpPost.setEntity(new StringEntity(paramsJson.toJSONString(), Charset.forName("UTF-8")));
// httpClient对象执行post请求,并返回响应参数对象
// HttpResponse httpResponse = httpClient.execute(httpPost);
CloseableHttpResponse httpResponse = httpClient.execute(httpPost);
// 从响应对象中获取响应内容
result = EntityUtils.toString(httpResponse.getEntity());
//logger.info("result = {}" , result);
} catch (UnsupportedEncodingException e) {
logger.error("URLUtil.httpPostRequest encounters an UnsupportedEncodingException : {}",e);
} catch (IOException e) {
logger.error("URLUtil.httpPostRequest encounters an IOException : {}",e);
}
logger.info("URLUtil.httpPostRequest -----result----: " + result);
return result;
}
public static String send(String url, JSONObject jsonObject,String encoding) throws Exception{
logger.info("httpPostRequest url : " + url + " jsonObject : " + jsonObject);
String body = "";
//创建httpclient对象
CloseableHttpClient client = HttpClients.createDefault();
//创建post方式请求对象
HttpPost httpPost = new HttpPost(url);
String strParam = JSONObject.toJSONString(jsonObject);
//System.out.println("strParam = " + strParam);
//装填参数
StringEntity entity = new StringEntity(strParam, "utf-8");
entity.setContentEncoding(new BasicHeader(HTTP.CONTENT_TYPE, "application/json"));
//设置参数到请求对象中
httpPost.setEntity(entity);
//System.out.println("请求地址:"+ url);
//System.out.println("请求参数:"+ entity.toString());
//设置header信息
//指定报文头【Content-type】、【User-Agent】
//httpPost.setHeader("Content-type", "application/x-www-form-urlencoded");
httpPost.setHeader("Content-type", "application/json");
httpPost.setHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
//执行请求操作,并拿到结果(同步阻塞)
CloseableHttpResponse response = client.execute(httpPost);
//获取结果实体
HttpEntity entityResult = response.getEntity();
if (entityResult != null) {
//按指定编码转换结果实体为String类型
body = EntityUtils.toString(entityResult, encoding);
}
EntityUtils.consume(entityResult);
//释放链接
response.close();
//logger.info("body = {}", body);
return body;
}
public static JSONObject doPost(String url,JSONObject json){
logger.info("httpPostRequest url : " + url + " jsonObject : " + json);
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpPost post = new HttpPost(url);
JSONObject response = null;
try {
StringEntity s = new StringEntity(json.toString());
s.setContentEncoding("UTF-8");
s.setContentType("application/json");//发送json数据需要设置contentType
post.setEntity(s);
HttpResponse res = httpClient.execute(post);
if(res.getStatusLine().getStatusCode() == HttpStatus.SC_OK){
HttpEntity entity = res.getEntity();
String result = EntityUtils.toString(res.getEntity());// 返回json格式:
//logger.info("result = {}", result);
response = (JSONObject) JSONObject.parse(result);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
//logger.info("response = {}", response);
return response;
}
}ImageUtil.java:给图片添加水印
package com.lhf.springboot.util;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
/**
* @ClassName: ImageUtil
* @Author: liuhefei
* @Description: 给图片添加水印工具类
* @Date: 2019/9/10 12:32
*/
public class ImageUtil {
/**
* 给图片添加水印文字、可设置水印文字的旋转角度
* @param logoText 要写入的文字
* @param srcImgPath 源图片路径
* @param newImagePath 新图片路径
* @param degree 旋转角度
* @param color 字体颜色
* @param formaName 图片后缀
*/
public static void markImageByText(String logoText, String srcImgPath, String newImagePath, Integer degree, Color color, String formaName) {
InputStream is = null;
OutputStream os = null;
try {
// 1、源图片
Image srcImg = ImageIO.read(new File(srcImgPath));
BufferedImage buffImg = new BufferedImage(srcImg.getWidth(null),srcImg.getHeight(null), BufferedImage.TYPE_INT_RGB);
// 2、得到画笔对象
Graphics2D g = buffImg.createGraphics();
// 3、设置对线段的锯齿状边缘处理
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.drawImage(srcImg.getScaledInstance(srcImg.getWidth(null), srcImg.getHeight(null), Image.SCALE_SMOOTH), 0, 0, null);
// 4、设置水印旋转
if (null != degree) {
g.rotate(Math.toRadians(degree), buffImg.getWidth()/2,buffImg.getHeight() /2);
}
// 5、设置水印文字颜色
g.setColor(color);
// 6、设置水印文字Font
g.setFont(new Font("宋体", Font.BOLD, buffImg.getHeight() /6));
// 7、设置水印文字透明度
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 0.15f));
// 8、第一参数->设置的内容,后面两个参数->文字在图片上的坐标位置(x,y)
g.drawString(logoText, buffImg.getWidth()/4 , buffImg.getHeight()/2);
// 9、释放资源
g.dispose();
// 10、生成图片
os = new FileOutputStream(newImagePath);
ImageIO.write(buffImg, formaName, os);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (null != is)
is.close();
} catch (Exception e) {
e.printStackTrace();
}
try {
if (null != os)
os.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
markImageByText("霜花似雪","F:\\echarts\\bar1567600917165oNeL.png","F:\\echarts\\new\\bar1567600917135oNeL.png",45,new Color(200,10,1),"png");
}
}RandomUtils.java
package com.lhf.springboot.util;
import java.util.Random;
/**
* @ClassName: RandomUtils
* @Desc: 生成随机字符串
* @Author: liuhefei
* @Date: 2019/2/28 14:16
*/
public class RandomUtils {
public static String getRandomString(int length){
//1. 定义一个字符串(A-Z,a-z,0-9)即62个数字字母;
String str="zxcvbnmlkjhgfdsaqwertyuiopQWERTYUIOPASDFGHJKLZXCVBNM1234567890";
//2. 由Random生成随机数
Random random=new Random();
StringBuffer sb=new StringBuffer();
//3. 长度为几就循环几次
for(int i=0; i<length; ++i){
//从62个的数字或字母中选择
int number=random.nextInt(62);
//将产生的数字通过length次承载到sb中
sb.append(str.charAt(number));
}
//将承载的字符转换成字符串
return sb.toString();
}
public static String getRandomNum(int length){
//1. 定义一个字符串(A-Z,a-z,0-9)即62个数字字母;
String str="1234567890";
//2. 由Random生成随机数
Random random=new Random();
StringBuffer sb=new StringBuffer();
//3. 长度为几就循环几次
for(int i=0; i<length; ++i){
//从10个的数字中选择
int number=random.nextInt(10);
//将产生的数字通过length次承载到sb中
sb.append(str.charAt(number));
}
//将承载的字符转换成字符串
return sb.toString();
}
public static void main(String[] args) {
//这里的32是生成32位随机码,根据你的需求,自定义
String random1 = getRandomString(32);
System.out.println(random1);
String random2 = getRandomNum(32);
System.out.println(random2);
}
}(8)controller模块(API接口)- EchartsController.java
package com.lhf.springboot.controller;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.abel533.echarts.json.GsonOption;
import com.lhf.springboot.common.JsonResult;
import com.lhf.springboot.echarts.option.EchartBar;
import com.lhf.springboot.echarts.option.EchartLine;
import com.lhf.springboot.echarts.option.EchartPie;
import com.lhf.springboot.echarts.pojo.BarData;
import com.lhf.springboot.echarts.pojo.LinesData;
import com.lhf.springboot.echarts.pojo.PieData;
import com.lhf.springboot.util.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.jboss.logging.Logger;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.awt.*;
import java.io.File;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
/**
* @ClassName: EchartsController
* @Author: liuhefei
* @Description: 利用Java代码生成柱状图和折线图
* @Date: 2019/9/26 10:37
*/
@Api(value = "生成Echarts图表API接口", tags = "Echarts图表")
@RequestMapping("/echarts")
@RestController
public class EchartsController {
private final static Logger logger = Logger.getLogger(EchartsController.class);
@Value("${img-url}")
private String imgUrl;
@Value("${img-url-path}")
private String imgUrlPath;
@Value("${request-url}")
private String requestUrl;
@ApiOperation(value = "生成柱状图")
@RequestMapping(value = "/bar", method = RequestMethod.POST)
public JsonResult createBar(@RequestBody BarData barData){
GsonOption option = EchartBar.createBar(barData);
String optionStr = JSONObject.toJSONString(option);
if(optionStr == null || "".equals(optionStr)){
return new JsonResult(-1, "Fail");
}
logger.info("bar-optionStr = " + optionStr);
File oldfile = null;
File newfile = null;
String oldFilePath = null;
String newFilePath = null;
try {
// 根据option参数发起请求,转换为base64
String base64 = EchartsUtil.generateEchartsBase64(optionStr, requestUrl);
long nowStr = Calendar.getInstance().getTimeInMillis();
//图片名
String imageName = "bar"+nowStr+ RandomUtils.getRandomString(4)+".png";
logger.info("bar图片:" + imageName);
oldfile = FileUtil.generateImage(base64, imgUrl+imageName);
newfile = new File(imgUrl+"new"+imageName);
oldFilePath = imgUrl+imageName;
newFilePath = imgUrl+"new"+imageName;
logger.info("file = " + oldfile);
logger.info("oldFilePath = " + oldFilePath);
logger.info("newFilePath = " + newFilePath);
String logoText = "霜花似雪";
//添加水印
ImageUtil.markImageByText(logoText, oldFilePath, newFilePath, -15, new Color(190,190,190), "png");
}catch (Exception e){
logger.error("发生了异常," + e.getMessage());
return new JsonResult(-1, "Fail");
}
return new JsonResult(1, newFilePath, "SUCCESS");
}
}四、插件环境配置
为了生成图片,我们需要借助插件来实现,这里我们以windows环境为主来说明
需要的插件:phantomjs-2.1.1-windows.zip 和 saintlee-echartsconvert-master.zip
(1)phantomjs-2.1.1-windows.zip下载地址:
https://phantomjs.org/download.html
API地址:http://phantomjs.org/api/
(2)saintlee-echartsconvert-master.zip下载地址:(github地址及文档)https://gitee.com/saintlee/echartsconvert/ 说明:此插件有缺陷,生成不了饼图,这个后面再说。
安装配置:
1. 首先需要安装这两个插件
2. 可将phantomjs-2.1.1-windows.zip添加到系统path变量下,我的安装路径:D:\softpack\echarts\phantomjs-2.1.1-windows\bin(此变量加到path变量环境下),也可以不操作此步
3. 配置好后,启动服务,启动cmd命令窗口,命令行输入<phantomjs路径> <EChartsConvert路径> -s -p <服务端口号>
五、结合Swagger文档测试
环境配置完成之后,启动服务,swagger文档:http://localhost:8095/swagger-ui.html
测试数据:
{
"barParamList": {
"barName": [
"A罩杯", "B罩杯", "C罩杯", "D罩杯", "E罩杯", "F罩杯","G罩杯"
],
"barValue": [
43364, 13899, 12000, 2181, 21798, 1796, 1300
],
"legendName": "胸罩图例"
},
"horizontal": true,
"title": "胸罩使用人数"
}效果展示:
由于篇幅太长,分享就到这里,未完待续!
另外推荐为大家推荐几门与Java相关的实战课程,望笑纳!
(1)一站式学习Java网络编程 全面理解BIO/NIO/AIO
发文不易,请多多支持!如果帮助到了你,请点个赞!如果你急需代码,可以联系我!
共同學習,寫下你的評論
評論加載中...
作者其他優質文章



