Java应用程序模拟向Servlet发送POST请求

在某些情况下,需要用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 classPostRequestEmulator

{

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 classHandlingHttpRequestServlet extends HttpServlet

{

private static final longserialVersionUID = 1L;

@Override

protected void doGet(HttpServletRequestreq, HttpServletResponse resp)

throws ServletException, IOException

{

super.doGet(req, resp);

}

@Override

protected voiddoPost(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目录

下面的目录文件结构如下图所示。

Java应用程序模拟向Servlet发送POST请求_第1张图片

其中的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使之如下:

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">

Hello

com.pat.handlinghttprequestservlet.HandlingHttpRequestServlet

Hello

/upload

这个web.xml可以先从D:\Tomcat6\webapps\examples\WEB-INF下面拷贝过来,再进行如上黑体字所示的修改即可。标签描述的是servlet代码方面的资料,其中Hello是给这个servlet起一个名字Hello,它必须和下面的中的一致,该名字具体是什么可以随意写定。

com.pat.handlinghttprequestservlet.HandlingHttpRequestServlet说明了完整的servlet类名,即servlet的类名为HandlingHttpRequestServlet,它位于包com.pat.handlinghttprequestservlet中。

/upload,说明了如果客户端向“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 classHandlingHttpRequestServlet 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 voiddoPost(HttpServletRequest req, HttpServletResponse resp)

throwsServletException, IOException

{

DiskFileItemFactory factory =new DiskFileItemFactory();

String path = req.getRealPath("/upload"); //得到绝对文件夹路径,比如

// "D:\\Tomcat6\\webapps\\test\\upload"

String repositoryPath =req.getRealPath("/upload/temp"); //临时文件夹路径

factory.setRepository(newFile(repositoryPath)); // 设定临时文件夹为repositoryPath

factory.setSizeThreshold(1024* 1024); // 设定上传文件的阈值,如果上传文件大于1M,

// 就可能在repository所代 表的文件夹中产生

// 临时文件,否则直接在内存中进行处理

//System.out.println("----"+ req.getContextPath()); // 得到相对文件夹路径,比如 "/test"

// 创建一个ServletFileUpload对象

ServletFileUpload uploader =new ServletFileUpload(factory);

try

{

// 调用uploader中的parseRequest方法,可以获得请求中的相关内容,

// 即一个FileItem类型的ArrayList。FileItem是在

// org.apache.commons.fileupload中定义的,它可以代表一个文件,

// 也可以代表一个普通的form field

ArrayListlist = (ArrayList)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

ArrayListffkvp = new ArrayList();

ffkvp.add(newFormFieldKeyValuePair("username", "Patrick"));

ffkvp.add(newFormFieldKeyValuePair("password", "HELLOPATRICK"));

ffkvp.add(newFormFieldKeyValuePair("hobby", "Computer programming"));

// 设定要上传的文件

ArrayListufi = new ArrayList();

ufi.add(newUploadFileItem("upload1", "E:\\Asturias.mp3"));

ufi.add(newUploadFileItem("upload2", "E:\\full.jpg"));

ufi.add(newUploadFileItem("upload3", "E:\\dyz.txt"));

HttpPostEmulator hpe = newHttpPostEmulator();

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,

ArrayListgeneralFormFields,

ArrayListfilesToBeUploaded) 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. 处理文字形式的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;

}

}

classFormFieldKeyValuePair implements Serializable

{

private static final longserialVersionUID = 1L;

// The form field used for receivinguser's input,

// such as "username" in ""

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;

}

}

classUploadFileItem implements Serializable

{

private static final longserialVersionUID = 1L;

// The form field name in a form used foruploading a file,

// such as "upload1" in ""

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目录下的情况:

Java应用程序模拟向Servlet发送POST请求_第2张图片

运行PostRequestEmulator后,服务器的upload目录下的情况:

Java应用程序模拟向Servlet发送POST请求_第3张图片

PostRequestEmulator从服务端得到的反馈情况:

Response fromserver is: OK

Tomcat控制台输出:

Java应用程序模拟向Servlet发送POST请求_第4张图片

如果上传的文件中有大于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应用程序模拟向Servlet发送POST请求)