前言
最近帮大四的弟弟解决了一个毕设的难题,课题内容大概是这样的:“Matlab利用调度算法实现一个车间零部件生产调度任务,最后MTALB会生成一个调用结果甘特图。现在需要通过Java web应用配置程序的入参,以及通过Java自动化操作Matlab进行传参,以及在web端可视化matlab的执行结果。”
之前没有没有做过类似Java操作MATLAB的经验,在实现的过程中遇到好多坑:“java连接不上matlab?”,“JDK版本、Matlab版本有关系吗?”,“如何传递矩阵?”,“结果拿不到?”……
在国内几乎0资料背景下,查阅了不少国外文档、Matlab相关源码,费了很大劲最终才解决,所以记录下,希望可以帮助到有同样问题的同学。
效果
- java web应用启动过程自动拉起MATLAB程序
-
通过web应用连接调用matlab程序,最后执行结果(图片+文字)实现可视化。
image.png
具体实现核心步骤
环境准备
安装JDK(建议1.8)、安装MATLAB
IDEA(开发工具,可更换为其他的)
MySQL(如果需要数据存储、肯定是需要一个RDMS)
驱动包
matlab-control.jar
通过matlab-control实现Java和Matlab混合编程的方法,并将该方法应用于过程控制仿真实验系统的研究和开发。
下载地址:https://www.mvnjar.com/org.n52.matlab/matlab-control/5.0.0/detail.html
下载后需要倒入你的java应用中(导入方法有疑问的话,找度娘吧)
准备matlab程序
main.m demo程序
# 定义一个main函数,它有一个T入参和一个out返回值
function [out] = main(T)
具体实现根据你的需要编写……
java程序
import org.n52.matlab.control.*;
import org.n52.matlab.control.extensions.MatlabNumericArray;
import org.n52.matlab.control.extensions.MatlabTypeConverter;
import org.springframework.util.ResourceUtils;
import java.io.File;
import java.io.FileNotFoundException;
/****
* 模拟java连接matlab
* @Author http://wwww.relaxheart.cn 王琦
*/
public class MatlabTest {
/***
* 指定matlab程序所处的位置,注意是文件夹形式
*/
private static final String matlabFile = "C:\\Users\\Administrator\\Desktop\\matlab";
/***
* matlab启动程序的路径,因为后续通过这个路径来拉起matlab应用程序
*/
private static final String matlabExe = "G:\\MATLAB\\R2018a\\bin\\matlab.exe";
public static void main(String[] args) throws MatlabConnectionException, MatlabInvocationException, FileNotFoundException {
File file = null;
try {
System.out.println(">>>>>>>>>>>>>>>>>>>>> Mtalab文件获取开始...");
file = ResourceUtils.getFile(matlabFile);
} catch (FileNotFoundException e) {
System.out.println("Mtalab文件获取失败!");
}
System.out.println(">>>>>>>>>>>>>>>>>>>>> Mtalab文件获取成功!");
System.out.println(">>>>>>>>>>>>>>>>>>>>> Mtalab建立连接...");
MatlabProxyFactoryOptions options = new MatlabProxyFactoryOptions.Builder()
.setProxyTimeout(300000L)
.setMatlabStartingDirectory(file)
.setHidden(false)
.setMatlabLocation(matlabExe)
.build();
System.out.println(">>>>>>>>>>>>>>>>>>>>> 开始拉起MATLAB程序...");
// 通过matlab代理工厂,创建matlab代理,后续通过代理操作matlab
MatlabProxyFactory factory = new MatlabProxyFactory(options);
MatlabProxy proxy = factory.getProxy();
System.out.println(">>>>>>>>>>>>>>>>>>>>> MATLAB连接成功!");
System.out.println(">>>>>>>>>>>>>>>>>>>>> JAVA 调用 MATLAB 程序...");
// 构造矩阵入参
double[][] in = createMockInputDataArray();
// 注意传递二维以上数组型入参,需要同MatlabNumericArray包装后传递,否则会报错
MatlabNumericArray input = new MatlabNumericArray(in, null);
MatlabTypeConverter converter = new MatlabTypeConverter(proxy);
converter.setNumericArray("in", input);
// 调用matlab程序
proxy.eval("[out]=main(in,path)");
// 获取返回值
double[][] out = converter.getNumericArray("out").getRealArray2D();
System.out.println(">>>>>>>>>>>>>>>>>>>>> java invoke matlab success");
// 断开连接
proxy.exit();
}
/***
* 构造一个输入参数
* @return
*/
private static double[][] createMockInputDataArray() {
String p = "1 1 2 3 6 3;" +
"1 2 2 8 16 1; " +
"1 3 2 9 18 2; " +
"1 4 2 2 4 4;" +
" 1 5 2 3 6 6;" +
" 1 6 2 2 4 5; " +
"2 1 3 6 18 2; " +
"2 2 3 8 24 3; " +
"2 3 3 2 6 6; ";
String[] p1 = p.split(";");
double[][] input = new double[p1.length][6];
for (int i = 0; i < p1.length; i++) {
String[] num = p1[i].split("\t");
input[i][0] = Integer.parseInt(num[0].trim());
input[i][1] = Integer.parseInt(num[1].trim());
input[i][2] = Integer.parseInt(num[2].trim());
input[i][3] = Integer.parseInt(num[3].trim());
input[i][4] = Integer.parseInt(num[4].trim());
input[i][5] = Integer.parseInt(num[5].trim());
}
return input;
}
}
--- 上面是一个Java连接matlab示例,那Javaweb应用具体如何连接 ---
我的web应用选用的spring boot框架,在上面的基础上我需要做一些调整。我不希望每次调用都需要拉起一个matlab。
spring boot application.xml
#matlab 文件路径
matlab.file.path=C:\\Users\\Administrator\\Desktop\\matlab
#matlab 启动程序 路径
matlab.exe.path=G:\\MATLAB\\R2018a\\bin\\matlab.exe
MatlabConfiguration.java 创建一个matlabProxy bean
import com.digitization.util.DateUtil;
import org.n52.matlab.control.MatlabConnectionException;
import org.n52.matlab.control.MatlabProxy;
import org.n52.matlab.control.MatlabProxyFactory;
import org.n52.matlab.control.MatlabProxyFactoryOptions;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.ResourceUtils;
import java.io.File;
import java.io.FileNotFoundException;
/****
* @Author http://wwww.relaxheart.cn 王琦
*/
@Configuration
public class MatlabConfiguration {
@Value("${matlab.file.path}")
private String matlabFilePath;
@Value("${matlab.exe.path}")
private String matlabExePath;
@Bean(name = "matlabProxy")
public MatlabProxy createFactory() throws MatlabConnectionException {
File file = null;
try {
System.out.println(DateUtil.getDateStr()+" -------------------------> MATLAB文件获取开始...");
file = ResourceUtils.getFile(matlabFilePath);
} catch (FileNotFoundException e) {
System.out.println(DateUtil.getDateStr()+" -------------------------> MATLAB文件获取失败!");
}
System.out.println(DateUtil.getDateStr()+" -------------------------> MATLAB文件获取成功!");
System.out.println(DateUtil.getDateStr()+" -------------------------> JAVA与MATLAB开始建立连接...");
MatlabProxyFactoryOptions options = new MatlabProxyFactoryOptions.Builder()
.setProxyTimeout(300000L)
.setMatlabStartingDirectory(file)
.setHidden(false)
.setMatlabLocation(matlabExePath)
.build();
System.out.println(DateUtil.getDateStr()+" -------------------------> 开始拉起MATLAB应用程序...");
MatlabProxyFactory factory = new MatlabProxyFactory(options);
MatlabProxy proxy = factory.getProxy();
System.out.println(DateUtil.getDateStr()+" -------------------------> MATLAB应用程序已经启动!");
System.out.println(DateUtil.getDateStr()+" -------------------------> JAVA与MATLAB开始建立连接成功!");
return proxy;
}
}
在再具体需要的时候只需要注入这个matlabProxy bean即可
/****
* @Author http://wwww.relaxheart.cn 王琦
*/
@Service
public class MatlabService {
@Autowired
private MatlabProxy matlabProxy;
public void task() {
……略
// 调用Matlab程序
matlabProxy.eval("[out]=main(in)");
……略
}
完结!!!
最后欢迎浏览我的个人兴趣分享网站: http://www.wangqi94.com
网友评论