背景介绍
由于系统需要从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();