新项目的框架是ssh,用到了struts2的文件上传功能,但发现项目在eclipse启动后,只有第一次上传文件是ok的,以后上传就报
2018-01-09 21:32:16 [http-nio-8080-exec-7] ERROR: com.cs.lexiao.admin.basesystem.component.core.AttachmentServiceImpl#save : Source ‘/home/vobile/workspace_trph/.metadata/.plugins/org.eclipse.wst.server.core/tmp1/work/Catalina/localhost/lexiao-admin/upload_2df39ff2_d4c7_49ef_a521_925b0e85c43a_00000001.tmp‘ does not exist java.io.FileNotFoundException: Source ‘/home/vobile/workspace_trph/.metadata/.plugins/org.eclipse.wst.server.core/tmp1/work/Catalina/localhost/lexiao-admin/upload_2df39ff2_d4c7_49ef_a521_925b0e85c43a_00000001.tmp‘ does not exist at org.apache.commons.io.FileUtils.copyFile(FileUtils.java:1004) at org.apache.commons.io.FileUtils.copyFile(FileUtils.java:968) at com.cs.lexiao.admin.basesystem.component.core.AttachmentServiceImpl.save(AttachmentServiceImpl.java:367) at com.cs.lexiao.admin.basesystem.component.core.AttachmentServiceImpl.save(AttachmentServiceImpl.java:217) at com.cs.lexiao.admin.basesystem.component.core.AttachmentServiceImpl$$FastClassByCGLIB$$99f22be.invoke(<generated>) at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) at org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint(Cglib2AopProxy.java:689) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150) at org.springframework.aop.framework.adapter.ThrowsAdviceInterceptor.invoke(ThrowsAdviceInterceptor.java:124) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) at org.springframework.aop.framework.adapter.ThrowsAdviceInterceptor.invoke(ThrowsAdviceInterceptor.java:124)
因为struts默会把文件放在/tmp1下面,生成了一个xxxx.tmp的临时文件,而报这个错是这个临时文件找不到,跟踪了下struts2的FileUploadInterceptor,
Enumeration fileParameterNames = multiWrapper.getFileParameterNames(); while (fileParameterNames != null && fileParameterNames.hasMoreElements()) { // get the value of this input tag String inputName = (String) fileParameterNames.nextElement(); // get the content type String[] contentType = multiWrapper.getContentTypes(inputName); if (isNonEmpty(contentType)) { // get the name of the file from the input tag String[] fileName = multiWrapper.getFileNames(inputName); if (isNonEmpty(fileName)) { // get a File object for the uploaded File File[] files = multiWrapper.getFiles(inputName); if (files != null && files.length > 0) { List<File> acceptedFiles = new ArrayList<File>(files.length); List<String> acceptedContentTypes = new ArrayList<String>(files.length); List<String> acceptedFileNames = new ArrayList<String>(files.length); String contentTypeName = inputName + "ContentType"; String fileNameName = inputName + "FileName"; for (int index = 0; index < files.length; index++) { if (acceptFile(action, files[index], fileName[index], contentType[index], inputName, validation)) { acceptedFiles.add(files[index]); acceptedContentTypes.add(contentType[index]); acceptedFileNames.add(fileName[index]); } } if (!acceptedFiles.isEmpty()) { Map<String, Object> params = ac.getParameters(); params.put(inputName, acceptedFiles.toArray(new File[acceptedFiles.size()])); params.put(contentTypeName, acceptedContentTypes.toArray(new String[acceptedContentTypes.size()])); params.put(fileNameName, acceptedFileNames.toArray(new String[acceptedFileNames.size()])); } } } else { if (LOG.isWarnEnabled()) { LOG.warn(getTextMessage(action, "struts.messages.invalid.file", new String[]{inputName})); } } } else { if (LOG.isWarnEnabled()) { LOG.warn(getTextMessage(action, "struts.messages.invalid.content.type", new String[]{inputName})); } }
发现acceptedFiles有多个文件,准确的说是之前上传了多少个就有多少个,而我一次其实只上传了一个文件,而临时目录里也只有我这次上传的文件,对应到java代码里只会接受一个文件,默认取了第一个_00000001.tmp,而实际存在的是_00000004.tmp,那就报错了。
为什么呢?当时怀疑是前端的问题,但没发现原因。后来我单独用postman向后端上传文件,发现问题依旧,说明是后端的问题。最后是注释掉了以前加的一个struts2的安全插件
struts.xml
<bean type="org.apache.struts2.dispatcher.multipart.MultiPartRequest" class="org.apache.struts.extras.SecureJakartaMultipartParser" name="secure-jakarta" scope="prototype"/> <constant name="struts.multipart.parser" value="secure-jakarta"/>
把struts.xml里的这段注释掉就好了。
那又是什么最终的原因呢?还没开始分析那个插件,待续。