在某些情况下,需要用Java applicatioin来模拟form,向服务器(本文以servlet为例)发送http post请求,包括提交表单域中的数据以及上传文件。如果仅仅是传递form中的数据,而不包含上传文件,那是很简单的,比如Java application可以这么写:
package com.pat.postrequestemulator;
importjava.io.BufferedReader;
importjava.io.InputStream;
importjava.io.InputStreamReader;
importjava.io.OutputStreamWriter;
importjava.net.HttpURLConnection;
importjava.net.URL;
public class PostRequestEmulator
{
public static void main(String[] args)throws Exception
{
// 服务地址
URL url = newURL("http://127.0.0.1:8080/test/upload");
// 设定连接的相关参数
HttpURLConnection connection= (HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setRequestMethod("POST");
OutputStreamWriter out = newOutputStreamWriter(connection.getOutputStream(), "UTF-8");
// 向服务端发送key = value对
out.write("username=kevin&password=pass");
out.flush();
out.close();
// 获取服务端的反馈
String strLine="";
String strResponse ="";
InputStream in =connection.getInputStream();
BufferedReader reader = newBufferedReader(new InputStreamReader(in));
while((strLine =reader.readLine()) != null)
{
strResponse +=strLine +"\n";
}
System.out.print(strResponse);
}
}
服务端的servlet可以这么写:
packagecom.pat.handlinghttprequestservlet;
importjava.io.IOException;
importjava.io.PrintWriter;
importjavax.servlet.ServletException;
importjavax.servlet.http.HttpServlet;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
public class HandlingHttpRequestServlet extends HttpServlet
{
private static final longserialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequestreq, HttpServletResponse resp)
throws ServletException, IOException
{
super.doGet(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throwsServletException, IOException
{
String username =req.getParameter("username"); //获取username所对应的value
String password =req.getParameter("password"); //获取password所对应的value
System.out.println("Thereceived username and password is: " + username + "/" +password);
// 向请求端发回反馈信息
PrintWriter out =resp.getWriter();
out.print("OK");
out.flush();
out.close();
super.doPost(req, resp);
}
}
一切看起来都不复杂。但是如果要模拟的表单,除了要向服务器传递如上面的“key = value”这样的普通信息,同时还要上传文件,事情就复杂得多。下面详解如下:
1. 准备
玄机逸士很久没有开发web方面的应用了,所以机器上没有现成的环境,为此先要进行这方面的准备。
a) 到http://tomcat.apache.org 上下载tomcat压缩包apache-tomcat-6.0.33.zip,将其解压到指定目录即可,
如:D:\Tomcat6
b) 到http://commons.apache.org上下载用于文件上传的两个包:commons-fileupload-1.2.2-bin.zip
和commons-io-2.1-bin.zip, commons-fileupload依赖于commons-io,但在编程的过程中,
不会直接用到commons-io
c) 检查Tomcat的安装是否成功。双击D:\Tomcat6\bin目录中的startup.bat文件,就可以启动tomcat。
打开浏览器,访问http://localhost:8080/,如果出现tomcat相关的页面,则说明tomcat安装成功。
d) 在D:\Tomcat6\webapps目录下创建一个test子目录,我们等会开发的servlet就将部署在这里。在
test目录下再建立两个目录WEB-INF(必须大写)和upload,在WEB-INF下面 创建两个目录classes和lib,
同时新建一个web.xml文件;在upload目录下,创建一个temp子目录,这些工作做完以后,test目录
下面的目录文件结构如下图所示。
其中的classes目录,用来存放将要开发的servlet,lib用来存放commons-fileupload和commons-io相关的jar包,web.xml是一些应用描述信息;upload用于存放客户端(即我们要开发的Java application)上传过来的文件,temp则用于存放上传过程中可能产生的一些临时文件。
e) 将commons-fileupload-1.2.2-bin.zip和commons-io-2.1-bin.zip解压,可以得到commons-fileupload-
1.2.2.jar和commons-io-2.1.jar,我们将这两个文件拷贝到d)中创建的lib目录中。
f) 编辑web.xml使之如下:
<?xmlversion="1.0" encoding="ISO-8859-1"?>
<!--
Licensed to the Apache Software Foundation(ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional informationregarding copyright ownership.
The ASF licenses this file to You under theApache License, Version 2.0
(the "License"); you may not usethis file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreedto in writing, software
distributed under the License is distributedon an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,either express or implied.
See the License for the specific languagegoverning permissions and
limitations under the License.
-->
<web-appxmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaeehttp://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<servlet>
<servlet-name>Hello</servlet-name>
<servlet-class>com.pat.handlinghttprequestservlet.HandlingHttpRequestServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Hello</servlet-name>
<url-pattern>/upload</url-pattern>
</servlet-mapping>
</web-app>
这个web.xml可以先从D:\Tomcat6\webapps\examples\WEB-INF下面拷贝过来,再进行如上黑体字所示的修改即可。<servlet>标签描述的是servlet代码方面的资料,其中<servlet-name>Hello</servlet-name>是给这个servlet起一个名字Hello,它必须和下面的<servlet-mapping>中的<servlet-name>一致,该名字具体是什么可以随意写定。
<servlet-class>com.pat.handlinghttprequestservlet.HandlingHttpRequestServlet</servlet-class>说明了完整的servlet类名,即servlet的类名为HandlingHttpRequestServlet,它位于包com.pat.handlinghttprequestservlet中。
<url-pattern>/upload</url-pattern>,说明了如果客户端向“http://Web服务器的URL地址:端口号/test/upload”发出了请求,则该请求将由位于包com.pat.handlinghttprequestservlet中的HandlingHttpRequestServlet进行处理。
到此,前期准备工作结束。下面准备写代码。
2. Servlet的代码
packagecom.pat.handlinghttprequestservlet;
importjava.io.File;
importjava.io.IOException;
importjava.io.PrintWriter;
importjava.util.ArrayList;
importjavax.servlet.ServletException;
importjavax.servlet.http.HttpServlet;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
importorg.apache.commons.fileupload.FileItem;
importorg.apache.commons.fileupload.disk.DiskFileItemFactory;
importorg.apache.commons.fileupload.servlet.ServletFileUpload;
public class HandlingHttpRequestServlet extends HttpServlet
{
private static final longserialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequestreq, HttpServletResponse resp)
throws ServletException, IOException
{
super.doGet(req, resp);
}
@SuppressWarnings({"unchecked", "deprecation" })
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throwsServletException, IOException
{
DiskFileItemFactory factory =new DiskFileItemFactory();
//得到绝对文件夹路径,比如"D:\\Tomcat6\\webapps\\test\\upload"
String path = req.getRealPath("/upload");
//临时文件夹路径
String repositoryPath =req.getRealPath("/upload/temp");
// 设定临时文件夹为repositoryPath
factory.setRepository(newFile(repositoryPath));
// 设定上传文件的阈值,如果上传文件大于1M,就可能在repository
// 所代 表的文件夹中产生临时文件,否则直接在内存中进行处理
factory.setSizeThreshold(1024* 1024);
//System.out.println("----"+ req.getContextPath()); // 得到相对文件夹路径,比如 "/test"
// 创建一个ServletFileUpload对象
ServletFileUpload uploader =new ServletFileUpload(factory);
try
{
// 调用uploader中的parseRequest方法,可以获得请求中的相关内容,
// 即一个FileItem类型的ArrayList。FileItem是在
// org.apache.commons.fileupload中定义的,它可以代表一个文件,
// 也可以代表一个普通的form field
ArrayList<FileItem>list = (ArrayList<FileItem>)uploader.parseRequest(req);
System.out.println(list.size());
for(FileItemfileItem : list)
{
if(fileItem.isFormField()) // 如果是普通的form field
{
Stringname = fileItem.getFieldName();
Stringvalue = fileItem.getString();
System.out.println(name+ " = " + value);
}
else // 如果是文件
{
Stringvalue = fileItem.getName();
intstart = value.lastIndexOf("\\");
StringfileName = value.substring(start + 1);
// 将其中包含的内容写到path(即upload目录)下,
// 名为fileName的文件中
fileItem.write(newFile(path, fileName));
}
}
}
catch(Exception e)
{
e.printStackTrace();
}
// 向客户端反馈结果
PrintWriter out =resp.getWriter();
out.print("OK");
out.flush();
out.close();
super.doPost(req, resp);
}
}
再在classes目录建立如下目录结构com\pat\handlinghttprequestservlet,这用来代表HandlingHttpRequestServlet这个servlet所在的包名,将编译好的HandlingHttpRequestServlet.class,拷贝到这个目录下,然后启动(或者重新启动)tomcat
3. Java application的代码
package com.pat.postrequestemulator;
importjava.io.BufferedReader;
importjava.io.DataInputStream;
importjava.io.File;
import java.io.FileInputStream;
importjava.io.InputStream;
importjava.io.InputStreamReader;
importjava.io.OutputStream;
importjava.io.Serializable;
importjava.net.HttpURLConnection;
importjava.net.URL;
importjava.util.ArrayList;
public classPostRequestEmulator
{
public static void main(String[] args)throws Exception
{
// 设定服务地址
String serverUrl ="http://127.0.0.1:8080/test/upload";
// 设定要上传的普通Form Field及其对应的value
// 类FormFieldKeyValuePair的定义见后面的代码
ArrayList<FormFieldKeyValuePair> ffkvp = new ArrayList<FormFieldKeyValuePair>();
ffkvp.add(newFormFieldKeyValuePair("username", "Patrick"));
ffkvp.add(newFormFieldKeyValuePair("password", "HELLOPATRICK"));
ffkvp.add(newFormFieldKeyValuePair("hobby", "Computer programming"));
// 设定要上传的文件。UploadFileItem见后面的代码
ArrayList<UploadFileItem> ufi = new ArrayList<UploadFileItem>();
ufi.add(newUploadFileItem("upload1", "E:\\Asturias.mp3"));
ufi.add(newUploadFileItem("upload2", "E:\\full.jpg"));
ufi.add(newUploadFileItem("upload3", "E:\\dyz.txt"));
// 类HttpPostEmulator的定义,见后面的代码
HttpPostEmulator hpe = new HttpPostEmulator();
String response =hpe.sendHttpPostRequest(serverUrl, ffkvp, ufi);
System.out.println("Responsefrom server is: " + response);
}
}
classHttpPostEmulator
{
//每个post参数之间的分隔。随意设定,只要不会和其他的字符串重复即可。
private static final String BOUNDARY ="----------HV2ymHFg03ehbqgZCaKO6jyH";
public StringsendHttpPostRequest(String serverUrl,
ArrayList<FormFieldKeyValuePair>generalFormFields,
ArrayList<UploadFileItem>filesToBeUploaded) throws Exception
{
// 向服务器发送post请求
URL url = newURL(serverUrl/*"http://127.0.0.1:8080/test/upload"*/);
HttpURLConnection connection= (HttpURLConnection) url.openConnection();
// 发送POST请求必须设置如下两行
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setUseCaches(false);
connection.setRequestMethod("POST");
connection.setRequestProperty("Connection","Keep-Alive");
connection.setRequestProperty("Charset","UTF-8");
connection.setRequestProperty("Content-Type","multipart/form-data; boundary=" + BOUNDARY);
// 头
String boundary = BOUNDARY;
// 传输内容
StringBuffer contentBody =new StringBuffer("--" + BOUNDARY);
// 尾
String endBoundary ="\r\n--" + boundary + "--\r\n";
OutputStream out =connection.getOutputStream();
// 1. 处理普通表单域(即形如key = value对)的POST请求
for(FormFieldKeyValuePairffkvp : generalFormFields)
{
contentBody.append("\r\n")
.append("Content-Disposition: form-data; name=\"")
.append(ffkvp.getKey() + "\"")
.append("\r\n")
.append("\r\n")
.append(ffkvp.getValue())
.append("\r\n")
.append("--")
.append(boundary);
}
String boundaryMessage1 =contentBody.toString();
out.write(boundaryMessage1.getBytes("utf-8"));
// 2. 处理文件上传
for(UploadFileItem ufi :filesToBeUploaded)
{
contentBody = newStringBuffer();
contentBody.append("\r\n")
.append("Content-Disposition:form-data; name=\"")
.append(ufi.getFormFieldName() +"\"; ") // form中field的名称
.append("filename=\"")
.append(ufi.getFileName() +"\"") //上传文件的文件名,包括目录
.append("\r\n")
.append("Content-Type:application/octet-stream")
.append("\r\n\r\n");
StringboundaryMessage2 = contentBody.toString();
out.write(boundaryMessage2.getBytes("utf-8"));
// 开始真正向服务器写文件
File file = newFile(ufi.getFileName());
DataInputStream dis= new DataInputStream(new FileInputStream(file));
int bytes = 0;
byte[] bufferOut =new byte[(int) file.length()];
bytes =dis.read(bufferOut);
out.write(bufferOut,0, bytes);
dis.close();
contentBody.append("------------HV2ymHFg03ehbqgZCaKO6jyH");
StringboundaryMessage = contentBody.toString();
out.write(boundaryMessage.getBytes("utf-8"));
//System.out.println(boundaryMessage);
}
out.write("------------HV2ymHFg03ehbqgZCaKO6jyH--\r\n".getBytes("UTF-8"));
// 3. 写结尾
out.write(endBoundary.getBytes("utf-8"));
out.flush();
out.close();
// 4. 从服务器获得回答的内容
String strLine="";
String strResponse ="";
InputStream in =connection.getInputStream();
BufferedReader reader = newBufferedReader(new InputStreamReader(in));
while((strLine =reader.readLine()) != null)
{
strResponse +=strLine +"\n";
}
//System.out.print(strResponse);
return strResponse;
}
}
// 一个POJO。用于处理普通表单域形如key = value对的数据
classFormFieldKeyValuePair implements Serializable
{
private static final longserialVersionUID = 1L;
// The form field used for receivinguser's input,
// such as "username" in "<inputtype="text" name="username"/>"
private String key;
// The value entered by user in thecorresponding form field,
// such as "Patrick" the abovementioned formfield "username"
private String value;
public FormFieldKeyValuePair(Stringkey, String value)
{
this.key = key;
this.value = value;
}
public String getKey()
{
return key;
}
public void setKey(String key)
{
this.key = key;
}
public String getValue()
{
return value;
}
public void setValue(String value)
{
this.value = value;
}
}
// 一个POJO。用于保存上传文件的相关信息
classUploadFileItem implements Serializable
{
private static final longserialVersionUID = 1L;
// The form field name in a form used foruploading a file,
// such as "upload1" in "<inputtype="file" name="upload1"/>"
private String formFieldName;
// File name to be uploaded, thefileName contains path,
// such as "E:\\some_file.jpg"
private String fileName;
public UploadFileItem(StringformFieldName, String fileName)
{
this.formFieldName =formFieldName;
this.fileName = fileName;
}
public String getFormFieldName()
{
return formFieldName;
}
public void setFormFieldName(StringformFieldName)
{
this.formFieldName =formFieldName;
}
public String getFileName()
{
return fileName;
}
public void setFileName(StringfileName)
{
this.fileName = fileName;
}
}
4. 运行结果
运行PostRequestEmulator之前,服务器的upload目录下的情况:
运行PostRequestEmulator后,服务器的upload目录下的情况:
PostRequestEmulator从服务端得到的反馈情况:
Response fromserver is: OK
Tomcat控制台输出:
如果上传的文件中有大于1M的情况,第二次执行PostRequestEmulator的时候,就会在temp目录中产生临时文件。
本文参考材料:
http://v.youku.com/v_show/id_XMjc0ODMxMTA4.html
http://www.iteye.com/topic/1116110(在Android中用Application模拟http post请求)
http://apps.hi.baidu.com/share/detail/46728849
http://www.eoeandroid.com/thread-22679-1-1.html
http://blog.zhaojie.me/2011/03/html-form-file-uploading-programming.html
相关推荐
在Java Web开发中,表单上传是常见的功能之一,尤其是当用户需要上传多个文件时。本文将详细讲解如何实现这个功能,主要涉及HTML表单、Servlet、MVC框架(如Spring MVC)以及文件处理的相关知识。 1. HTML表单设置...
在后台,Java通常使用Servlet或Spring MVC来接收并处理文件上传。Servlet API提供`Part`接口来处理`multipart/form-data`请求。以下是一个简单的Servlet示例: ```java import javax.servlet.http.Part; import ...
AJAX通过XMLHttpRequest对象实现后台与服务器的通信,允许我们发送GET或POST请求,并处理服务器返回的数据。 接下来,我们谈谈Java Servlet。Servlet是Java编写的一个服务器端程序,主要用来扩展服务器的功能,处理...
开发者可能使用HTTPClient来模拟客户端,发送请求到一个基于servlet的服务器,而服务器则利用MQ来处理这些请求,实现服务间的通信和任务调度。 在实际开发中,这样的架构可以帮助我们构建出高性能、高可用的系统。...
POST请求用于向服务器发送数据,适用于创建新资源或更新现有资源。在Android中,可以使用HttpPost对象构造POST请求,通过添加NameValuePair或RequestBody对象设置请求体数据。Servlet通过HttpServletRequest对象的...
这通常涉及到HTTP协议的POST请求,以及对上传文件的大小、类型等进行限制和验证,以保证服务端的稳定性和安全性。 7. **数据持久化**:用户信息和上传的文件需要持久化存储,以便于后续访问和管理。这可能涉及到...
Servlet通过`doGet`和`doPost`方法处理HTTP GET和POST请求,使用`HttpServletRequest`和`HttpServletResponse`对象来获取请求参数和设置响应内容。 3. **数据库三层架构**: 为了持久化用户信息,如用户名、密码等...
AJAX(Asynchronous JavaScript and XML)是一种异步请求技术,允许网页在不刷新整个页面的情况下,向服务器发送请求并获取数据。AJAX是基于JavaScript和XML技术的,它可以使网页具有更高的交互性和响应性。 知识点...
在Android开发中,Java语言是首选的编程工具,尤其对于后台服务的实现。这篇简易教程主要面向初学者,旨在帮助他们理解如何使用Java在Android中创建后台服务,并涉及到了Tomcat服务器的一些具体应用。 首先,我们...
3. **HTTP请求和响应**:Android应用通过HTTP协议向Servlet发送POST请求,携带登录信息(如用户名和密码)。Servlet接收到请求后,解析请求参数,与数据库中的用户信息进行匹配。如果匹配成功,Servlet会构造一个...
【房地产交易系统】是一个基于Java Web技术,使用JSP(JavaServer Pages)和Servlet开发的Web应用程序,主要用于模拟和管理房地产的交易流程。系统的核心功能包括用户注册与验证、房源展示以及后台管理。 1. **用户...
2. **JavaScript部分**:使用JavaScript的XMLHttpRequest对象创建一个新的HTTP请求,并设置请求方法(GET或POST)、URL(指向Servlet的URL)以及请求体(如果需要发送数据)。然后,使用open()方法初始化请求,send...
使用这种方式,可以在JavaScript中创建XMLHttpRequest对象,监听上传进度,并通过POST请求发送文件。例如: ```javascript var xhr = new XMLHttpRequest(); xhr.open("POST", "/upload2", true); xhr.upload....
对于POST请求,Java后台还需要处理请求体中的数据。例如,使用Spring MVC框架,控制器方法可以这样定义: ```java @PostMapping("/api/data") public ResponseEntity<?> sendData(@RequestBody YourRequestObject ...
Servlet通过`doGet`和`doPost`方法响应HTTP的GET和POST请求,然后返回相应的JSP页面或者JSON数据。 3. **MVC模式**: 本项目可能采用了Model-View-Controller(模型-视图-控制器)架构模式。在这种模式下,Model...
2. **请求处理**:掌握HttpServletRequest和HttpServletResponse接口,学会处理GET和POST请求。 3. **JSP动作指令**:如`<jsp:include>`、`<jsp:forward>`和`<jsp:useBean>`,以及EL(Expression Language)和JSTL...
本项目"基于Servlet实现的点餐系统"是利用Servlet技术构建的一个实际应用,旨在模拟餐厅点餐流程,提供用户友好、高效且可靠的在线订餐服务。 【核心知识点1】:Servlet生命周期 Servlet生命周期包括加载、初始化、...
在描述中提到的"JSP无组件实现WEB上传",意味着可能是在JSP页面上直接处理文件上传,而不是将逻辑放在单独的Java后台处理。这通常涉及到创建一个表单,设置`enctype="multipart/form-data"`属性,并且不使用任何...
使用`$.ajax()`或`$.post()`(jQuery提供的便捷方法)发送POST请求到Servlet,将用户选择的商品信息(如商品ID、数量等)发送到服务器。例如: ```javascript $.ajax({ url: '/add-to-basket', type: 'POST', ...
【Java网上购物系统】是一个基于JSP(JavaServer Pages)技术构建的Web应用程序,主要用于模拟实现电子商务中的在线购物功能。JSP是Java EE平台的一部分,它允许开发者在HTML页面中嵌入Java代码,以实现动态网页的...