最近,公司的一个项目要结合matlab 做一些算法预测。传递的参数大部分是矩阵结构,在java中可以用二维数组表示。
首先百度搜索资料,尝试过matlab 的.m文件打包成jar的形式,这个是可行的,只不过jar的形式受限比较大,jdk运行版本要求严格,而且后期的.m文件的修改,要重新打包,增加运维成本。
最终参照这篇博客的经验,,https://blog.csdn.net/qq_27731689/article/details/81068516。其实使用的是matlabcontrol api。
因我的是web项目,防止每次计算都会启动matlab,创建一个Listener来代理;只要springboot启动后,后面就无需在次启动,Listener代码结构如下:
MatlabListener.java
import java.io.File;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import matlabcontrol.MatlabConnectionException;
import matlabcontrol.MatlabInvocationException;
import matlabcontrol.MatlabProxy;
import matlabcontrol.MatlabProxyFactory;
import matlabcontrol.MatlabProxyFactoryOptions;
public class MatlabListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
File file = new File("D:\\m");//m文件所在根目录,可以任意,并不是m文件的绝对路径噢。
MatlabProxyFactoryOptions options = new MatlabProxyFactoryOptions.Builder()
.setProxyTimeout(300000L)
.setMatlabStartingDirectory(file)
.setHidden(false)
.build();
MatlabProxyFactory factory = new MatlabProxyFactory(options);
MatlabProxy proxy = null;
try {
proxy = factory.getProxy();
}catch (MatlabConnectionException e) {
e.printStackTrace();
}
sce.getServletContext().setAttribute("proxy", proxy);
System.out.println("matlab连接成功");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
MatlabProxy proxy=(MatlabProxy) sce.getServletContext().getAttribute("proxy");
try {
proxy.exit();
} catch (MatlabInvocationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("matlab销毁");
}
}
MatlabConfig.java //@Configuration springBoot 启动时加载运行
import java.util.EventListener;
import org.jeecg.listener.MatlabListener;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MatlabConfig {
@Bean
public ServletListenerRegistrationBean myListener(){
ServletListenerRegistrationBean<EventListener> servletListenerRegistrationBean = new ServletListenerRegistrationBean<>();
servletListenerRegistrationBean.setListener(new MatlabListener());
return servletListenerRegistrationBean;
}
}
代码结构:
只要完成编写上方的两个文件,就可以在web中连接matlab进行计算。那么怎么调用matlab的方法呢,一维数组参数可以参照https://blog.csdn.net/qq_27731689/article/details/81068516,我这里是二维数组为参数的demo
首先准备.m文件demo
function [out,out2] = demo(in,in2)
out = 2*in;
out2=3*in2;
end
java 调用代码:
package org.jeecg.modules.emb.controller;
import javax.servlet.ServletContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import matlabcontrol.MatlabProxy;
import matlabcontrol.extensions.MatlabNumericArray;
import matlabcontrol.extensions.MatlabTypeConverter;
public class MatlabTestController {
@Autowired
private ServletContext servletContext;
@PostMapping(value = "/calculateStarts")
public void calculateStarts() {
try {
MatlabProxy proxy=(MatlabProxy)servletContext.getAttribute("proxy");
double[][] in = {{1,1},{2,2}};//第1个二维矩阵入参
double[][] in2 = {{2,2},{3,3}};//第2个二维矩阵入参
MatlabNumericArray input = new MatlabNumericArray(in,null);
MatlabNumericArray input2 = new MatlabNumericArray(in2,null);
MatlabTypeConverter mtc=new MatlabTypeConverter(proxy);
mtc.setNumericArray("in", input);
mtc.setNumericArray("in2", input2);
proxy.eval("[out,out2]=demo(in,in2)");
//计算结果
double[][] out=mtc.getNumericArray("out").getRealArray2D();
double[][] out2=mtc.getNumericArray("out2").getRealArray2D();
} catch (Exception e) {
e.printStackTrace();
}
}
}
有更好的办法,麻烦大神留言一下。