public abstract class AbstractCoupleUploadController<T extends Serializable> extends RemoteServiceServlet implements ServletContextAware,UploadServlet<WorkshopHistoryModel> { ... @RequestMapping(method={RequestMethod.GET,RequestMethod.POST}) public ModelAndView handleRequest(@RequestParam("firstFile") CommonsMultipartFile firstFile,@RequestParam("secondFile") CommonsMultipartFile secondFile,HttpServletRequest request,HttpServletResponse response) { synchronized(this) { initThreads(); perThreadRequest.set(request); perThreadResponse.set(response); } handleUpload(firstFile,secondFile,request,response); response.getWriter().flush(); response.flushBuffer(); return null; } private void handleUpload(CommonsMultipartFile firstFile,CommonsMultipartFile secondFile,HttpServletResponse response) throws IOException { response.setContentType("text/html"); if(firstFile.getSize() == 0 || secondFile.getSize() == 0) { response.getWriter().print(AppConstants.UPLOAD_ZERO_SIZE_FILE); return; } // other validations // uploading: try { String content = request.getParameter(CoupleUploadPanel.CONTENT); T model = deserialize(content); UploadResultModel resultModel = upload(model,firstFile,secondFile); // it's implemented in UploadFileServletImpl if(resultModel.hasCriticalError()) { response.getWriter().print(AppConstants.UPLOAD_FAIL + "," + String.valueOf(resultModel.getWorkshopHistoryId())); } else { response.getWriter().print(AppConstants.UPLOAD_SUCCESS + "," + String.valueOf(resultModel.getWorkshopHistoryId())); } } catch(ProcessRequestException e) { // write upload error description in response.getWriter() } catch(Exception e) { e.printStackTrace(); response.getWriter().print(AppConstants.UPLOAD_UNKOWN_ERROR); } } ... }
我的app-servlet.xml(file.upload.max_size = 9437184)中有一个multipartResolver bean,另外还有一个用于处理UploadSizeExceededExceptions的maxUploadSizeExceptionExceptionHandler bean:
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="maxUploadSize" value="${file.upload.max_size}" /> </bean> <bean id="maxUploadSizeExceededExceptionHandler" class="com.insurance.ui.server.uploadfile.MaxUploadSizeExceededExceptionHandler"> <property name="order" value="1"/> </bean>
我的maxUploadSizeExceededExceptionHandler:
public class MaxUploadSizeExceededExceptionHandler implements HandlerExceptionResolver,Ordered { private int order; @Override public ModelAndView resolveException(HttpServletRequest request,HttpServletResponse response,Object handler,Exception ex) { if(ex instanceof MaxUploadSizeExceededException) { try { response.getWriter().print(ErrorConstants.UPLOAD_SIZE_EXCEED + "," + (((MaxUploadSizeExceededException) ex).getMaxUploadSize()/(1024*1024))); response.getWriter().flush(); response.flushBuffer(); return new ModelAndView(); } catch(IOException e) { } } return null; } ... }
当我上传一个非常大的文件(超过${file.upload.max_size},大约700MB),CommonsMultipartResolver立即抛出MaxUploadSizeExceededException,它正在捕获和处理它(在response.getWriter()中写)).我的问题:我的浏览器上传进度条显示文件仍在上传!为什么?
更新:我正在使用:
> Spring – * – 3.0.5.RELEASE
> commons-fileupload-1.1.1
并尝试:
> Spring – * – 3.1.2.RELEASE
> commons-fileupload-1.3
和我的AS:
> Tomcat 6(开发中)
> Jboss 7(生产中)
更新2:在客户端,我使用GWT(我认为没关系):
点击submitRequestButton开始上传:
@UiHandler("submitRequestButton") public void submitRequestButtonClick(ClickEvent event) { try { // some validation submitRequestButton.setEnabled(false); uploadPanel.upload(model.getWorkshopHistoryModel()); // uploadPanel is from the CoupleUploadPanel type } catch(ValidationException exception) { // handle validation errors } catch(SerializationException e) { // handle serialization errors } }
我有一个CoupleUploadPanel小部件上传(两个文件):
public class CoupleUploadPanel<T extends Serializable> extends FormPanel { public final static String CONTENT = "content"; private static final String FIRST_FILE = "firstFile"; private static final String SECOND_FILE = "secondFile"; private Hidden contentInput; private FileUpload firstFileUploadInput; private FileUpload secondFileUploadInput; private SerializationStreamFactory factory; public CoupleUploadPanel(UploadServletAsync<T> factory) { this(null,factory); } public CoupleUploadPanel(String url,UploadServletAsync<T> factory) { this.factory = (SerializationStreamFactory) factory; if(url != null) { setAction(url); } init(); } public CoupleUploadPanel(String target,String url,UploadServletAsync<T> factory) { super(target); this.factory = (SerializationStreamFactory) factory; if(url != null) { setAction(url); } init(); } private void init() { setMethod("POST"); setEncoding(ENCODING_MULTIPART); firstFileUploadInput = new FileUpload(); firstFileUploadInput.setName(CoupleUploadPanel.FIRST_FILE); secondFileUploadInput = new FileUpload(); secondFileUploadInput.setName(CoupleUploadPanel.SECOND_FILE); contentInput = new Hidden(); contentInput.setName(CONTENT); VerticalPanel panel = new VerticalPanel(); panel.add(firstFileUploadInput); panel.add(secondFileUploadInput); panel.add(contentInput); add(panel); } public void upload(T input) throws SerializationException { contentInput.setValue(serialize(input)); submit(); } private String serialize(T input) throws SerializationException { SerializationStreamWriter writer = factory.createStreamWriter(); writer.writeObject(input); return writer.toString(); } }
我们应该将UploadServletAsync传递给CoupleUploadPanel构造函数. UploadServletAsync和UploadServlet接口:
public interface UploadServletAsync<T extends Serializable> { void upload(T model,AsyncCallback<Void> callback); } public interface UploadServlet<T extends Serializable> extends RemoteService { void upload(T model); }
所以uploadPanel将以这种方式被实例化:
uploadPanel= new CoupleUploadPanel<WorkshopHistoryModel>((UploadFileServletAsync) GWT.create(UploadFileServlet.class)); uploadPanel.setAction(UploadFileServlet.URL);
并且添加到uploadPanel(onSumbitComplete()的SubmitCompeleteHandler将在提交完成时被调用,结果传递给客户端):
uploadPanel.addSubmitCompleteHandler(new SubmitCompleteHandler() { @Override public void onSubmitComplete(SubmitCompleteEvent event) { String s = event.getResults(); //contains whatever written by response.getWriter() if(s == null) { // navigate to request list page } else { String[] response = s.split(","); // based on response: // show error messages if any error occurred in file upload // else: navigate to upload result page } } });
UploadFileServlet和UploadFileServletAsync接口:
public interface UploadFileServlet extends UploadServlet<WorkshopHistoryModel> { String URL = "**/uploadFileService.mvc"; } public interface UploadFileServletAsync extends UploadServletAsync<WorkshopHistoryModel> { public static final UploadFileServletAsync INSTANCE = GWT.create(UploadFileServlet.class); }
在服务器端:UploadFileServletImpl扩展AbstractCoupleUploadController并实现upload()方法(上传过程):
@RequestMapping(UploadFileServlet.URL) public class UploadFileServletImpl extends AbstractCoupleUploadController<WorkshopHistoryModel> { ... @Override protected UploadResultModel upload(WorkshopHistoryModel model,MultipartFile firstFile,MultipartFile secondFile) throws ProcessRequestException { return workshopHistoryService.submitList(model.getWorkshop(),secondFile); } ... }
解决方法
在我最后一次安装过程中,我曾经用过Nginx作为Tomcat前面的代理:
>如果您的浏览器发送实际的文件大小(现代浏览器,至少IE7?或IE8?),Nginx将发送500,如果大小超过定义的限制.>我不是100%肯定:如果上传的大小超过指定的限制,Nginx也会发送一个500.这也将取消与Tomcat的底层连接.