- 浏览: 519119 次
- 性别:
- 来自: 上海
文章分类
- 全部博客 (278)
- java (41)
- 设计模式 (4)
- sql (10)
- webservice (2)
- spring (9)
- struts (6)
- struts2 (32)
- hibernate (27)
- Struts_hibernate_Spring整合 (4)
- Velocity (1)
- Servlet (9)
- JSP (6)
- javascript (19)
- jquery (10)
- ajax (4)
- html、xml (3)
- JDBC (2)
- JDK (6)
- mysql (2)
- oracle (11)
- SqlServer (1)
- DB2 (4)
- tool (7)
- linux (5)
- UML (1)
- eclipse (8)
- 执行文件 (1)
- 应用服务器 (4)
- 代码重构 (1)
- 日本語 (19)
- 交规 (1)
- office (9)
- firefox (1)
- net (1)
- 测试 (1)
- temp (6)
- 对日外包 (1)
- windows (1)
- 版本控制 (1)
- android (2)
- 项目管理 (1)
最新评论
一、 文件上传的原理
1. 表单元素的 enctype 属性
表单的 enctype 属性指定的是表单数据的编码方式 ,该属性有 3 个值:
1. application/x-www-form-urlencoded : 这是默认的编码方式,它只处理表单域里的 value 属性值,采用这种编码方式的表单会将表单域的值处理成 URL 编码方式。
2. multipart/form-data : 这种编码方式会以二进制流的方式来处理表单数据,这种编码方式会把文件域指定文件的内容也封装到请求参数里。
3. text/plain : 这种编码方式当表单的 action 属性为 mailto:URL 的形式时比较方便,这种方式主要适用于直接通过表单发送邮件的方式
下面来介绍 application/x-www-form-urlencoded 和 multipart/form-data 的区别。如下:
application.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title> enctype属性测试 </title> <meta name="author" content="Yeeku.H.Lee" /> <meta name="website" content="http://www.crazyit.org" /> <meta http-equiv="Content-Type" content="text/html; charset=GBK" /> </head> <body> <form id="form1" name="form1" enctype="application/x-www-form-urlencoded" method="post" action="pro.jsp"> 上传文件:<input type="file" name="file" /><br /> 请求参数:<input type="text" name="wawa" /><br /> <input name="dd" type="submit" value="提交" /> </form> </body> </html>
下面是处理的 jsp
pro.jsp
<%@ page contentType="text/html;charset=GBK" %> <%@ page import="java.io.*"%> <% //获取HTTP请求的输入流 InputStream is = request.getInputStream(); //以HTTP请求输入流建立一个BufferedReader对象 BufferedReader br = new BufferedReader( new InputStreamReader(is)); //读取HTTP请求内容 String buffer = null; while( (buffer = br.readLine()) != null) { //在页面中显示读取到的请求参数 out.println(buffer + "<br />"); } %>
上面的处理页面直接通过二进制流来处理该 HTTP 请求,这是一种更底层的处理方式 ,当通过 HttpServletRequest 的 getParameter() 方法来获取请求参数时,实际上是 Web 服务器替我们处理了这种底层的二进制流 ,并将二进制流转换成对应的请求参数值。
如果上面 html 的 上传文件 是 logo.jpg , 请求参数 是 “crazyit标志” ,提交后 :
pro.jsp 页面将显示:
file=logo.jpg&wawa=crazyit%EA%D6%BE&dd=%CC%E1%BD%BB
如上,即使通过底层的二进制输入流,一样可以读到该请求的内容 :
一个普通字符串,包含了 3 个请求参数,即 file, wawa 和 dd
提示: 即使是“提交”按钮,表单一样将其当成一个表单域,一样转换成一个请求参数。浏览器会将表单里所有具有 name 属性的表单控件转换成请求参数,因此“提交”按钮也有 name 属性,因此也被转化请求参数
Java 提供了 2 个类: URLDecoder 和 URLEncoder ,
来处理 " %CC%E1%BD%BB " 字符串。如下:
TestURLEncoder.java
import java.net.*; public class TestURLEncoder { public static void main(String[] args) throws Exception { //定义一个字符串,该字符串的值为上面的dd请求参数的值 String encodeStr = "%CC%E1%BD%BB"; //使用URLDecoder类来处理该dd请求参数值 String decodeStr = URLDecoder.decode(encodeStr ,"GBK"); System.out.println(decodeStr); //定义一个字符串,该字符串的值为在图7.1中的文本框中输入的内容 String rawStr = "crazyit标志"; //使用URLEncoder类处理该字符串 System.out.println(URLEncoder.encode(rawStr , "GBK")); } }
大部分时候,程序中直接通过 HttpServletRequest 的 getParameter 方法即可获得正确的请求参数,而那些底层的二进制流处理,以及使用 URLDecoder 处理请求参数,都由 Web 服务器来替我们完成了
但是如果我们设置表单元素的 enctype 属性为 "multipart/form-data ",该请求将会把文件域里浏览到的文件内容作为请求参数发送。显然此时无法直接通过 request.getParameter() 方法来获取请求参数。
pro.jsp 页面将显示:
-----------------------------7cf87224d2020a
Content-Disposition: form-data; name= "email "
PhCollignon@email.com
-----------------------------7cf87224d2020a
Content-Disposition: form-data; name= "file"; filename= "c:\windows常用健.txt "
Content-Type: text/plain
Ctrl+L 打开“打开”面版(可以在当前页面打开Iternet地址或其他文件...)
Ctrl+N 新建一个空白窗口(可更改,Maxthon选项→标签→新建)
Ctrl+O 打开“打开”面版(可以在当前页面打开Iternet地址或其他文件...)
Ctrl+P 打开“打印”面板(可以打印网页,图片什么的...)
Ctrl+Q 打开“添加到过滤列表”面板(将当前页面地址发送到过滤列表)
Ctrl+R 刷新当前页面
Ctrl+S 打开“保存网页”面板(可以将当前页面所有内容保存下来)
Ctrl+T 垂直平铺所有窗口
Ctrl+V 粘贴当前剪贴板内的内容
Ctrl+W 关闭当前标签(窗口)
Ctrl+X 剪切当前选中内容(一般只用于文本操作)
Ctrl+Y 重做刚才动作(一般只用于文本操作)
Ctrl+Z 撤消刚才动作(一般只用于文本操作)
-----------------------------7cf87224d2020a
Content-Disposition: form-data; name= "Enter "
Submit Query
-----------------------------7cf87224d2020a--
2.手动上传
下面将直接通过底层的二进制流来取得上传文件内容,并将该文件内容放到 Web 应用所在路径。
由上面 “
pro.jsp
页面将显示:
”
可以发现
,每个表单域的内容总以
“-----------------------------7cf87224d2020a ”
式样的字符串开始,后面的字符串可能变化,但前面的中画线总是不会变的。 对每个文件域而言,在第二行内容中总会包含 filename = ""
的字符串
。
下面是处理上传文件的 JSP :
uploadpro.jsp
<%@ page contentType="text/html;charset=GBK" %> <%@ page import="java.io.*"%> <% //取得HttpServletRequest的InputStream输入流 InputStream is = request.getInputStream(); //以InputStream输入流为基础,建立一个BufferedReader对象 BufferedReader br = new BufferedReader(new InputStreamReader(is)); String buffer = null; //循环读取请求内容的每一行内容 while( (buffer = br.readLine()) != null) { //如果读到的内容以-----------------------------开始, //且以--结束,表明已到请求内容尾 if(buffer.endsWith("--") && buffer .startsWith("-----------------------------")) { //跳出循环 break; } //如果读到的内容以-----------------------------开始,表明开始了一个表单域 if(buffer.startsWith("-----------------------------")) { //如果下一行内容中有filename字符串,表明这是一个文件域 if (br.readLine().indexOf("filename") > 1) { //跳过两行,开始处理上传的文件内容 br.readLine(); br.readLine(); //以系统时间为文件名,创建一个新文件 File file = new File(request.getRealPath("/") + System.currentTimeMillis()); //创建一个文件输出流 PrintStream ps = new PrintStream(new FileOutputStream(file)); String content = null; //接着开始读取文件内容 while( (content = br.readLine()) != null) { //如果读取的内容以-----------------------------开始, //表明开始了下一个表单域内容 if(content.startsWith("-----------------------------")) { //跳出处理 break; } //将读到的内容输出到文件中 ps.println(content); } //关闭输出 ps.flush(); ps.close(); } } } br.close(); %>
通过上面 JSP ,就可以把一个文件上传到 Web 应用的根路径下。值得注意的是,上面用的是 BufferedReader
字符流( 字符流在处理二进制文件时会出现问题 ),因此上面的上传处理只能处理文本文件的上传。
如果将上面采用字符流
处理文件的上传逻辑,改为以字节流
来处理文件上传,则上传处理将可以处理任何文件的上传
对于一个成熟的文件上传框架而言,它需要完成的逻辑非常简单: 通过分析 HttpServletRequest 的二进制流,解析出二进制流中所包含的全部表单域,分析出每个表单域的类型(是文件还是普通表单域),并允许开发者以简单的方式来取得文件域的内容字节,文件名和文件内容等信息,也可以取得其他表单域的值。
3.使用上传框架完成上传
对于 java 而言,比较常用的上传框架有 2 个
: Common-FileUpload
和 COS
,不管使用哪个,它都负责解析出 HttpServletRequest 请求中的所有域 —— 不管是文件域还是普通表单域。
【1】 Common-FileUpload
这个框架是 Apache 组织下 jakarta-commons 项目组下的一个小项目,该框架可以方便地将 multipart/form-data 类型请求中的各种表单域解析出来。该项目还依赖于另一个项目: Common-IO。
步骤:
① 登录 http://jakarta.apache.org/commons/fileupload/ 站点,下载 Common-FileUpload 项目最新发布版,下载后得到一个压缩文件,将下载的压缩文件打开,看到:
● lib : 该路径下存放的是 Common-FileUpload 项目的二进制类库和源文件等。
● site : 该路径下存放的是 Common-FileUpload 项目的各种文档,包括使用手册和 API 文档等。
● 注意和 LICENSE 等文件
② 将上面文件路径中的 lib\commons-fileupload-1.2.1.jar 文件复制到 Web 应用的 WEB-INF/lib 路径下
③ 登录 http://jakarta.apache.org/commons/io/ 站点,下载 Common-IO 项目的最新发布版本。打开下载文件,看到如下结构:
●
docs:该路径下存放了该项目的文档文件,包括使用说明和 API 文档等
●
commons-io-1.4.jar:该文件是该项目的二进制类库文件
●
commons-io-1.4-javadoc.jar:该项目 API 文档压缩包
● commons-io-1.4-sources.jar:该项目的全部源文件压缩包
● 注意和 LICENSE 等文件
④
将上面解压出来的
commons-io-1.4.jar 文件复制到 Web 应用的 WEB-INF/lib 路径下
经过上面 4 个步骤,即可在 Web 应用中使用该框架来完成文件上传了。该框架完成文件上传的关键类是 ServletFileUpload ,该类可以对 HttpServletRequest 请求进行分析,分析出该请求中的全部表单域
commonUpload.jsp
<%@ page contentType="text/html;charset=GBK" %> <%@ page import="java.io.*,java.util.*"%> <%@ page import="org.apache.commons.fileupload.disk.*" %> <%@ page import="org.apache.commons.fileupload.*" %> <%@ page import="org.apache.commons.fileupload.servlet.*" %> <% DiskFileItemFactory factory = new DiskFileItemFactory(); //设置上传工厂的限制 factory.setSizeThreshold(1024 * 1024 * 20); factory.setRepository(new File(request.getRealPath("/"))); //创建一个上传文件的ServletFileUpload对象 ServletFileUpload upload = new ServletFileUpload(factory); //设置上传文件的最大接受20M upload.setSizeMax(1024 * 1024 * 20); //处理HTTP请求,items是所有的表单项 List items = upload.parseRequest(request); //遍历所有的表单项 for (Iterator it = items.iterator(); it.hasNext() ; ) { FileItem item = (FileItem)it.next(); if (item.isFormField()) { String name = item.getFieldName(); String value = item.getString("GBK"); out.println("表单域的name=value对为:" + name + "=" + value + "<br />"); } else { //取得文件域的表单域名 String fieldName = item.getFieldName(); //取得文件名 String fileName = item.getName(); //取得文件类型 String contentType = item.getContentType(); //以当前时间来生成上传文件的文件名 FileOutputStream fos = new FileOutputStream( request.getRealPath("/") + System.currentTimeMillis() + fileName.substring(fileName.lastIndexOf(".") , fileName.length())); //如果上传文件域对应文件的内容已经在内存中 if (item.isInMemory() ) { fos.write(item.get()); } //如果文件内容不完全在内存中 else { //获取上传文件内容的输入流 InputStream is = item.getInputStream(); byte[] buffer = new byte[1024]; int len; //读取上传文件的内容,并将其写入服务器的文件中 while ((len = is.read(buffer)) > 0 ) { fos.write(buffer , 0 , len); } is.close(); fos.close(); } } } %>
不管是文件域还是普通表单域 Common-FileUpload 框架都把它们当成 FileItem 对象处理,如果该对象的 isFormField() 方法返回 true ,表明该表单域是一个普通表单域,否则将是一个文件域
FileItem 类包含了如下几个方法
● getFieldName():取得该表单域的 name 属性值
● getString(String encoding): 取得该表单域的 value 属性值,其中 encoding 参数设置该表单域的编码集
● getName():仅当该表单域是文件域,才有效,该方法返回上传文件的文件名
● getContentType():返回上传文件的文件类型
● get():返回上传文件的文件类型
● getInputStream():返回上传文件对应的输入流
通过上面的几个方法可以很轻易的完成文件上传
【2】 COS
这个框架是 Oreilly 组织下的一个小项目,该项目同样可以将 multipart/form-data 类型请求中的各个表单域解析出来。
为了在 Web 应用中使用 COS 项目,有如下步骤。
①
在 http://www.servlets.com/cos/ ,下载 COS 项目的最新版本。得到一个压缩文件,解压后:
● doc : 该项目的 API 文档
● lib : classes 路径下所有 class 文件打包后的文件
● src : 所有源文件
●注意LICENSE 等文件
② 将上面文件结构中的 lib/cos.jar 复制到 WEB-INF/lib 下 。
COS 实现文件上传更简单,它的核心类是 MultipartParser, 该类用于解析 HttpservletRequest 请求。
COS 用 Part 实例代表了所有的表单域,不管是普通表单域还是文件域。part类有2个子类:ParamPart 和 FilePart ,它们分别代表了 普通表单域和文件域
Part 类包含的常用方法:
● getName() : 获取表单域的 name 属性。
ParamPart 类包含的常用方法:
● getStringValue(String encoding) : 取得该表单域的 value 属性值,encoding 参数是表单域的编码集
FilePart 类包含的常用方法:
● getFileName(): 返回 上传文件的文件名
● getFilePath() : 返回上传文件的文件路径
● getContentType() : 返回上传文件的文件类型
cosUpload.jsp
<%@ page contentType="text/html;charset=GBK" %> <%@ page import="java.io.*,java.util.*" %> <%@ page import="com.oreilly.servlet.multipart.*" %> <%@ page import="com.oreilly.servlet.*" %> <% //设置POST请求的内容最大字节为10M,该类用于解析HTTP请求 MultipartParser mp = new MultipartParser(request , 10*1024*1024); //所有表单域都是Part实例 Part part; //遍历请求中的所有表单域 while ((part = mp.readNextPart()) != null) { //取得表单域的name属性值 String name = part.getName(); //对于普通表单域 if (part.isParam()) { //取得普通表单域的值 ParamPart paramPart = (ParamPart) part; String value = paramPart.getStringValue("GBK"); out.print("普通表单域部分: <br />name=" + name + ";value=" + value + "<br />"); } //对于文件域 else if(part.isFile()) { //取得文件上传域 FilePart filePart = (FilePart) part; String fileName = filePart.getFileName(); if (fileName != null) { //输出文件内容 long size = filePart.writeTo(new File( request.getRealPath("/"))); out.println("上传文件:<br /> 文件域的名=" + name + ";文件名=" + fileName + "<br />" + "上传文件的内容=" + filePart.getFilePath() + "<br />" + "文件内容类型=" + filePart.getContentType() + "<br />" + "文件大小=" + size + "<br />"); } //文件名为空 else { //该文件域没有输入文件名 out.println("名为" + name + "的文件不存在!"); } out.flush(); } } %>
注意: 如果使用 COS 来上传,文件名包含中文字符,会出现异常,可能是 COS 本身的问题。对于中文开放环境,推荐使用 Common-FileUpload 来上传文件 。
发表评论
文章已被作者锁定,不允许评论。
-
Struts1 与 Struts2 的12点区别
2011-11-16 11:14 7401) 在Action实现类方面 ... -
Struts 2 的 Ajax 支持(四)
2011-03-14 16:21 17425.4 tabbedpanel 标签 ... -
Struts 2 的 Ajax 支持(三)
2011-02-11 13:18 24345.2 submit 和 a 标签 ... -
Struts 2 的 Ajax 支持(二)
2011-01-27 14:08 2397四、 基于 Dojo 的 pub-sub 事件模型 ... -
Struts 2 的 Ajax 支持(一)
2011-01-20 14:55 2485一、 Ajax 概述 ... -
Struts 2 的拦截器(三)
2011-01-20 13:09 2907六、 拦截器示例 : 实现权限控制 权限检 ... -
Struts 2 的拦截器(二)
2011-01-12 16:38 1628四、 开发自己的拦截器 Struts 2 ... -
Struts 2 的拦截器(一)
2010-12-31 16:53 2021一、 理解拦截器 ... -
Struts 2 的标签库(五)
2010-12-29 11:35 11426.8 select 标签 以下代码 都是基 ... -
Struts 2 的标签库(四)
2010-12-24 16:21 1645六、 表单标签 表单标签,分为 2 种 : f ... -
Struts 2 的标签库(三)
2010-12-20 14:15 1971四、 数据标签 数据标签主要 ... -
Struts 2 的标签库(二)
2010-12-15 16:21 2029三、 控制标签 Str ... -
Struts 2 的标签库(一)
2010-12-13 13:47 1362一、 Struts 2 标签库概述 ... -
Struts 2 的国际化(二)
2010-12-09 13:25 2259二、 Struts 2 的国际化入门 ... -
Struts 2 的国际化(一)
2010-12-06 22:44 1305一、 程序国际化简 ... -
Struts2 上传和下载文件(三)
2010-12-03 14:58 1793三、 同时上传多个 ... -
Struts2 上传和下载文件(二)
2010-11-29 13:37 1983二、 Struts 2 的文件上传 ... -
struts2 输入校验 (四)
2010-11-15 22:43 1215六、 手动完成输入校验 对于一些特殊的检验 ... -
struts2 输入校验 (三)
2010-11-08 13:25 1721五、 内建校验器 S ... -
struts2 输入校验 (二)
2010-10-28 11:01 2385二、 基本输入校验 MVC ...
相关推荐
在Struts2中,文件上传和下载是常见的功能需求,特别是在处理用户交互和数据交换时。这篇博客文章提供的"struts2文件上传下载源代码"旨在帮助开发者理解和实现这些功能。 文件上传功能允许用户从他们的设备上传文件...
Struts2是一个强大的MVC(模型-视图-控制器)框架,广泛应用于Java ...以上就是使用Struts2框架实现文件上传下载的基本步骤和关键知识点。在实际开发中,可以根据项目需求进行调整和优化,确保功能的稳定性和安全性。
在这个"struts2上传和下载文件详细源码"中,我们可以深入理解Struts2如何处理文件上传和下载操作。 1. 文件上传: 在Struts2中,文件上传主要依赖于Apache的Commons FileUpload库。首先,需要在struts.xml配置文件...
在Struts2中,文件上传和下载是常见的功能需求,对于用户交互和数据交换至关重要。以下是对这些知识点的详细阐述: 1. **文件上传**: 在Struts2中,文件上传主要依赖于`Commons FileUpload`库,它是一个Apache提供...
在这个特定的项目中,我们关注的是"struts2文件上传下载"的功能,这涉及到用户通过Web界面上传文件到服务器,以及从服务器下载文件到用户的设备。 文件上传是Web应用中的常见需求,例如用户可能需要提交图片、文档...
总之,这个项目实例为使用Struts2和Uploadify实现带进度条的多文件上传及下载功能提供了一个基础模板,对于学习和实践此类功能的开发者来说是一个有价值的参考。通过深入研究和理解这个项目的代码,可以提升对Struts...
Struts2框架是Java Web开发中的一个流行MVC(Model-View-Controller)框架,它提供了丰富的功能,包括处理表单提交、文件上传等。在Struts2中,文件上传是一个常见的需求,可以帮助用户从客户端上传文件到服务器。...
3.Struts2进行下载处理,能对上传的所有文件进行下载(多个) 4.文件保存的名称UUID生成,不过显示并下载的名称都是原文件名称 (通过UploadFiles处理) 5.对配置文件中的路径可以进行动态读取(不重启服务器) ...
Struts2是一个强大的Java web框架,它为开发者提供了丰富的功能,包括文件上传和下载。在Struts2中处理文件上传和下载是常见的需求,对于构建交互式的Web应用来说至关重要。以下将详细介绍Struts2中如何实现这两个...
Struts1和Struts2是两个非常著名的Java Web框架,它们都提供了处理文件上传和下载的功能,但实现方式有所不同。本文将深入探讨这两个框架在文件操作方面的具体实现。 首先,让我们了解一下Struts1中的文件上传功能...
Struts2是一个强大的Java web框架,它为开发者提供了丰富的功能,包括处理用户表单提交、进行文件上传和下载。在Web应用中,文件上传和下载是常见的需求,例如用户上传头像、下载文档等。Struts2通过其Action类和...
在Struts2中,实现文件上传和下载是常见的需求,对于用户交互和数据交换至关重要。这篇博客文章可能详细讨论了如何在Struts2框架中实现这两个功能。 在Struts2中,文件上传主要依赖于`Commons FileUpload`库,这是...
综上所述,Struts2文件上传下载和表单重复提交涉及多个技术点,包括Struts2的配置、文件操作、HTTP响应头设置、安全性和异常处理。理解并熟练掌握这些知识点,对于构建健壮的Web应用程序至关重要。
使用struts2框架进行文件的上传并限制文件的大小与类型,使用struts2框架实现文件下载
在Struts2中,文件上传功能是一个常用特性,尤其在处理用户提交的多个文件时。本文将详细讲解如何使用Struts2进行多个文件的上传,重点是使用List集合进行上传。 首先,要实现Struts2的文件上传,必须引入必要的...
在Struts2中,文件的上传和下载是常见的功能需求,特别是在处理用户表单提交、数据交换或者提供资源下载服务时。这篇博客文章将探讨如何在Struts2框架下实现文件的上传和下载操作。 首先,我们需要了解文件上传的...
在Struts2中,文件上传和下载是常见的功能需求,主要用于处理用户在Web表单中提交的文件,如图片、文档等。下面将详细介绍Struts2中文件上传和下载的实现方法。 ### 1. 文件上传 #### 1.1 配置Struts2 首先,我们...
在Struts2中,文件上传和下载是常见的功能需求,主要用于处理用户通过表单提交的文件,或者允许用户从服务器下载文件。这些功能极大地增强了Web应用的交互性和实用性。 在Struts2中实现文件上传,主要涉及到以下几...
在基于Struts2的文件上传下载功能中,它提供了处理用户上传文件和提供文件下载的服务。这个完整的源代码是实现这些功能的一个实例,经过测试确保了其正确性和可用性。 首先,我们要理解Struts2中的Action类。Action...