最近,公司的一個項目要結合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();
}
}
}
有更好的辦法,麻煩大神留言一下。