问题:
当在表单form中设置 multipart/form-data
如:
<form action="userfile.jsp" method="post" enctype="multipart/form-data">
<p><input type="text" name="user" size="20"> </p>
<p><input type="text" name="password" size="20"> </p>
<p> <input type="file" name="ff"></p>
<p><input type="submit" value="tt" ></p>
</form>
在userfile.jsp中用
String user=request.getParameter("user");
String password=request.getParameter("password");
是获取不了参数的。 将返回null
为什么会这样呢???
enctype="multipart/form-data"是上传二进制数据; form里面的input的值以2进制的方式传过去。
form里面的input的值以2进制的方式传过去,所以request就得不到值了
所以我们可以用二进制文件流进行处理解析 request.getInputStream();
可以参考:http://www.oschina.net/code/snippet_117676_4588
public String getParameter(ServletInputStream in) |
071 | byte [] b = new byte [ 1024 ]; |
072 | l = in.readLine(b, 0 , b.length); |
073 | String si = new String(b); |
074 | if (si.startsWith( "----------------------------" )) |
076 | l = in.readLine(b, 0 , b.length); |
078 | l = in.readLine(b, 0 , b.length); |
079 | l = in.readLine(b, 0 , b.length); |
080 | String value = new String(b, 0 , l); |
084 | public long getFileUpload(ServletInputStream in, String fpath) |
088 | long begin = System.currentTimeMillis(); |
090 | byte [] b = new byte [ 1024 ]; |
091 | l = in.readLine(b, 0 , b.length); |
092 | String sign = new String(b, 0 , l); |
093 | l = in.readLine(b, 0 , b.length); |
094 | String info = new String(b, 0 , l); |
096 | l = in.readLine(b, 0 , b.length); |
099 | l = in.readLine(b, 0 , b.length); |
102 | int nIndex = info.toLowerCase().indexOf( "filename=\"" ); |
103 | int nLastIndex = info.toLowerCase().indexOf( "\"" , nIndex + 10 ); |
104 | String filepath = info.substring(nIndex + 10 , nLastIndex); |
105 | int na = filepath.lastIndexOf( "\\" ); |
106 | String filename = filepath.substring(na + 1 ); |
110 | String path=fpath + filename; |
112 | File fi = new File(path); |
113 | if (!fi.exists()&&!fi.createNewFile()) |
115 | BufferedOutputStream f = new BufferedOutputStream( new FileOutputStream( |
118 | while ((l = in.readLine(b, 0 , b.length)) > 0 ) |
120 | if (l == sign.length()) |
122 | String sign1 = new String(b, 0 , sign.length()); |
124 | if (sign1.startsWith(sign)) |
132 | long end = System.currentTimeMillis(); |
在jsp目标页面中调取
33 | ServletInputStream in = request.getInputStream(); |
34 | upload.setInputStream(in); |
35 | String nam = upload.getParameter(); |
36 | out.println("姓名:" + nam + "< br >< br >"); |
38 | long time = upload.getFileUpload(); |
39 | out.println("文件上传完毕,总共耗时:" + time + "毫秒< br >"); |
41 | String leixing = upload.getParameter(); |
42 | out.println("文件类型:" + leixing + "< br >"); |
但是这样也不多方便
采用commons-fileupload
FileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
upload.setHeaderEncoding("UTF-8");
List items = upload.parseRequest(request);
Iterator itr = items.iterator();
//System.out.println((String)itr.next());
while (itr.hasNext()) {
FileItem item = (FileItem) itr.next();
String fileName = item.getName();
System.out.println(fileName);
long fileSize = item.getSize();
if (!item.isFormField()) {
//检查文件大小
// 判断FileItem类对象封装的数据是否属于一个普通表单字段,还是属于一个文件表单字段。
// 普通表单字段 ---- return true;
// 文件表单字段 ---- return false;
if(item.getSize() > maxSize){
// out.println(getError("上传文件大小超过限制。"));
return;
}
//检查扩展名
String fileExt = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");
String newFileName = df.format(new Date()) + "_" + new Random().nextInt(1000) + "." + fileExt;
try{
File uploadedFile = new File(savePath, newFileName);
item.write(uploadedFile);
}catch(Exception e){
out.println("上传文件失败。");
return;
}
out.println("ok");
}else if(item.isFormField()){在此处判断是否是表单中的值 如果是 直接取出来
System.out.println(">>>>"+item.getString());
}
参考http://mcs.sysu.edu.cn/user/longt/Article_2081
下面及个重要的类及方法
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1. DiskFileUpload类
(1)setSizeMax(long sizeMax):
设置请求实体的最大限定值,防止客户端故意通过上传特大文件塞满服务器.
(2)setSizeThreshold(int sizeThreshold):
Apache文件上传组件在解析和处理上传数据中的每个字段内容时,需要临时保存解析出的数据。
(3)setRepositoryPath(String path):
设置setSizeThreshold方法中提到的临时文件的存放目录,这里使用绝对路径。
(4)parseRequest(HttpServerletRequest request)
ParseRequest(HttpServerletRequest request,int sizeThreshold,long sizeMax,String path)
是对HTTP请求消息进行解析的入口,需要Http请求必须是"multipart/form-data"类型.
该方法解析出Form表单中的每个字段的数据,并将它们分别包装成独立的FileItem对象加进一个List
类型的集合对象。
(5)setHeaderEncoding(String encode)
设置编码的方法,中文乱码处理需要用此方法.中文的编码一般用"gb2312"作为参数.
2. FileItem 类
(1) isFormField()
判断FileItem类对象封装的数据是否属于一个普通表单字段,还是属于一个文件表单字段。
普通表单字段 ---- return true;
文件表单字段 ---- return false;
(2) getName()
用于获取文件上传字段中的含路径的文件名。
需要注意的是用户如果没有通过文件表单传递文件,浏览器同样也会将文件字段和信息传递给服务器,
只是文件名和文件内容部分都为空,但这个表单字段仍然对应一个FileItem对象。此时getName()返回的是
一个空字符串"".
(3) getFieldName()
用于返回表单字段元素的name属性值.
(4) write(File file)
该方法用于将FileItem对象中保存的主题内容保存到某个指定的文件中.该方法也可以将普通表单字 段内容写入到一个文件中,但是它的主要用途是将上传的文件内容保存到本地文件系统中。
(5) getString()方法
用于将FileItem对象中保存的主体内容作为一个字符串返回。
(6)getContentType()方法
获得上传文件的类型,即文件的后缀。如果FileItem类对象对应的是普通表单字段,返回null.
(7)delete()方法
用来清空FileItem类对象中存放的主体内容,如果主体内容保存在临时文件中,delete方法将删除该 临时文件。
其余API,参考:http://commons.apache.org/fileupload/apidocs/index.html
别人的理解 (我也这样认为的)
当通过表单传递到服务器的时候,客户端浏览器会把表单相应的数据打包发送到服务器。有点web开发
经验的都知道表单对每个数据项提供一个name属性值,服务器通过访问name属性值获取客户端提供的数据。
FileUpload的核心就是解析浏览器传到服务器的http请求,把每个表单项解析出来打包成一个FileItem.
这个FileItem可以是一个普通表单项,也可以是一个文件上传表单项。服务器可以针对每个FileItem进行
处理。普通表单项可通过getString()提取主体内容,文件表单项进行文件保存操作.
当初不理解FileUpload,还觉得很难,其实也不是很难,不懂得看看API就OK了。还有Fileupload似乎
有进行更新,在用DiskFileUpload fu = new DiskFileUpload();的时候已经出现了过时警告。不过没有关
系,慢慢研究新内容。