技术背景:
1. SpringBoot + JPA
2. 前端使用Bootstrap
3. 需要将后台数据生成柱状图、折线图 在前台显示
问题:
如果将后台数据生成柱状图、折线图在前台显示
遇坑:
1. 使用Echart进行图片显示,后台传递数据,前台使用jquery显示
使用这种方法发现,网上大多数教程为静态Echart的显示,不符合需求,动态显示没有研究出来,且这种方法比较具有局限性,由于我做的项目以数据可视化为主,Echart可以表现的图形有限,且作为一个后端开发..前端不擅长
解决方法:
1. Java调用Python,传递数据,使用Python绘制图片并进行图片保存,保存至指定路径
2. Java前端每次点击按钮,jquery获取图片路径,在前台进行显示
Java调用Python数据并传值:
public void startCharaChange(HttpServletRequest request , Long fileId) throws Exception {
String[] arg2 = new String[] { "python", "D:\\\\Software\\\\python3.7\\\\pie3.py", String.valueOf(fileId)};
Process pr2=Runtime.getRuntime().exec(arg2);
}
此处值的传递,我使用了数据库保存数据,并向Python程序传递Id, Python再查询数据库中的相关数据,读取后绘制图片(范例为饼图)
Python绘制饼图:
# encoding: utf-8
import pymysql
import matplotlib.pyplot as plt
import matplotlib
import sys
def paint(var1):
matplotlib.rcParams['font.sans-serif']=['SimHei'] #指定默认字体 SimHei为黑体#连接数据库
db = pymysql.connect("localhost","root","123456","test")
db2 = pymysql.connect("localhost","root","123456","test")
#使用cursor()方法创建一个游标对象
cursor = db.cursor()
sql2="select word,chara from keyword where file_id=%s"
c2=[]
word=[]
cursor.execute(sql2,int(var1))
# 获取所有记录列表
course = cursor.fetchall()
for row in course:
a=row[0]
b=row[1]
word.append(a)
d=0.0362
if(b[0:1] == 'a'):
d = 0.0432
if(b[0:1] == 'n'):
d = 0.2666
if(b[0:1] == 'v'):
d = 0.0850
if(b[0:1] == 'g'):
d = 0.5691
c2.append(d)
plt.axes(aspect = 1)
plt.pie(x=c2,labels=word,autopct='%.0f%%')
plt.savefig('E:\\testDataStore\\pics\\piechara.jpg')
#plt.show()
#关闭游标和数据库的连接
cursor.close()
db.close()
print(var1)
if __name__ == '__main__':
#for i in range(1, len(sys.argv)):
paint(sys.argv[1])
#paint(114)
此时已经在Java调用该Python程序后,已经在指定路径输出了图片,所以,在后台点击按钮时也要同时获取该图片:
设置获取方法:
@RequestMapping(value = "/seekPieChara")
@ResponseBody
public String seekPieChara(HttpServletRequest request,
HttpServletResponse response, Model model) {
// response.setContentType("image/*");
FileInputStream fis = null;
OutputStream os = null;
try {
fis = new FileInputStream(new File("E:\\testDataStore\\pics\\piechara.jpg"));
os = response.getOutputStream();
int count = 0;
byte[] buffer = new byte[1024 * 8];
while ((count = fis.read(buffer)) != -1) {
os.write(buffer, 0, count);
os.flush();
}
} catch (Exception e) {
e.printStackTrace();
}
try {
fis.close();
os.close();
} catch (IOException e) {
e.printStackTrace();
}
return "ok";
}
同时,在jquery中设置点击事件,保证点击后该前端数据源调用上述的图片获取方法,以在前端页面进行显示:
//all
$("#allChange").on("click",function () {
var data = getData();
console.log(data);
$("#loading").showLoading();
$.ajax({
type : 'POST',
url : '/formatChange/startAll',
data : JSON.stringify({'data' : data}),
dataType : "text",
contentType : "application/json",
success : function (response) {
$("#loading").hideLoading();
response = JSON.parse(response);
if (response.errorCode !== 0) {
toastr.error('转化失败 [' + response.errorInfo + ']');
}else{
$('#piechara').attr('src','../seekPieChara.do')
toastr.success('转化成功');
}
},
error : function () {
$("#loading").hideLoading();
toastr.error('请求发送失败');
}
});
});
由此,可以在前端获取后台生成的图像,并进行显示,同时也具有较好的延展性,因为Python的图像绘制更加专业,可以调用wordcloud、matlabplotlib包等。
注:
由于生成图片和读图片存在时间差,这里我一般用
Thread.sleep(5000);
来缓和时间差,保证一定可以取到最新图片。
可以根据实际情况设置等待时间,或者有更好地方法也欢迎大家告诉我Thanks♪(・ω・)ノ