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 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目录

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

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

                            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

                   // 类FormFieldKeyValuePair的定义见后面的代码

                   ArrayList ffkvp = new ArrayList();

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

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

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

                  

                   // 设定要上传的文件。UploadFileItem见后面的代码

                   ArrayList ufi = new ArrayList();

                   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,

                                                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. 处理普通表单域(即形如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 ""

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

         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,get,post,upload,模拟)