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();
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章