从客户端向服务器端提交信息是非常普遍的,比如常见的注册,客户端通过浏览器在表单里输入姓名等内容提交后就可以将数据传送到服务器端,而request对象就可以获得客户端输入的信息,同时还能具有信息传递功能。
request中有五个方法可以按名称取得客户端上传的非多分类型数据(多分类型将在后面6.7节介绍到),取得的数据可以是通过form表单上传的,也可以是通过url附带的。
1. public String getParameter(String key, String enc)
获取特定名称的上传数据,并根据指定的字符集对取得的数据进行编码后返回。
参数:key表示上传数据项的名称,注意此项区分大小写。
enc表示要对取得的上传数据进行编码的字符集。
返回:指定名称且按指定字符集编码过的上传数据。如果使用多分类型上传或者上传项的名称不存在则返回null。
2. public String getParameter(String key)
获取特定名称的上传数据,并根据默认的字符集对取得的数据进行编码后返回。默认的字符集是指webconfig.xml中systemSet下dataEnc所指定的值(参见2.1节)。
参数:key表示上传数据项的名称,注意此项区分大小写。
返回:指定名称且按默认字符集编码过的上传数据。如果使用多分类型上传或者上传项的名称不存在则返回null。
3. public String[] getParameterValues(String key, String enc)
获取特定名称的上传数据集,并根据指定的字符集对取得的数据集进行编码后返回。
参数:key表示上传数据项的名称,注意此项区分大小写。
enc表示要对取得的上传数据集进行编码的字符集。
返回:指定名称且按指定字符集编码过的上传数据集。如果使用多分类型上传或者上传项的名称不存在则返回null。
4. public String[] getParameterValues(String key)
获取特定名称的上传数据集,并根据默认的字符集对取得的数据集进行编码后返回。默认的字符集是指webconfig.xml中systemSet下dataEnc所指定的值(参见2.1节)。
参数:key表示上传数据项的名称,注意此项区分大小写。
返回:指定名称且按默认字符集编码过的上传数据集。如果使用多分类型上传或者上传项的名称不存在则返回null。
5. public Set<String> getParameterNameSet()
返回上传非多分数据的所有名称。
返回:上传非多分数据的所有名称,所有名称以集合方式返回。如果没有上传任何项则返回空的Set,既Set的size为零。
举一个例子,一个是post.htm静态文件,用于向动态文件传输数据,源程序如下:
1 2 3 4
5 |
<form method="POST" action="post.dqm?key2=kangaroo-egg"> <p>key1: <input type="text" name="key1" size="20"></p> <p>key1: <input type="text" name="key1" size="20"></p> <p><input type="submit" value="提交" name="B1"><input type="reset" value="重置" name="B2"></p> </form> |
动态文件post.dqm用于读取上传数据,源程序如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
<%@page import="java.util.*"%> <pre><%
//读取所有非多分数据项的名称 Set nameSet = request.getParameterNameSet(); if (nameSet.size() == 0) { out.println("没有上传任何非多分数据!"); } else { Iterator<String> nameItor = nameSet.iterator(); while (nameItor.hasNext()) { String tempName = nameItor.next(); out.println("------------------------------------------------------"); out.println("上传非多分项名称:" + tempName);
//getParameter方法 out.println("本非多分项的值:" + request.getParameter(tempName));
//getParameterValues方法 String tempValues[] = request.getParameterValues(tempName); out.println("本非多分项总共有几个值:" + tempValues.length); out.print("本非多分项的所有值:"); for (int i = 0; i < tempValues.length; i++) { out.print(tempValues[i] + ", "); } out.println(""); } }
%></pre> |
当用户访问post.htm,在key1二个文本框内分别填入:hello和world(如图6-1-1)。
图6-1-1
运行结果如下:
------------------------------------------------------ 上传非多分项名称:key1 本非多分项的值:hello 本非多分项总共有几个值:2 本非多分项的所有值:hello, world, ------------------------------------------------------ 上传非多分项名称:B1 本非多分项的值:提交 本非多分项总共有几个值:1 本非多分项的所有值:提交, ------------------------------------------------------ 上传非多分项名称:key2 本非多分项的值:kangaroo-egg 本非多分项总共有几个值:1 本非多分项的所有值:kangaroo-egg, |
从运行结果可以看出getParameter方法只能读取一个值(源程序17行),即使key1含有二个值也只能读取第一个值“hello”,而getParameterValues方法就可以返回指定名称的所有值的数组(源程序20行)。
注意:主机或虚拟主机的maxPostLen参数(参见2.4节和2.5节),如果上传的数据量大于当前主机或虚拟主机所设置的maxPostLen值,那么将会报413错误或直接关闭连接。如果发生这种状况请核实上传数据量是否大于所设的值,并按需要调整。 |
当在一个请求动态文件中需要暂时存储和读取数据就可以用以下二个方法,不过只能在同一个请求动态文件中存储和读取。
1. public void setAttribute(String name, Object value)
存储一个临时的数据以一个特定的名字。
参数:name表示临时存储数据的名称。
value表示临时存储数据的值。
2. public Object getAttribute(String name)
根据指定名字读取临时存储的数据。
参数:name表示临时存储数据的名称。
返回:按指定名字所存储的数据。
这二个方法主要是为了方便用户而设立的,其实在同一个页面中只需要设立变量就可以达到这二个方法的功能,不过在插入文件时,这二个方法可以起到流程清晰的效果。
例如有一个静态文件setAttribute.txt,源程序如下:
1 2 3 4 |
<% request.setAttribute("name", "kangaroo-egg"); request.setAttribute("age", "1"); %> |
动态文件setAttribute.dqm中插入了上面那个静态文件,源程序如下:
1 2 3 4 |
<%@include file="setAttribute.txt"%> <pre> name: <%=request.getAttribute("name")%> age: <%=request.getAttribute("age")%></pre> |
执行的结果为:
name: kangaroo-egg
age: 1
|
从执行结果来看setAttribute.txt将值存入(源程序2、3行),getAttribute.dqm将值读取(源程序3、4行)。当然用二个变量也可以起到相同作用,不过似乎用本方法更易于理解。
有时需要获取客户端访问时的信息,比如客户端的IP地址,客户端软件的版本等,本节要介绍读取客户端信息的一些方法。
1. public String getRemoteAddr()
读取客户端的IP 地址。
返回:客户端IP地址,返回的格式例如192.168.0.100
2. public String getRemoteHost()
读取客户端的完全主机名称。
返回:客户端完全主机名称,返回的格式例如localhost。
3. public int getRemotePort()
读取客户端连接服务器时所用的端口号。
返回:端口号,返回的格式例如3323。
4. public String[] getAllHttpHead()
读取客户端请求的所有http头。
返回:客户端请求的所有http头,通常请求的http头是多个的。
5. public String getHeader(String name)
根据http头功能标签来读取对应的值。
参数:name表示http头的功能标签,此参数不区分大小写。
返回:功能标签所对应的值。如果功能标签不存在则返回null。
我们来看一个例子,clientInfo.dqm用于显示当前访问的客户端信息,源代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<pre> 当前访问的客户端信息
客户端IP地址:<%=request.getRemoteAddr()%> 客户端完全主机名:<%=request.getRemoteHost()%> 客户端当前连接所用的端口:<%=request.getRemotePort()%>
客户端请求http头:<% String[] allHttpHead = request.getAllHttpHead(); for (int i = 0; i < allHttpHead.length; i++) { out.println(allHttpHead[i]); } %>
http头Accept-Language功能标签的值:<%=request.getHeader("accept-language")%>
</pre> |
不同的环境和浏览器所执行的结果有可能不一样,我们的执行的结果为:
当前访问的客户端信息
客户端IP地址:127.0.0.1
客户端完全主机名:localhost
客户端当前连接所用的端口:1369
客户端请求http头:
GET /clientInfo.jsp HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*
Referer: http://localhost:8080
Accept-Language: zh-cn
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)
Host: localhost:8080
Connection: Keep-Alive
Cookie: DQMSESSIONID=23ec026c-101d-4d94-8fe4-20b03af680f9
http头Accept-Language功能标签的值:zh-cn |
上一节介绍了如何获取客户端访问时的信息,既然有时需要读取客户端信息,那么难免有时也需要读取服务器端的信息,本节介绍一下读取服务器端的方法。
1. public String getLocalAddr()
读取服务器当前连接的IP 地址,因为有时一台服务器有多个IP地址。
返回:服务器IP地址,返回的格式例如192.168.0.100
2. public String getLocalHost()
读取服务器的完全主机名称。
返回:服务器完全主机名称,返回的格式例如localhost。
3. public int getLocalPort()
读取服务器被连接时所用的端口号。
返回:端口号,返回的格式例如8080。
同样看一个例子,serverInfo.dqm同来显示当前访问的服务器信息,源程序如下:
1 2 3 4 5 6 7 8 |
<pre> 当前服务器端信息
服务器IP地址:<%=request.getLocalAddr()%> 服务器完全主机名:<%=request.getLocalHost()%> 服务器当前连接所用的端口:<%=request.getLocalPort()%>
</pre> |
执行结果为:
当前服务器端信息
服务器IP地址:127.0.0.1
服务器完全主机名:localhost
服务器当前连接所用的端口:8080
|
5.6节介绍了如何在客户端保存cookie信息的方法,而本节就是介绍如何读取那些先前保存的cookie信息。
1. public String getCookieValue(String cookieName)
读取指定的cookie项的值。
参数:cookieName表示指定的cookie项。
返回:对应cookie项的值。如果指定的cookie项没有找到则返回null。
2. public DCookie[] getCookies()
读取所有先前保存的cookie。
返回:先前所有保存的cookie,类型为DCookie类的数组。如果没有任何cookie则返回一个长度为0的数组。
具体的使用方法我们将在第7章介绍。
我们有时需要获取当前访问的动态文件所在的目录等信息,本节将会介绍如何获取这些信息。
1. public String getNowFolder()
获取当前访问的动态文件所在目录的绝对地址。
返回:当前访问的动态文件所在目录地址,目录以String形式返回,且是绝对地址形式。这里不会返回null,除非系统出错。
2. public String getNowPath()
获取当前访问的动态文件的绝对路径地址。
返回:当前访问的动态文件地址,目录以String形式返回,且是绝对地址形式。
3. public File getNowFile()
获取当前访问的动态文件,通过返回值可以获得动态文件的更多信息。
返回:当前访问的动态文件。
4. public String getWebPath()
获取当前主机或虚拟主机的根目录地址,其值就等于2.4和2.5节中webPath所设定目录的对绝地址。
返回:当前主机或虚拟主机的根目录地址,目录以String形式返回,且是绝对地址形式。
5. public String getNowUrlFolder()
获取当前访问的动态文件所在目录的url相对地址。
返回:url相对地址,url地址以String形式返回,且是相对地址形式。
6. public String getNowUrlQuery()
获取访问当前动态文件时url中所附带查询部分,即url中问号后的部分。注意返回的查询部分已经是经过浏览器编码的(编码请参见2.1节的urlEnc)。
返回:获取访问当前动态文件时url中所附带查询部分,如果没有附带查询部分则返回null。
举一个例子,getDqmFileInfo.dqm动态文件用于获取它本身的一些信息,我们将此动态文件放入test_folder目录下。源程序如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<%@page import="java.util.Date"%>
<pre> 当前访问主机的根目录:<%=request.getWebPath()%>
当前访问的动态文件所在绝对目录:<%=request.getNowFolder()%> 当前访问的动态文件的绝对地址:<%=request.getNowPath()%> 当前访问的动态文件所在目录的相对URL:<%=request.getNowUrlFolder()%> 访问当前动态文件的URL附带的查询部分:<%=request.getNowUrlQuery()%>
利用request.getNowFile()方法获取更多信息-------------------------- <%File file = request.getNowFile();%> 当前访问的动态文件名:<%=file.getName()%> 当前访问的动态文件的大小:<%=file.length()%> 当前访问的动态文件最后修改时间:<%=new Date(file.lastModified())%> </pre> |
不同的环境所执行的结果有可能不一样,我们的执行的结果为:
1 2 3 4 5 6 7 8 9 10 11 12 |
当前访问主机的根目录:D:\webapp
当前访问的动态文件所在绝对目录:D:\webapp\test_folder 当前访问的动态文件的绝对地址:D:\webapp\test_folder\getDqmFileInfo.dqm 当前访问的动态文件所在目录的相对URL:/test_folder/ 访问当前动态文件的URL附带的查询部分:null
利用request.getNowFile()方法获取更多信息--------------------------
当前访问的动态文件名:getDqmFileInfo.dqm 当前访问的动态文件的大小:554 当前访问的动态文件最后修改时间:Tue Dec 13 15:23:47 GMT+08:00 2005 |
动态文件的路径信息在不同的设置下会不同,我是将主机根目录设置在d:\webapp下,所以动态文件及其存放目录的绝对地址都会含有这个根目录(执行结果第3和4行)。URL的查询部分为null是因为本次请求没有附带查询部分(执行结果第6行)。利用getNowFile()方法返回File类本身的方法可以获得更多的信息,如上面取得的文件大小和最后修改时间(执行结果8到12行)。
7. public boolean isSSL()
获取当前访问是普通的http还是安全的https。因为服务器可以同时开启http和https(参见2.2节),所以用户可以通过二种方式来访问当前资源,此方法用于判断当前的访问是哪种方式。
返回:当本次访问是https形式则返回true,否则返回false。
isSSL()方法也是非常有用的,我们看一个例子,hr_system目录下有一个login.dqm,这是我们模拟的一个人事系统登录页面,我们来看一下它的源代码:
1
2 3 4 5
6 7 8 9 10 11 12 13 14 15 16
17 18 19 20 21 22 23 24
25 26 27 28 29 30 31 32 33 34 35 36 |
<p align="center"><font color="#0000FF" size="7"><b>欢迎使用本系统</b></font></p> <form method="POST" action=""> <p align="center">用户名:<input type="text" name="T1" size="20"></p> <p align="center">密码:<input type="text" name="T2" size="20"></p> <p align="center"><input type="submit" value="Submit" name="B1"><input type="reset" value="Reset" name="B2"></p> </form>
<% //判断本次访问是http形式还是https形式 boolean isSSL = request.isSSL(); String bgColor, link, linkInfo; if (isSSL) { //如果当前是https访问方式 //背景色为淡黄色 bgColor = "#FFFF99"; //切换http方式的链接 link = "http://localhost:8080" + request.getNowUrlFolder() + request.getNowFile().getName(); //提示用户如何切换到http方式 linkInfo = "通过普通方式访问"; } else { //如果当前是http访问方式 //背景色为灰色 bgColor = "#C0C0C0"; //切换到https方式的链接 link = "https://localhost:8443" + request.getNowUrlFolder() + request.getNowFile().getName(); //提示用户如何切换到https方式 linkInfo = "通过安全方式访问"; }
%>
<table border="0" width="100%" id="table1" bgcolor="<%=bgColor%>"> <tr> <td> <p align="right"><a href="<%=link%>"><%=linkInfo%></a></td> </tr> </table> |
当通过http形式访问此动态文件时最下方会提示可以用安全的https方式来登录系统,提示框的背景色是灰的(提示当前是在http状态下访问),同时提供了链接至https的地址,如图6-6-1。
图6-6-1
当切换到https形式访问此动态文件时最下方又会提示可以用普通的http方式来登录系统,提示框的背景色又变为了淡黄色(提示当前是在https状态下访问),同时提供了链接至http的地址,如图6-6-2。
图6-6-2
这样用户可以按照提示方便的在http和https二种连接方式间进行切换。源程序12行是用来区分http和https状态的,同时为了用链接切换这二种状态必须定义完整的url,参见源程序16和24行。
注意:要使本示例成功运行必须同时开启http和https服务(参见2.2节),同时http服务端口要设置为8080,https服务端口要设置为8443。 |
6.1节介绍了如何取得客户端上传的数据,但是普通上传的数据只能是少量且是文本形式的,而多分(multipart)类型可以上传大量和各种类型的数据。比如二进制数据,依靠这个功能就可以一次同时向服务器上传图片、音乐等二进制文件和文本数据。
1. public DMpFormData.FormDataEntry getFormDataEntry(String key)
参数:key表示上传多分数据的名称,注意此项区分大小写。
返回:多分数据类型,此返回值是FormDataEntry类型的,此类型我们将会在本节进行介绍。如果不是多分数据或者多分项的名称不存在则返回null。
2. public DMpFormData.FormDataEntry[] getFormDataEntryValues(String key)
根据指定的上传多分数据项的名称返回多分数据类型集。
参数:key表示上传多分数据的名称,注意此项区分大小写。
返回:多分数据类型集,此返回值是FormDataEntry类型的数组,此类型我们将会在本节进行介绍。如果不是多分数据或者多分项的名称不存在则返回null。
3. public Set<String> getFormDataNameSet()
返回上传多分数据的所有名称。
返回:上传多分数据的所有名称,所有名称以集合方式返回。如果上传的不是多分类型或没有项则返回null。
4. public int getContentLength()
取得post上传数据的总字节数,即post请求的身体(Body)长度。
返回:如果是多分数据则返回全部上传多分数据的大小,包括描述数据属性的数据。如果不是多分数据(6.1节介绍的上传)则返回普通form上传的大小,也包括描述数据属性的数据。请注意通过url附带的数据不会包含在内。如果没有上传数据则返回0。
第一个方法返回的是一个FormDataEntry类型,多分数据及其信息都包含在此类中。FormDataEntry是com.kangaroo_egg.dqm.DMpFormData的内部类,我们来看一下FormDataEntry这个内部类方法。
1. public String getValue(String enc) throws UnsupportedEncodingException
将指定的多分数据按指定的字符集编码后以字符内容返回。如果此多分数据是二进制格式则也会将这些数据编码成字符格式返回。
参数:enc表示将数据进行字符编码的字符集。
返回:以字符形式返回多分数据。
异常:如果enc所指定的字符集不支持则抛出异常。
2. public String getValue() throws UnsupportedEncodingException
将指定的多分数据按默认的字符集编码后以字符内容返回。如果此多分数据是二进制格式则也会将这些数据编码成字符格式返回。默认的字符集是指webconfig.xml中systemSet下dataEnc所指定的值(参见2.1节)。
返回:以字符形式返回多分数据。
异常:如果默认的字符集不支持则抛出异常。
3. public int getContentSize()
获取当前项的多分数据量大小,不包括描述数据属性的数据大小。
返回:当前多分数据项字节数。
4. public boolean isFile()
判断当前项的多分数据是否是上传的文件,因为文本项也可以用多分形式上传。
返回:如果是文件上传项则返回true,否则返回false。
5. public String getAbsolutePath(String enc) throws UnsupportedEncodingException
将上传文件的绝对路径和文件名按指定的字符集编码后返回。
参数:enc表示需将绝对路径和文件名进行字符编码的字符集。
返回:如果是文件上传项则返回上传文件的绝对路径和文件名。如果不是文件上传项则返回null。如果是文件上传项但没有选择文件上传则返回空字符串。可以用isFile()方法判断是否是文件上传项。
异常:如果enc所指定的字符集不支持则抛出异常。
6. public String getAbsolutePath() throws UnsupportedEncodingException
将上传文件的绝对路径和文件名按默认的字符集编码后返回。默认的字符集是指webconfig.xml中systemSet下dataEnc所指定的值(参见2.1节)。
返回:如果是文件上传项则返回上传文件的绝对路径和文件名。如果不是文件上传项则返回null。如果是文件上传项但没有选择文件上传则返回空字符串。可以用isFile()方法判断是否是文件上传项。
异常:如果默认的字符集不支持则抛出异常。
7. public String getFileName(String enc) throws UnsupportedEncodingException
将上传文件的文件名按指定的字符集编码后返回。
参数:enc表示需将上传文件的文件名进行字符编码的字符集。
返回:如果是文件上传项则返回上传文件的文件名。如果不是文件上传项则返回null。如果是文件上传项但没有选择文件上传则返回空字符串。可以用isFile()方法判断是否是文件上传项。
异常:如果enc所指定的字符集不支持则抛出异常。
8. public String getFileName() throws UnsupportedEncodingException
将上传文件的文件名按默认的字符集编码后返回。
返回:如果是文件上传项则返回上传文件的文件名。如果不是文件上传项则返回null。如果是文件上传项但没有选择文件上传则返回空字符串。可以用isFile()方法判断是否是文件上传项。
异常:如果默认的字符集不支持则抛出异常。
9. public String getFileExtName(String enc) throws UnsupportedEncodingException
将上传文件的扩展名按指定的字符集编码后返回。
参数:enc表示需将上传文件的扩展名进行字符编码的字符集。
返回:如果是文件上传项则返回上传文件的扩展名,如果没有扩展名则返回整个文件名。如果不是文件上传项则返回null。如果是文件上传项但没有选择文件上传则返回空字符串。可以用isFile()方法判断是否是文件上传项。
异常:如果enc所指定的字符集不支持则抛出异常。
10. public String getFileExtName() throws UnsupportedEncodingException
将上传文件的扩展名按默认的字符集编码后返回。
返回:如果是文件上传项则返回上传文件的扩展名,如果没有扩展名则返回整个文件名。如果不是文件上传项则返回null。如果是文件上传项但没有选择文件上传则返回空字符串。可以用isFile()方法判断是否是文件上传项。
异常:如果默认的字符集不支持则抛出异常。
11. public String getName()
获取当前上传项的名称,此名称就是request. getFormDataEntry(String key)方法中key的值。此方法设立的目的是方便查看当前在操作的多分数据名称。
返回:当前上传项的名称。
12. public String getContentType()
获取当前上传项的MIME类型,此类型根据上传文件的类型来确定。
返回:上传项的MIME类型。比如上传一张jpg图片则返回image/pjpeg,上传一个二进制文件则返回application/octet-stream,上传一个文本文件则返回text/plain。如果本项是文件上传项但是并没有上传文件则必定返回application/octet-stream。如果上传的数据不是文件,比如通过文本行上传则返回null,所以通过本方法返回值是否为null也可以判断是否是文件上传项,参见本节isFile方法。
13. public String getContentDisposition()
取得当前上传项内容Disposition信息。
返回:当前上传项内容Disposition信息,通常这个信息为form-data,表示本多分数据是由html的form表单上传的。
14. public void saveToFile(String fileName, boolean append) throws IOException
将上传的数据保存为文件。
参数:filename存储文件的路径名称,可以是绝对路径也可是相对路径。相对路径如:“../xxx.txt”、“test/xxx.txt”等,绝对路径如:“c:\\xxx.txt”、“/xxx.txt”等。不过注意如果要使用‘\’字符必须使用转义的‘\\’取代。同时如果在windows下以‘/’或‘\\’开头则表示从当前动态文件所在盘的根目录开始,而在linux或unix下则表示从根目录开始。
append如果为true则表示目标文件存在时数据将添加到已存在文件末尾。为false时不管目标文件是否存在都重写文件。
异常:如果在写入文件时遇到问题则此方法会抛出IOException异常。
15. public boolean saveToFile(File file, boolean overWrite, boolean append)
将上传的数据保存为文件。
参数:file将数据存储的目标文件。
overWrite如果目标文件存在则是否允许修改它。
append如果目标文件存在是进行添加还是重写。
返回:保存文件是否成功。
如果目标文件存在:overWrite为false则表示不允许修改已存在的文件,那么无论append为何值,都将不作任何事情,返回false以表示保存文件失败。
overWrite为true则表示允许修改已存在的文件,那么依据append的值来判断是添加还是重写文件。如果添加或重写成功则返回true,如果操作中发生任何异常则返回false以表示添加或重写文件过程失败。
如果目标文件不存在:overWrite则无论为何值都将根据append的值来进行添加或者重写。如果添加或重写成功则返回true,如果操作中发生任何异常则返回false以表示添加或重写文件过程失败。
注意:以上saveToFile方法直接写相对地址定义文件,如: <%saveToFile(new File("save.txt"), true, false);%> 那么目标文件将保存在服务器运行的目录下,如果要产生相对于当前动态文件的路径,那么可以使用6.6节介绍的方法获取。如: <%saveToFile(new File(request.getNowFolder + "/save.txt"), true, false);%> |
16. public int read()
读取上传数据的一个字节。此方法可以和输出流的write(int b)方法配合使用,如往数据库中写入二进制数据就可使用这个方法。
返回:上传数据中的下一个字节,如果返回-1则表示已读到末尾。
17. public void resetRead()
复位read()方法,即执行本方法后,read又从上传数据的第一个字节开始读取。
为了更好理解上述那么多方法,我们举些例子,首先我们创建一个upfile.htm静态文件,用于象动态文件上传数据,源程序如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<form method="POST" enctype="multipart/form-data" action="upfile.dqm"> <p>自我介绍:</p> <p><textarea rows="7" name="intro" cols="31"></textarea></p> <p> 性别:<input type="radio" value="男" checked name="gender">男 <input type="radio" name="gender" value="女">女 </p> <p> 爱好:<input type="checkbox" name="favorite" value="足球">足球 <input type="checkbox" name="favorite" value="漫画">漫画 <input type="checkbox" name="favorite" value="上网">上网</p>
<input type="FILE" name="upfile" size="50"><br> <p><input type="submit" value="提交" name="button"><input type="reset" value="重置" name="B2"></p> </form> |
注意第1行中enctype="multipart/form-data",这表明上传的是多分类型数据。第一行中action="upfile.dqm"表明上传数据由upfile.dqm这个动态文件处理,这个动态文件源程序如下:
1 2 3 4 5 6 7 8 9 10 11 12
13 14 15 16 17 18 19 20 21 22 23 24
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
<%@page import="java.util.*"%>
<pre>
本次上传数据字节数:<%=request.getContentLength()%>
<% //读取所有多分数据项的名称 Set nameSet = request.getFormDataNameSet(); %>
本次上传的多分数据共有几项:<%if (nameSet != null) out.print(nameSet.size()); else out.print("无多分数据");%>
<% if (nameSet != null) { Iterator<String> nameItor = nameSet.iterator(); while (nameItor.hasNext()) { String tempName = nameItor.next(); out.println("------------------------------------------------------");
//读取多分各项的FormDataEntry类 DMpFormData.FormDataEntry tempFDE = request.getFormDataEntry(tempName);
out.println("多分项名称:" + tempFDE.getName()); //此输出的名称就是当前tempName的值
out.println("当前多分项的MIME类型:" + tempFDE.getContentType());
out.println("当前多分项的Disposition信息:" + tempFDE.getContentDisposition());
//输出本项的多份数据大小 out.println("当前多分项字节数:" + tempFDE.getContentSize());
if (!tempFDE.isFile()) { //如果上传的不是文件,则输出其内容 out.println("内容为:" + tempFDE.getValue()); } else { //如果上传的是文件 out.println("本项上传的是文件"); out.println("上传文件的路径:" + tempFDE.getAbsolutePath()); out.println("上传的文件名:" + tempFDE.getFileName()); out.println("上传的文件扩展名:" + tempFDE.getFileExtName()); out.println("保存上传的文件"); if (tempFDE.getContentSize() > 0) { //如果有上传文件 tempFDE.saveToFile("上传文件.txt", false); } }
} } %> </pre> |
我们开始上传数据,操作如图6-7-1。
图6-7-1
我提交后的结果为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
本次上传数据字节数:8040
本次上传的多分数据共有几项:5
------------------------------------------------------ 多分项名称:upfile 当前多分项的MIME类型:text/plain 当前多分项的Disposition信息:form-data 当前多分项字节数:7334 本项上传的是文件 上传文件的路径:D:\我的自传.txt 上传的文件名:我的自传.txt 上传的文件扩展名:.txt 保存上传的文件 ------------------------------------------------------ 多分项名称:gender 当前多分项的MIME类型:null 当前多分项的Disposition信息:form-data 当前多分项字节数:2 内容为:男 ------------------------------------------------------ 多分项名称:intro 当前多分项的MIME类型:null 当前多分项的Disposition信息:form-data 当前多分项字节数:12 内容为:我是袋鼠蛋。 ------------------------------------------------------ 多分项名称:favorite 当前多分项的MIME类型:null 当前多分项的Disposition信息:form-data 当前多分项字节数:4 内容为:漫画 ------------------------------------------------------ 多分项名称:button 当前多分项的MIME类型:null 当前多分项的Disposition信息:form-data 当前多分项字节数:4 内容为:提交 |
我们来分析以上输出的结果,本次上传的多分数据总共有5项,可以看到upfile是文件上传项,如果有上传文件则显示该文件上传路径、文件名等信息,且upfile项的字节数就是上传文件的大小。同时我们将上传的文件保存在动态文件相同目录下(使用相对路径),名为“上传文件.txt”。
我们再来看一个有趣的现象,结果第1行显示本次上传的字节数为8040,upfile、gender、intro、favorite、button各项的字节数分别为7334(执行结果11行)、2(执行结果21行)、12(执行结果27行)、4(执行结果33行)、4(执行结果39行),但是所有项字节数加起来只有7356,那么为什么本次上传的所有字节数为8040呢?其实前面已经提到过了,因为其中含有描述这些数据的信息,而这些信息是由服务器处理的,所以各项显示的是真正的数据大小,而描述信息已经被剔除了。
另一个现象是提交数据时“爱好”这项同时选择了“漫画”和“上网”,可是结果中只有“漫画”,这时就要用getFormDataEntryValues(String key)方法了。我们来看另一个例子,upfile1.htm可以让用户多选爱好,源程序如下:
1 2 3 4 5 6 7 8 9 10 11 |
<form method="POST" enctype="multipart/form-data" action="upfile1.dqm"> <p> 爱好:<input type="checkbox" name="favorite" value="足球">足球 <input type="checkbox" name="favorite" value="漫画">漫画 <input type="checkbox" name="favorite" value="上网">上网 </p> <p> <input type="submit" value="提交" name="button"> <input type="reset" value="重置" name="B2"> </p> </form> |
同样上面第1行enctype="multipart/form-data"表明是多分类型,action="upfile1.dqm"表明了处理的动态文件,源程序如下:
1 2 3 4 5 6
7 8 9 10 11 12 13 14 15 |
<%@page import="java.util.*"%>
<pre>
<% DMpFormData.FormDataEntry[] tempFDE = request.getFormDataEntryValues("favorite"); if (tempFDE != null) { out.println("favorite项:"); for (int i = 0; i < tempFDE.length; i++) { out.println("内容为:" + tempFDE[i].getValue()); } } %>
</pre> |
执行时操作如图6-7-2。
图6-7-2
同时选择了“足球”和“上网”,则提交后结果如下:
favorite项: 内容为:足球 内容为:上网 |
可以看到多项选择的内容都读取到了,而读取这些选项的代码就在upfile1.dqm的第6行。
注意:主机或虚拟主机的maxPostLen参数(参见2.4节和2.5节),如果上传的数据量大于当前主机或虚拟主机所设置的maxPostLen的值,那么将会报413错误或直接关闭连接。如果发生这种状况请核实上传数据量是否大于所设的值,并按需要调整。 |