搭建图片服务器《bug》- bug1 - java.lang.ClassNotFoundException: org.apache.commons.net.ftp.FTPClient

五月 30, 2018 9:04:23 下午 org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet [springmvc] in context with path [/taotao-manager-web] threw exception [Handler processing failed; nested exception is java.lang.NoClassDefFoundError: org/apache/commons/net/ftp/FTPClient] with root cause
java.lang.ClassNotFoundException: org.apache.commons.net.ftp.FTPClient
	at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1702)
	at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1547)
	at com.taotao.common.utils.FtpUtil.uploadFile(FtpUtil.java:19)
	at com.taotao.service.impl.PictureServiceImpl.uploadPicture(PictureServiceImpl.java:38)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:601)
	at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
	at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:98)
	at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:262)
	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
	at $Proxy40.uploadPicture(Unknown Source)
	at com.taotao.controllers.PictureController.upload(PictureController.java:27)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:601)
	at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:214)
	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132)
	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:748)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:689)
	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:83)
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:945)
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:876)
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:931)
	at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:833)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:647)
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:807)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:108)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
	at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
	at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1041)
	at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:603)
	at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
	at java.lang.Thread.run(Thread.java:722)
 
package com.taotao.common.utils;
 
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
 
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
 
public class FtpUtil {
 
	public static boolean uploadFile(String host, int port, String username, String password, String basePath,
			String filePath, String filename, InputStream input) {
		boolean result = false;
		FTPClient ftp = new FTPClient();
		try {
			int reply;
			ftp.connect(host, port);
			ftp.login(username, password);
			reply = ftp.getReplyCode();
			if (!FTPReply.isPositiveCompletion(reply)) {
				ftp.disconnect();
				return result;
			}
			if (!ftp.changeWorkingDirectory(basePath+filePath)) {
				String[] dirs = filePath.split("/");
				String tempPath = basePath;
				for (String dir : dirs) {
					if (null == dir || "".equals(dir)) continue;
					tempPath += "/" + dir;
					if (!ftp.changeWorkingDirectory(tempPath)) {
						if (!ftp.makeDirectory(tempPath)) {
							return result;
						} else {
							ftp.changeWorkingDirectory(tempPath);
						}
					}
				}
			}
			ftp.setFileType(FTP.BINARY_FILE_TYPE);
			if (!ftp.storeFile(filename, input)) {
				return result;
			}
			input.close();
			ftp.logout();
			result = true;
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (ftp.isConnected()) {
				try {
					ftp.disconnect();
				} catch (IOException ioe) {
				}
			}
		}
		return result;
	}
	
	public static boolean downloadFile(String host, int port, String username, String password, String remotePath,
			String fileName, String localPath) {
		boolean result = false;
		FTPClient ftp = new FTPClient();
		try {
			int reply;
			ftp.connect(host, port);
			ftp.login(username, password);
			reply = ftp.getReplyCode();
			if (!FTPReply.isPositiveCompletion(reply)) {
				ftp.disconnect();
				return result;
			}
			ftp.changeWorkingDirectory(remotePath);
			FTPFile[] fs = ftp.listFiles();
			for (FTPFile ff : fs) {
				if (ff.getName().equals(fileName)) {
					File localFile = new File(localPath + "/" + ff.getName());
 
					OutputStream is = new FileOutputStream(localFile);
					ftp.retrieveFile(ff.getName(), is);
					is.close();
				}
			}
 
			ftp.logout();
			result = true;
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (ftp.isConnected()) {
				try {
					ftp.disconnect();
				} catch (IOException ioe) {
				}
			}
		}
		return result;
	}
 
}

控制台显示出错的地方在FileClient fileClient = new FileClient();是在Service层找不到FileClient的类。FileClient所在的依赖是在taotao-common工程中导入的,taotao-manager-service中导入了taotao-common工程作为依赖并导入了其它service工程需要的依赖。我在web工程中是写过一个测试类的,在测试类中我成功完成了上传,但是写成Service方法就出现了问题,很是苦恼。

当我单独对Service工程进行install,控制台的代码如下:

[INFO] Scanning for projects...
[INFO] 
[INFO] -----------------< com.taotao:taotao-manager-service >------------------
[INFO] Building taotao-manager-service 0.0.1-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[WARNING] The POM for com.taotao:taotao-common:jar:0.0.1-SNAPSHOT is invalid, transitive dependencies (if any) will not be available, enable debug logging for more details
[WARNING] The POM for com.taotao:taotao-manager-dao:jar:0.0.1-SNAPSHOT is invalid, transitive dependencies (if any) will not be available, enable debug logging for more details
[INFO] 
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ taotao-manager-service ---
[WARNING] Using platform encoding (GBK actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] Copying 0 resource
[INFO] 
[INFO] --- maven-compiler-plugin:3.5.1:compile (default-compile) @ taotao-manager-service ---
[INFO] Nothing to compile - all classes are up to date
[INFO] 
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ taotao-manager-service ---
[WARNING] Using platform encoding (GBK actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] Copying 0 resource
[INFO] 
[INFO] --- maven-compiler-plugin:3.5.1:testCompile (default-testCompile) @ taotao-manager-service ---
[INFO] Nothing to compile - all classes are up to date
[INFO] 
[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ taotao-manager-service ---
[INFO] 
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ taotao-manager-service ---
[INFO] Building jar: E:\maven\taotao-parent\taotao-manager\taotao-manager-service\target\taotao-manager-service-0.0.1-SNAPSHOT.jar
[INFO] 
[INFO] --- maven-install-plugin:2.4:install (default-install) @ taotao-manager-service ---
[INFO] Installing E:\maven\taotao-parent\taotao-manager\taotao-manager-service\target\taotao-manager-service-0.0.1-SNAPSHOT.jar to E:\apache-maven-3.5.3\repository\com\taotao\taotao-manager-service\0.0.1-SNAPSHOT\taotao-manager-service-0.0.1-SNAPSHOT.jar
[INFO] Installing E:\maven\taotao-parent\taotao-manager\taotao-manager-service\pom.xml to E:\apache-maven-3.5.3\repository\com\taotao\taotao-manager-service\0.0.1-SNAPSHOT\taotao-manager-service-0.0.1-SNAPSHOT.pom
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 8.875 s
[INFO] Finished at: 2018-05-30T21:53:30+08:00
[INFO] ------------------------------------------------------------------------

上面的过程看似是BUILD SUCCESS,没有什么问题。但是我无意间注意到上面的两行标蓝的Warning:(我发现颜色在代码段显示不出来,这两行警告就在“-------jar-----”那一行的下面很近的地方)

意思就是common工程和dao工程中的pom在Service中是无效的,一些依赖是不能被传递过来的,所以在Service中不能直接找到common-net这个依赖。所以我在service层也添加了FTPClient的依赖,就成功解决了问题。

但是具体什么样的依赖是不能被传递需要重新导入的我还不清楚,烦请知道的小伙伴评论告诉我~

感觉是一次比较有意思的经历了,从控制台的警告中发现了问题~~

---------------------------------------华丽丽的分割线------------------------

现在我有了一种理解,,大致就是:

package com.taotao.common.utils;
 
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
 
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
 
public class FtpUtil {
	public static boolean uploadFile(String host, int port, String username, String password, String basePath,
			String filePath, String filename, InputStream input) {
		boolean result = false;
		FTPClient ftp = new FTPClient();
 
		try {
			int reply;
			ftp.connect(host, port);
			ftp.login(username, password);
			reply = ftp.getReplyCode();
			if (!FTPReply.isPositiveCompletion(reply)) {
				ftp.disconnect();
				return result;
			}
			if (!ftp.changeWorkingDirectory(basePath+filePath)) {
				String[] dirs = filePath.split("/");
				String tempPath = basePath;
				for (String dir : dirs) {
					if (null == dir || "".equals(dir)) continue;
					tempPath += "/" + dir;
					if (!ftp.changeWorkingDirectory(tempPath)) {
						if (!ftp.makeDirectory(tempPath)) {
							return result;
						} else {
							ftp.changeWorkingDirectory(tempPath);
						}
					}
				}
			}
			ftp.setFileType(FTP.BINARY_FILE_TYPE);
			if (!ftp.storeFile(filename, input)) {
				return result;
			}
			input.close();
			ftp.logout();
			result = true;
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (ftp.isConnected()) {
				try {
					ftp.disconnect();
				} catch (IOException ioe) {
				}
			}
		}
		return result;
	}
	
	public static boolean downloadFile(String host, int port, String username, String password, String remotePath,
			String fileName, String localPath) {
		boolean result = false;
		FTPClient ftp = new FTPClient();
 
		try {
			int reply;
			ftp.connect(host, port);
			ftp.login(username, password);
			reply = ftp.getReplyCode();
			if (!FTPReply.isPositiveCompletion(reply)) {
				ftp.disconnect();
				return result;
			}
			ftp.changeWorkingDirectory(remotePath);
			FTPFile[] fs = ftp.listFiles();
			for (FTPFile ff : fs) {
				if (ff.getName().equals(fileName)) {
					File localFile = new File(localPath + "/" + ff.getName());
 
					OutputStream is = new FileOutputStream(localFile);
					ftp.retrieveFile(ff.getName(), is);
					is.close();
				}
			}
 
			ftp.logout();
			result = true;
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (ftp.isConnected()) {
				try {
					ftp.disconnect();
				} catch (IOException ioe) {
				}
			}
		}
		return result;
	}
 
}

我的FtpUtil是作为一个工具类存在于taotao-common工程中的,并且在taotao-common中引入了FtpClient所在的common-net依赖。然后我将taotao-common作为依赖传递到了taotao-service工程,并在service工程的service类的方法中使用FtpUtil的静态方法upload。这时就找不到FTPClient类了。根据提示信息,某些依赖没有从common工程中传递过来,事实又是在service工程再添加一次common-net依赖工程就正常运行了。那么我就有了个大胆的看法:

由于upload是静态方法,在common工程中这个FTPUtil类是没有被加载的。根据类的加载时机(类被引用,通过new或者ClassLoader类创建对象时加载),FtpUtil这个类及其静态方法是在service工程的PictureServiceImpl类中被第一次使用时才加载的。加载时需要依赖信息,但是由于在common中这个类并没有被加载,common中导入的依赖相当于只是为了对FtpUtil中编写代码需要用到的对象的类信息的一种声明,没有进行实际的创建对象的操作。因此那些依赖就不能被传递过来。

可以这样理解吧:maven聚合工程中,某个工程(service)导入依赖的工程(common),实际是依赖common中已经存在的对象等等,一切已经可以用的东西。不能用的东西在Service自己这里使用时都需要重新导入依赖,因为工程的依赖关系传递的不是简单的依赖(理解为jar包比较好),而是原工程通过自己的添加的依赖创建的已有的对象等等,是实际的东西,可直接被调用的东西,而不是简单的依赖(声明的jar包)。

以上是我的个人理解,以此和大家讨论。不代表完全正确,欢迎评论指正。

 

 

 

 

阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页