`

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

阅读更多
转载自:
http://blog.csdn.net/pathuang68/article/details/6920076
在某些情况下,需要用Java applicatioin来模拟form,向服务器(本文以servlet为例)发送http post请求,包括提交表单域中的数据以及上传文件。如果仅仅是传递form中的数据,而不包含上传文件,那是很简单的,比如Java application可以这么写:
package com.pat.postrequestemulator;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;

public class PostRequestEmulator {

	public static void main(String[] args) throws Exception {
		// 服务地址
		URL url = new URL("http://127.0.0.1:8080/test/upload");

		// 设定连接的相关参数
		HttpURLConnection connection = (HttpURLConnection) url.openConnection();
		connection.setDoOutput(true);
		connection.setRequestMethod("POST");
		OutputStreamWriter out = new OutputStreamWriter(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 = new BufferedReader(new InputStreamReader(in));
		while ((strLine = reader.readLine()) != null) {
			strResponse += strLine + "\n";
		}

		System.out.print(strResponse);
	}
}


服务端的servlet可以这么写:
package com.pat.handlinghttprequestservlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class PostRequestEmulator extends HttpServlet {
	private static final long serialVersionUID = 1L;

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		super.doGet(req, resp);
	}

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, 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/javaee http://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的代码
public class HandlingHttpRequestServlet extends HttpServlet {

	private static final long serialVersionUID = 1L;

	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		super.doGet(req, resp);
	}

	@SuppressWarnings({ "unchecked", "deprecation" })
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {

		DiskFileItemFactory factory = new DiskFileItemFactory();

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

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

		// 设定临时文件夹为repositoryPath
		factory.setRepository(new File(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 (FileItem fileItem : list) {
				if (fileItem.isFormField()) { // 如果是普通的form field
					String name = fileItem.getFieldName();
					String value = fileItem.getString();
					System.out.println(name + " = " + value);
				} else { // 如果是文件
					String value = fileItem.getName();
					int start = value.lastIndexOf("\\");
					String fileName = value.substring(start + 1);
					// 将其中包含的内容写到path(即upload目录)下,
					// 名为fileName的文件中
					fileItem.write(new File(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的代码
public class PostRequestEmulator {
	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(new FormFieldKeyValuePair("username", "Patrick"));
		ffkvp.add(new FormFieldKeyValuePair("password", "HELLOPATRICK"));
		ffkvp.add(new FormFieldKeyValuePair("hobby", "Computer programming"));

		// 设定要上传的文件。UploadFileItem见后面的代码
		ArrayList<UploadFileItem> ufi = new ArrayList<UploadFileItem>();
		ufi.add(new UploadFileItem("upload1", "E:\\Asturias.mp3"));
		ufi.add(new UploadFileItem("upload2", "E:\\full.jpg"));
		ufi.add(new UploadFileItem("upload3", "E:\\dyz.txt"));

		// 类HttpPostEmulator的定义,见后面的代码
		HttpPostEmulator hpe = new HttpPostEmulator();
		String response = hpe.sendHttpPostRequest(serverUrl, ffkvp, ufi);
		System.out.println("Responsefrom server is: " + response);
	}
}

class HttpPostEmulator {
	// 每个post参数之间的分隔。随意设定,只要不会和其他的字符串重复即可。
	private static final String BOUNDARY = "----------HV2ymHFg03ehbqgZCaKO6jyH";
	public String sendHttpPostRequest(String serverUrl, ArrayList<FormFieldKeyValuePair> generalFormFields,
			ArrayList<UploadFileItem> filesToBeUploaded) throws Exception {

		// 向服务器发送post请求
		URL url = new URL(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 (FormFieldKeyValuePair ffkvp : 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 = new StringBuffer();
			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");

			String boundaryMessage2 = contentBody.toString();
			out.write(boundaryMessage2.getBytes("utf-8"));

			// 开始真正向服务器写文件
			File file = new File(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");
			String boundaryMessage = contentBody.toString();
			out.write(boundaryMessage.getBytes("utf-8"));
		}

		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 = new BufferedReader(new InputStreamReader(in));

		while ((strLine = reader.readLine()) != null) {
			strResponse += strLine + "\n";
		}

		return strResponse;
	}
}

// 一个POJO。用于处理普通表单域形如key = value对的数据
class FormFieldKeyValuePair implements Serializable {
	// 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(String key, 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。用于保存上传文件的相关信息
class UploadFileItem implements Serializable {
	// 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(String formFieldName, String fileName) {
		this.formFieldName = formFieldName;
		this.fileName = fileName;
	}

	public String getFormFieldName() {
		return formFieldName;
	}

	public void setFormFieldName(String formFieldName) {
		this.formFieldName = formFieldName;
	}

	public String getFileName() {
		return fileName;
	}

	public void setFileName(String fileName) {
		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
分享到:
评论

相关推荐

    JavaServlet示例代码

    JavaServlet是一种用于构建动态Web应用程序的技术,它是Java平台上的服务器端组件,允许开发者在服务器上处理HTTP请求并返回响应。这个示例代码主要是关于用户注册和登录功能的实现,这在许多Web应用中是非常基础且...

    模拟tomcat、servlet服务器

    6. **Servlet规范**:虽然我们不是直接使用Tomcat,但理解Servlet规范对于模拟Servlet服务器至关重要。Servlet是Java Web应用的标准接口,用于扩展服务器的功能。模拟服务器需要实现类似Servlet的接口,处理HTTP请求...

    java处理文件上传的底层实现以及java模拟post协议实现文件上传

    本篇将详细探讨Java处理文件上传的底层实现,以及如何使用Java模拟POST协议来实现文件上传。 首先,我们需要理解文件上传的基本原理。在HTTP协议中,文件上传通常通过POST请求进行。当用户在表单中选择文件并提交时...

    servlet登录小程序

    3. **请求处理方法**:Servlet通过重写`doGet()`和`doPost()`方法来处理HTTP GET和POST请求。在登录场景中,POST请求通常用于提交登录信息,因为其能携带更多数据且数据不会显示在URL中。 4. **会话管理**:为了...

    HTTPClient + MQ + servlet

    首先,**HTTPClient**是Java中用于发送HTTP请求的库,它允许应用程序与Web服务器进行交互。在Java世界里,HTTPClient可以是Apache HttpClient库,它提供了丰富的功能,包括GET、POST、PUT等HTTP方法的支持,以及...

    HTTP 通信测试或者JAVAServlet测试

    AJAX通过XMLHttpRequest对象实现后台与服务器的通信,允许我们发送GET或POST请求,并处理服务器返回的数据。 接下来,我们谈谈Java Servlet。Servlet是Java编写的一个服务器端程序,主要用来扩展服务器的功能,处理...

    基于 IntelliJ IDEA 模拟 Servlet 网络请求示例

    Servlet 是 Java web 开发的基础组件,广泛应用于 web 应用程序的开发中。 知识点三:基于 IntelliJ IDEA 模拟 Servlet 网络请求 在 IntelliJ IDEA 中,可以使用 Java Enterprise 项目类型来创建一个 web 应用工程...

    servlet技术初步入门

    Servlet技术是Java Web开发中的核心组件之一,它用于扩展服务器的功能,处理来自客户端(通常是Web浏览器)的HTTP请求,并向客户端发送响应。本教程将引导初学者了解Servlet的基本概念、工作原理以及如何在实际项目...

    JAVA实现模拟导入数据/上传文件进度条

    3. **Ajax提交文件**:通过FormData对象将文件添加到请求体中,然后使用Ajax向Servlet发送POST请求。 4. **Servlet处理文件**:在Servlet中,接收文件并分块读取,每处理完一块,就更新一次进度信息,如处理的字节...

    java-servlet-api.doc

    当一个Servlet被卸载时,引擎将不能给Servlet发送任何请求。引擎必须释放Servlet并完成无用存储单元的收集 Servlet映射技术\r 作为一个Servlet引擎的开发者,你必须对于如何映射客户端的请求到Servlet有大量的适应...

    JAVA+JSP实现模拟登录主动向用户推送

    在IT行业中,Java和JSP(JavaServer Pages)是用于构建动态web应用程序的常用技术。本文将深入探讨如何使用这两种技术来实现一个模拟登录并主动向用户推送信息的系统。 首先,我们需要理解Java和JSP的基本概念。...

    基于java的一个支持servlet的web服务器.zip

    Java是一种广泛使用的编程语言,尤其在开发Web应用程序时。Servlet是Java平台上的一个核心组件,它为创建动态、交互式的Web服务提供了强大的后端支持。本项目“基于Java的一个支持Servlet的Web服务器”是一个实现...

    httpclient模拟post请求json封装表单数据的实现方法

    HTTPClient 是一个强大的 Java 库,它允许程序员模拟 HTTP 请求,包括 POST 请求。在这个场景中,我们关注的是如何使用 HTTPClient 发送一个 JSON 格式的 POST 请求并封装表单数据。下面将详细介绍这个过程。 首先...

    ATA Java web应用开发模拟题A

    这是Servlet规范中定义的标准做法,以便适当地处理POST请求。 ### 10. SingleThreadModel属性的作用 `SingleThreadModel`接口在Servlet 2.3规范中引入,用于指示Servlet实例在同一时间只应由一个线程调用。然而,...

    java模拟tomcat的web服务器源码

    当我们创建一个Servlet时,我们需要覆盖`doGet`和`doPost`方法,这些方法会在HTTP GET或POST请求到达时被调用。 Tomcat的工作流程大致如下: 1. **接收请求**:当客户端发起HTTP请求时,Tomcat会监听特定的端口...

    java +jsp+servlet(java书城小项目).zip

    本项目"java +jsp+servlet(java书城小项目).zip"显然是一个基于这些技术的实战案例,旨在帮助学习者理解和应用Java Web开发的基础知识。 1. **Java基础**: - **对象与类**:Java是一种面向对象的语言,书城项目中...

    j2ee.zip servlet第一个例子

    在IT行业中,Servlet技术是Java EE(Java 2 Platform, Enterprise Edition)平台的核心组成部分,用于构建动态Web应用程序。Servlet是一个Java类,它扩展了服务器的功能,可以处理HTTP请求并生成响应。在这个“j2ee....

    JAVA使用MVC,servlet+jsp做的项目

    Servlet通过重写`doGet`和`doPost`方法来响应GET和POST请求,并使用`request`和`response`对象来获取请求参数和向客户端发送响应。 3. JSP(JavaServer Pages): JSP是Java Web开发中的视图技术,允许开发者在...

    Servlet框架模拟

    Servlet是一种Java技术,用于构建动态、交互式的Web应用程序。它提供了一种服务器端处理HTTP请求并返回响应的方式。在这个框架模拟中,我们将深入探讨Servlet的基本概念、生命周期以及如何通过Eclipse进行开发。 1....

Global site tag (gtag.js) - Google Analytics