技术背景:
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-8import pymysqlimport matplotlib.pyplot as pltimport matplotlibimport sysdef 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.0362if(b[0:1] == 'a'):d = 0.0432if(b[0:1] == 'n'):d = 0.2666if(b[0:1] == 'v'):d = 0.0850if(b[0:1] == 'g'):d = 0.5691c2.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")@ResponseBodypublic 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♪(・ω・)ノ