1. 程式人生 > >springboot整合kettle, 訪問不到ktr檔案

springboot整合kettle, 訪問不到ktr檔案

背景介紹

由於系統需要從sql server 遠端資料庫抓取資料儲存到當前資料庫(mysql)中,所以採用了kettle來進行資料抽取。使用spoon圖形化工具進行ktr檔案的編寫。測試通過後,想整合進專案中,然而遇到以下問題:

  • 首先,kettle的jar包引入,在一些共有的maven庫中找不到相關jar包。所以從spoon客戶端中,拷貝出jar包,然後加入本地maven庫。主要包括kettle-core、kettle-engine、metastore、commons-vfs2、commons-lang。
mvn install:install-file -DgroupId=pentaho-kettle 
-DartifactId=kettle-core
-Dversion=7.1.0.0-12
-Dpackaging=jar -Dfile=pentaho-kettle.jar

  • 其次,將專案部署到linux伺服器後,發現kettle讀不到ktr檔案,檢視堆疊資訊,發現路徑正常。
org.pentaho.di.core.exception.KettleXMLException: 
Unable to read file [file:///pws.jar!/BOOT-INF/classes!/kettle/userInfo.ktr]
Could not read from "file:///pws.jar!/BOOT-INF/classes!/kettle/userInfo.ktr" because it is a not a file.

	at org.pentaho.di.core.xml.XMLHandler.loadXMLFile(XMLHandler.java:561)
	at org.pentaho.di.core.xml.XMLHandler.loadXMLFile(XMLHandler.java:540)
	at org.pentaho.di.trans.TransMeta.<init>(TransMeta.java:2742)
	at org.pentaho.di.trans.TransMeta.<init>(TransMeta.java:2710)
	at org.pentaho.di.trans.TransMeta.<init>(TransMeta.java:2687)
	at org.pentaho.di.trans.TransMeta.<init>(TransMeta.java:2667)
	at org.pentaho.di.trans.TransMeta.<init>(TransMeta.java:2632)
	at org.pentaho.di.trans.TransMeta.<init>(TransMeta.java:2595)
	at cn.pioneer.pws.service.impl.KettleServiceImpl.synchronizationInfo(KettleServiceImpl.java:50)
	at cn.pioneer.pws.service.impl.KettleServiceImpl.synchroUserData(KettleServiceImpl.java:29)
	at cn.pioneer.pws.controller.KettleController.synchroUserData(KettleController.java:21)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:209)
	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:136)
	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:877)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:783)
	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:991)
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:925)
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:974)
	at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:877)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:661)
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:851)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at com.alibaba.druid.support.http.WebStatFilter.doFilter(WebStatFilter.java:123)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:96)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at cn.pioneer.pws.util.PageFilter.doFilter(PageFilter.java:46)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:496)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:803)
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:790)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1468)
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.lang.Thread.run(Thread.java:748)
Caused by: org.apache.commons.vfs2.FileNotFoundException: Could not read from "file:///pws.jar!/BOOT-INF/classes!/kettle/userInfo.ktr" because it is a not a file.
	at org.apache.commons.vfs2.provider.AbstractFileObject.getInputStream(AbstractFileObject.java:1315)
	at org.apache.commons.vfs2.provider.DefaultFileContent.getInputStream(DefaultFileContent.java:396)
	at org.pentaho.di.core.vfs.KettleVFS.getInputStream(KettleVFS.java:267)
	at org.pentaho.di.core.xml.XMLHandler.loadXMLFile(XMLHandler.java:559)
	... 62 common frames omitted
Caused by: java.io.FileNotFoundException: /pws.jar!/BOOT-INF/classes!/kettle/userInfo.ktr (No such file or directory)
	at java.io.FileInputStream.open0(Native Method)
	at java.io.FileInputStream.open(FileInputStream.java:195)
	at java.io.FileInputStream.<init>(FileInputStream.java:138)
	at org.apache.commons.vfs2.provider.local.LocalFile.doGetInputStream(LocalFile.java:209)
	at org.apache.commons.vfs2.provider.AbstractFileObject.getInputStream(AbstractFileObject.java:1307)
	... 65 common frames omitted

問題分析

  • 首先,由於在idea中專案能夠正常執行,但在伺服器上面執行失敗。第一反應是window與linux的差異造成的。然後在本機以java -jar xxx 方式執行,同樣報錯。
 		String filePath =  this.getClass().getClassLoader().getResource("kettle/userInfo.ktr").getPath();
 		KettleEnvironment.init();
        TransMeta transMeta = new TransMeta(filePath);
        Trans trans = new Trans(transMeta);
        if (!StringUtils.isNullOrEmpty(department)){
            trans.setVariable("department", department);
        }
        trans.execute(null); // You can pass arguments instead of null.
        trans.waitUntilFinished();

其中,String filePath = this.getClass().getClassLoader().getResource("kettle/userInfo.ktr").getPath();獲取資原始檔ktr的路徑。 TransMeta transMeta = new TransMeta(filePath);將路徑傳遞給kettle內庫中的處理類,進行ktr檔案的解析及執行。 而問題在於以java -jar 方式執行程式時,由於專案沒有解壓,程式不能訪問未解壓的資原始檔

解決方案

  • 將字串的路徑引數改成流(InputStream)。檢視kettle原始碼發現, TransMeta transMeta = new TransMeta(filePath);內部連續多次呼叫其他帶引數方法,且新增引數都為null,即引數可以忽略。
		InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("/kettle/userInfo.ktr");
		KettleEnvironment.init();
        TransMeta transMeta = new TransMeta(inputStream, null, true, null,null);
        Trans trans = new Trans(transMeta);
        if (!StringUtils.isNullOrEmpty(department)){
            trans.setVariable("department", department);
        }
        trans.execute(null); // You can pass arguments instead of null.
        trans.waitUntilFinished();