文件上传中的一个致命异常

指尖上的行者 2012-01-10 03:11:06
我通过struts1+apache的fileUpload实现文件上传功能,但是因为要考虑并发的问题,所以我加入了线程池对其进行管理,当把代码复制到run()方法中时,它提示要把request与response全部设成final类型,之后,问题就接踵而来了。在执行到:
List <FileItem> fileItems = upload.parseRequest(request);这一句时就报异常了,如下:
org.apache.commons.fileupload.FileUploadBase$InvalidContentTypeException: the request doesn't contain a multipart/form-data or multipart/mixed stream, content type header is null
at org.apache.commons.fileupload.FileUploadBase.parseRequest(FileUploadBase.java:294)
at org.apache.commons.fileupload.servlet.ServletFileUpload.parseRequest(ServletFileUpload.java:116)
at com.dtcloud.action.UploadAction$1.run(UploadAction.java:81)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:619)


在网上找了半天都没找到想对应的回答,我们做的是移动开发,后台是通过手机端访问的。在没加线程池的时候访问是正常的,知道的朋友还望指点一二,谢谢啦!!!
...全文
4239 11 打赏 收藏 转发到动态 举报
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
johnsongya 2014-02-27
  • 打赏
  • 举报
回复
得,都2年过去了,有人应吗
johnsongya 2014-02-27
  • 打赏
  • 举报
回复
那个<s ......>在哪找啊
ilovefzq 2012-01-13
  • 打赏
  • 举报
回复
一班的web服务器中,如tomcat都是有线程机制的,不用考虑并发时的问题,要考虑也应该是高并发时的性能,这就与数据结构,数据库设计,代码优化有关,跟线程无关了
MiceRice 2012-01-13
  • 打赏
  • 举报
回复
所以,楼主啊,问题跟我说的是一致的。

你看你最后的两端代码:
threadPool.execute(new Runnable() {
...
});
return null;

当主线程利用threadPool启动了子线程去处理文件上传后,你的主线程其实就 return null; 了,那么中间件(Tomcat或JBOSS,不知道你用的是啥)就会把整个请求全部结束掉了,也就是request和response都会结束掉。那么你的子线程当然什么东西都干不了了。

你可以尝试在return null;这句话的前面增加
try {threadPool.awaitTermination(60, TimeUnit.SECONDS);} catch (Exception ex){}
看看问题是否迎刃而解?
但其实这就已经丧失了你最开始的设计初衷了。


但,总的来说,楼主,我认为你过度设计了。
中间件的整个设计本身已经有线程池的概念,并且也已经很好的支持了并发需求,你是不能企图用自己的线程池去接管它的工作的。原则上来说,J2EE开发,是不建议有类似创建子线程的代码的。

我认为你没有任何合理的理由去这么做。
如果你认为你有,那么请说出来,我们探讨下是否有更合理的模式,而不是采用这种方式。
若鱼1919 2012-01-13
  • 打赏
  • 举报
回复

org.apache.commons.fileupload.FileUploadBase$InvalidContentTypeException: the request doesn't contain a multipart/form-data or multipart/mixed stream, content type header is null


form表单加上:enctype="multipart/form-data"

指尖上的行者 2012-01-13
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 ldh911 的回复:]

没搞懂楼主是怎么用线程池去对上传做并发管理的。常规分析如下:

浏览器提交文件后,服务器会有一个线程负责处理这个请求,我们称其为“主线程”。

现在你启动一个子线程去接管这个请求,继续完成下载工作,但你的主线程在干啥呢?

我觉得你的主线程只能是在傻傻的等你启动的子线程完成任务吧?因为你的主线程不能返回(结束)啊,你一返回,中间件就把这个请求彻底结束了,你就没啥好玩的了。

所以……
[/Quote]
我这也是这么认为的,之所以要使用线程池是因为考虑到高并发的问题。
谢谢其他朋友的答复,你们说的那个因为缺少数据类型而导致错误的这种情况确实存在,但是我这里不是因为那个原因。当我不使用线程池的时候就没问题啦,以下是我的源码:

public ActionForward execute(ActionMapping mapping, ActionForm form,
final HttpServletRequest request, final HttpServletResponse response)
throws Exception {

ThreadPoolExecutor threadPool = (ThreadPoolExecutor) Executors.newCachedThreadPool();

Properties config = getProperty(config_path);
if (config == null) {
config = loadConfig(config_path);
}
final String tempDir = config.getProperty("tempDir");//存储图片的临时目录
final String photoDir = config.getProperty("photoDir");//照片目录
final String photoUrl = config.getProperty("photoUrl");//照片的URL
final String memorySize = config.getProperty("memorySize");//内存缓冲大小
final String sizeMax = config.getProperty("sizeMax");//文件允许的最大值
final String outTime = config.getProperty("outTime");//设置线程在终止前可以保持空闲的时间限制
threadPool.setKeepAliveTime(Long.parseLong(outTime), TimeUnit.SECONDS);

final PrintWriter out = response.getWriter();
threadPool.execute(new Runnable() {
public void run() {
try {
// 创建磁盘工厂
DiskFileItemFactory factory = new DiskFileItemFactory();
// 设置内存缓冲大小
factory.setSizeThreshold(Integer.parseInt(memorySize));
// 设置临时目录
File file = new File(tempDir);
if(!file.exists()){
file.mkdir();
}
factory.setRepository(file);
// 创建处理工具
ServletFileUpload upload = new ServletFileUpload(factory);
// 设置最大允许的尺寸
int setFileSize = Integer.parseInt(sizeMax);
int fileSize = request.getContentLength();
upload.setSizeMax(setFileSize);

if (fileSize <= setFileSize) {
// 解析
String contentType = request.getContentType();//multipart/form-data; boundary=p89nCm2-NdBgJFcZIdCixdGVgEbKHP
if(contentType == null && "".equals(contentType)){
out.print("File Upload Error");
return;
}
List<FileItem> fileItems = upload.parseRequest(request);
Iterator<FileItem> iter = fileItems.iterator();

for (; iter.hasNext();) {

FileItem fileItem = (FileItem) iter.next();
// 判断FileItem类对象封装的数据是一个普通文本表单字段,还是一个文件表单字段,如果是普通表单字段则返回true,否则返回false
if (fileItem.isFormField()) {
// 当前是一个表单项
out.print("form field : "
+ fileItem.getFieldName() + ", "
+ fileItem.getString());
} else {
// 当前是一个上传的文件
String fileName = fileItem.getName();
File fileDir = new File(photoDir + fileName);
fileItem.write(fileDir);

out.print(photoUrl + fileName);
}
}
} else {
out.print("你上传的文件过大");
}
} catch (Exception e) {
e.printStackTrace();
out.print("File Upload Fail!");
}
}
});
return null;
}
anhy 2012-01-12
  • 打赏
  • 举报
回复
估计是request过期了
huangxw000 2012-01-12
  • 打赏
  • 举报
回复
异常说是请求头文件信息是空,你就给一句源码,很难猜测哪里出问题吧。
指尖上的行者 2012-01-12
  • 打赏
  • 举报
回复
有知道的么???为什么将执行代码放入线程池中request就有问题啦???
我系大红花 2012-01-12
  • 打赏
  • 举报
回复
<s:form action="Upload" method="post" enctype="multipart/form-data">
加这句enctype="multipart/form-data";
如果不行,请发详细点的代码上来
一般是这个问题,因为前几天我也遇到这个问题
MiceRice 2012-01-12
  • 打赏
  • 举报
回复
没搞懂楼主是怎么用线程池去对上传做并发管理的。常规分析如下:

浏览器提交文件后,服务器会有一个线程负责处理这个请求,我们称其为“主线程”。

现在你启动一个子线程去接管这个请求,继续完成下载工作,但你的主线程在干啥呢?

我觉得你的主线程只能是在傻傻的等你启动的子线程完成任务吧?因为你的主线程不能返回(结束)啊,你一返回,中间件就把这个请求彻底结束了,你就没啥好玩的了。

所以,我对于楼主对上传还用了线程池去做并发管理,表示相当没看懂。

81,094

社区成员

发帖
与我相关
我的任务
社区描述
Java Web 开发
社区管理员
  • Web 开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧