在Java Web开发过程中,经常会遇到需要将数据分析的结果很直观的展现给用户,这就要用到数据统计图(柱形图、饼图、折线图),对于一些简单的统计图,可以推荐使用jfreechart,是第三方开源的框架。但是对于复杂的图形,使用这些框架就不太合适了,比如
要求展现的图比较复杂,具体需求这边不阐述,如果使用Matlab作图,就很方便,但是在使用的过程中会遇到很多的坑,因为这个作图功能,让我将生产服务器从Linux到Windows server 2012再到Linux,最后换为Linux是因为在Windows服务器上生成的图片全是黑的,没要找到有效的解决办法。
Matlab是专业的数学软件,主要包括MATLAB和Simulink两大部分。本文主要讲述在Java程序中如何使用Matlab程序、Linux中安装MCR(Matlab Compiler Runtime,Matlab运行时环境)以及在使用过程中遇到的一些问题的解决办法,并以R2016a版本的Matlab为例,以此分享给对Matlab感兴趣的同学。
一、编写Matlab脚本
举个简单的例子,利用Matlab画一个正弦函数(y=sin(x))的图像。
function plotSin()
x=-3.14:0.01:3.14;
y=sin(x);
plot(x,y);
ylabel('y=sin(x)图像');
title('Java调用Matlab作正弦函数图像');
保存,并执行函数脚本:
然后稍微修改下plotSin函数:
function plotSin(x, savePath)
%savePath图片保存地址
%x=-3.14:0.01:3.14;
y=sin(x);
plot(x,y);
ylabel('y=sin(x)图像');
title('Java调用Matlab作正弦函数图像');
set(gcf,'visible','off')
set(gcf, 'PaperPositionMode', 'manual');
set(gcf, 'PaperUnits', 'points');
set(gcf, 'PaperPosition', [0 0 500 600]);
saveas(gcf,savePath) ;
下面将脚本plotSin函数编译并打包成Jar包,值得注意的是,打包编译的 JDK版本不能超过1.7,所以事先检查环境变量,如果是1.8以上的,请修改成1.7或以下版本,编译后是可以在1.7版本以上的环境下执行的。在Matlab命令窗口输入deploytool,并回车:
选择Library Compile,在弹出的窗口按如下步骤操作
1:选择Java Package;
2:输入包名(Library name);
3:输入类路径(Namespase);
4:输入类名(Class name,java类,在后边java代码中会用);
5:点击加号按钮,添加刚才的plotSin.m文件;
6:点击Package打包。
打包需要一定过程,接下来就是耐心的等待了。
打包成功后在for_redistribution_files_only路径下找到plot.jar,以及在Matlab安装目录R2016a\toolbox\javabuilder\jar 找到javabuilder.jar。
二、如何使用
将上述两个包引入项目中,接下来就是在Java程序中使用了,直接上代码:
package com.seage;
import com.mathworks.toolbox.javabuilder.MWArray;
import com.mathworks.toolbox.javabuilder.MWClassID;
import com.mathworks.toolbox.javabuilder.MWComplexity;
import com.mathworks.toolbox.javabuilder.MWNumericArray;
import com.mathworks.toolbox.javabuilder.internal.MWComponentInstance;
import com.seage.plotsin.PlotSin;
/**
* Title: PlotSinMain
* 描述:
* @author wangzb
* @Date 2018-8-21 上午9:32:15
*/
public class PlotSinMain {
/**
* 画图
* @param savePath 图片保存地址
*/
private static voit plot(String savePath){
PlotSin plot = null;//打包是定义的类
MWNumericArray x = null; // 存放x值的数组
try{
int size = (int) (6.28/0.01 + 1);
/*
* 初始化数组,定义一个一维数组,其中:
* MWClassID.DOUBLE定义数据类型为double
* MWComplexity.REAL定义数据为实数
*/
int[] dims = {1,size};
x = MWNumericArray.newInstance(dims, MWClassID.DOUBLE,MWComplexity.REAL);
int index = 1;
for (double i=-3.14;i<=3.14;i=i+0.01){
x.set(index++,i);
}
plot = new PlotSin();
String savePath = "E:\\seage\\1.png";
//调用画图函数
plot.plotSin(x,savePath);
plot.waitForFigures();
} catch(Exception e){
e.printStackTrace();
} finally{
//关闭资源
dispose(plot, x);
}
}
/**
* 关闭资源
* @param plot 画图对象
* @param mwArrays 画图参数数组对象
*/
public static void dispose(MWComponentInstance plot, MWArray... mwArrays){
if(plot!=null){
plot.dispose();
}
for(MWArray mwArray : mwArrays){
if(mwArray!=null){
MWArray.disposeArray(mwArray);
}
}
}
public static void main(String[] args) {
String savePath = "E:\\seage\\1.png";
plot(savePath);
}
}
使用起来并不难,但是实际生产中,业务量比较复杂,往往需要生成图片不止一张,甚至在并发的情况下,需要同时生成几百张图片,所以必须注意以下两点:
1、在生成每一张图片后都需要调用dispose(plot, x)方法关流,否则会消耗大量内存,浪费大量的资源;
2、int[] dims = {row,col};其中行row以及col避免出现负数或者封装Intger的null值,否则会导致tomcat内存溢出,造成tomcat死机。
最后,将上述代码打包成可执行的jar文件,以便在已成功安装MCR环境下的Linux系统中测试。
三、Linux中使用Matlab
众所周知,在企业级项目中,大部分系统还是使用的是Linux,单纯的在Windows系统中正确使用了Matlab是完全不够的,Matlab提供了MCR,可用于在未安装 MATLAB 的计算机上执行编译后的 MATLAB 应用程序或组件。执行如下命令下载MCR安装包:
1:下载安装包
[root@EM0103170701 matlab]# wget http://ssd.mathworks.com/supportfiles/downloads/R2016a/deployment_files/R2016a/installers/glnxa64/MCR_R2016a_glnxa64_installer.zip
2:解压安装包
[root@EM0103170701 matlab]# unzip MCR_R2016a_glnxa64_installer zip -d MCR_R2016a_glnxa64_installer
3:进入解压后的目录
[root@EM0103170701 matlab]# cd MCR_R2016a_glnxa64_installer
4:安装
[root@EM0103170701 matlab]# ./install -mode silent -agreeToLicense yes
当出现下面语句,表示安装成功。
Exitingwith status 0
End – Successful.
Finished
5、配置环境变量
export MCR_HOME=/usr/local/MATLAB/MATLAB_Runtime
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$MCR_HOME/v901/runtime/glnxa64:$MCR_HOME/v901/sys/os/glnxa64:$MCR_HOME/v901/sys/java/jre/glnxa64/jre/lib/amd64/headless:$MCR_HOME/v901/sys/java/jre/glnxa64/jre/lib/amd64/server:$MCR_HOME/v901/sys/java/jre/glnxa64/jre/lib/amd64
6、测试
将第二步最后打包的jar文件拷贝到linux服务器,运行如下命令
[root@EM0103170701 matlab]# jar -jar plotsin.jar
如果执行成功则万事大吉,下面将列出我在使用过程中出现的错误,以及解决办法。
6.1、无法加载libmwosgserver.so
Can't load '/usr/local/MATLAB/MATLAB_Runtime/v901/bin/glnxa64/libmwosgserver.so'
在环境变量的LD_LIBRARY_PATH下引入:
$MCR_HOME/v901/bin/glnxa64:$MCR_HOME/v901/sys/opengl/lib/glnxa64
6.2、在tomcat下运行时出现异常NoClassDefFoundError MWClassID.class,这种错误一般原因很多,很难找到真正的原因,类明显是在的,但就是无法找到,实在让人头疼。这个错误需要区别于ClassNotfoundException,事实上这两个错误是完全不同的,NoClassDefFoundError是在运行时,根据你提供的类名,在classpath中找不到对应的类进行加载,而ClassNotFoundException是在编译的时候在classpath中找不到对应的类而发生的错误。
经查找发现,启动tomcat的方式为:service tomcat start.以这种方式启动就会出现NoClassDefFoundError MWClassID.class异常,而在tomcat的bin目录下使用./start启动,或者在/etc/init.d下使用./tomcat start启动也则没有问题。
执行命令:cat /sbin/service,打开service文件,发现service启动方式为:
env -i PATH="$PATH" TERM="$TERM" "${SERVICEDIR}/${SERVICE}" ${OPTIONS}
然后,执行命令which env 找到env在/bin目录下,并执行env --help或者env -?:
用法:env [选项]... [-] [名称=值]... [命令 [参数]...]
设置一个环境变量的"名称=键值"并运行命令。
-i, --ignore-environment 以无定义的环境启动
-0, --null 以空字符而非新行符结束每一输出行
-u, --unset=名称 从当前环境中撤消一个变量
--help 显示此帮助信息并退出
--version 显示版本信息并退出
单纯的 - 意味着 -i。如果没有命令,则打印结果环境。
请向bug-coreutils@gnu.org 报告env 的错误
GNU coreutils 项目主页:<http://www.gnu.org/software/coreutils/>
GNU 软件一般性帮助:<http://www.gnu.org/gethelp/>
请向<http://translationproject.org/team/zh_CN.html> 报告env 的翻译错误
要获取完整文档,请运行:info coreutils 'env invocation'
-i命令是以无定义的环境启动,所以在/etc/init.d/tomcat脚本文件中重新加入第五步的环境变量。然后使用service tomcat start就不再冒错了。
6.3、在Linux系统中生成的图片出现中文乱码,一开始我以为是Matlab程序编码的问题,在网上找了很多办法去改变Matlab的编码,但都没有用,最终发现是Linux系统中没有安装中文支持,使用下面命令安装中文支持,问题解决。
yum -y groupinstall chinese-support