这实际上是模仿浏览器的post行为,问题的提出是本人在做一个企业内部网络的项目的时候,该企业网络与Internet是通过一台HP-UNIX的服务器连接的,项目需要经常从互联网传送一些文本文件到内部网络的一台Web服务器,我们只能够通过那台HP-UNIX的主机进去,当时内网的Web服务器用的是DotNet框架,很容易的写好了文件上传的Web界面。这就麻烦了,我不能够用浏览器直接访问该文件上传页面,所以就只好用Java写了个模仿浏览器上传文件的程序。
环境:
内网Web服务器:Windows2000+DotNet Framework1.0
外网主机:HP-UNIX(具体什么版本号忘记了)、jdk1.4
 首先、我们解决容易的问题,我们知道asp.net的文件上传功能封装得非常完美。很轻松我们就写好了如下上传页面(命名为TestFileManager.aspx):

<%@ Page Language=c# CodePage=936 %>
<%@ import Namespace=System %>
<%@ import Namespace=System.IO %>

<script runat=server>
 void Page_Load(Object sender, EventArgs e) {
 }
 void Button1_Click(Object sender, EventArgs e) {
  //判断选取对话框选取的文件长度是否为0
  Label1.Text=Clicked;
  //因为我的项目中用的只是xml文件,所以有此判断
  if (uploadfile1.PostedFile.ContentLength != 0 && uploadfile1.PostedFile.FileName.ToLower().EndsWith(.xml)) {
   try{
    string strFileName = uploadfile1.PostedFile.FileName;
    string[] strTemp = strFileName.Split(new char[]{\\});
    strFileName = C:\\+strTemp[strTemp.Length-1];
    uploadfile1.PostedFile.SaveAs(strFileName);
    Label1.Text=测试文件 + strFileName + 上传成功! ;
            }
            catch (Exception exp)
            {
    Label1.Text = exp.StackTrace;
            }
  }
 }
</script>
<html>
<head>
 <title>逻辑层测试管理</title>
</head>
<body>
    <form method=post enctype=multipart/form-data runat=server>
        <p>
            <input id=uploadfile1 type=file size=49 runat=server />
            <asp:Button id=Button1 onclick=Button1_Click runat=server Text=上传></asp:Button>
        </p>
        <p>
            <asp:Label id=Label1 runat=server Width=459px></asp:Label>
        </p>
        <!-- Insert content here -->
    </form>
</body>
</html>


这个上传页面应该没什么好说的了,我们看看它将产生的html页面内容:
<html>
<head>
    <title>逻辑层测试管理</title>
</head>
<body>
    <form name=_ctl0 method=post action=TestFileManager.aspx id=_ctl0 enctype=multipart/form-data>
<input type=hidden name=__VIEWSTATE value=dDwyNTIzNjA5NDU7Oz7rsE3eBYzQHDVtl+aTn96MvQW6PQ== />

        <p>
            <input name=uploadfile1 id=uploadfile1 type=file size=49 />
            <input type=submit name=Button1 value=? id=Button1 />
        </p>
        <p>
            <span id=Label1 style=width:459px;></span>
        </p>
        <!-- Insert content here -->
    </form>
</body>
</html>

上面有一段<input type=hidden name=__VIEWSTATE value=dDwyNTIzNjA5NDU7Oz7rsE3eBYzQHDVtl+aTn96MvQW6PQ== />这是它产生的相当于Session的一个值,这个值将对我们的上传程序产生比较大的影响。
接着我们来写Java上传的程序,这里要说明一点,我没有用j2se的网络包,并不是现有的网络包不行,因为当时我正好在玩sun的BRAZIL PROJECT(http://www.sun.com/2000-0822/brazil/),感觉挺精巧的,所以就用上了brazil的网络功能。

import java.io.*;
import org.w3c.dom.*;
import org.xml.sax.*;
import javax.xml.parsers.*;
import sunlabs.brazil.util.*;
import sunlabs.brazil.util.http.*;
/**
 * 该类实现上传xml测试文件到逻辑层
 *
 */
public class TestFileManager {
 /**
  * 提取XML一个节点的属性值
  * @node XML节点对象
  * @strName 属性名称
  * @return 节点的属性值
  */
 private static String getNodeAttributeValue(Node node, String strName) {
  NamedNodeMap nmap = node.getAttributes();
  Node tmpnode = nmap.getNamedItem(strName);
  String rtStr = ;
  if ( tmpnode != null ) {
   rtStr = tmpnode.getNodeValue().trim();
  }
  return rtStr;
 }

 public static void main(String[] args){
  if ( args.length < 1 ) {
   System.out.println(Usage: java TestFileManager xmlfilelist);
   System.exit(0);
  }
  try {
   HttpRequest request = new HttpRequest(http://192.9.200.108/OnlineService/TestFileManager.aspx);
   request.setMethod(GET);
   request.setRequestHeader(Cache-Control, no-cache);
   request.setRequestHeader(Connection, Keep-Alive);
   request.setRequestHeader(Accept, image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*);
   request.setRequestHeader(Accept-Encoding, gzip, deflate);
   request.setRequestHeader(Accept-Language, en-au);
   request.setRequestHeader(Referer, http://rookie/OnlineService/TestFileManager.aspx);
   request.setRequestHeader(User-Agent, Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3215; .NET CLR 1.0.3705));
   
   request.connect();
   String strCookie = request.getResponseHeader(Set-Cookie);
   strCookie = strCookie.substring(0,strCookie.indexOf(;));
   
   DocumentBuilderFactory dbfactory = DocumentBuilderFactory.newInstance();
   DocumentBuilder parser =dbfactory.newDocumentBuilder();
   String strTemp = request.getContent();
   

   Document xmldoc = parser.parse(new InputSource(new StringReader(strTemp)));
   NodeList nlist = xmldoc.getElementsByTagName(input);
   Node node;
   String strName = ;
   String strValue = ;
   for ( int i = 0; i < nlist.getLength(); i++) {
    node = nlist.item(i);
    strName = getNodeAttributeValue(node,name);
    if ( strName.equals(__VIEWSTATE) ) {
     strValue = getNodeAttributeValue(node,value);
     break;
    }
   }
   request.close();
   request = null;

   String strBoundary = null;
   String strFileName = null;
   BufferedInputStream bis = null;
   byte[] data = null;
   for ( int i=0; i<args.length;i++ ) {
    try {
     strBoundary = new String(+(Math.random()+Math.random())).substring(2);
     strFileName = args[i];
     bis = new BufferedInputStream(new FileInputStream(strFileName));
     data = new byte[bis.available()];
     bis.read(data, 0, data.length);
     bis.close();
     System.out.println(上传文件 + strFileName + ...);

     request = new HttpRequest(http://192.9.200.108/OnlineService/TestFileManager.aspx);
     request.setMethod(POST);
     request.setRequestHeader(Cache-Control, no-cache);
     request.setRequestHeader(Connection, Keep-Alive);
     request.setRequestHeader(Content-Type, multipart/form-data; boundary=---------------------------+strBoundary);
     request.setRequestHeader(Accept, image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*);
     request.setRequestHeader(Accept-Encoding, gzip, deflate);
     request.setRequestHeader(Accept-Language, en-au);
     request.setRequestHeader(Cookie, strCookie);
     request.setRequestHeader(Host, rookie);
     request.setRequestHeader(Referer, http://rookie/OnlineService/TestFileManager.aspx);
     request.setRequestHeader(User-Agent, Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3215; .NET CLR 1.0.3705));
     DataOutputStream dos = new DataOutputStream(request.getOutputStream());
     dos.writeBytes(-----------------------------+strBoundary);
     dos.writeBytes(\r\nContent-Disposition: form-data; name=\__VIEWSTATE\);
     dos.writeBytes(\r\n\r\n+strValue);
     dos.writeBytes(\r\n-----------------------------+strBoundary);
     dos.writeBytes(\r\nContent-Disposition: form-data; name=\uploadfile1\; filename=\ + strFileName + \);
     dos.writeBytes(\r\nContent-Type: text/xml);
     dos.writeBytes(\r\n\r\n);
     dos.writeBytes(new String(data));
          dos.writeBytes(\r\n-----------------------------+strBoundary);
     dos.writeBytes(\r\nContent-Disposition: form-data; name=\Button1\);
     dos.writeBytes(\r\n上传);
     dos.writeBytes(\r\n-----------------------------+strBoundary+--);
     dos.writeBytes(\r\n);
     dos.close();
     request.connect();

     request.close();
     request = null;
     System.out.println(文件 + strFileName + 上传成功.);
    } catch (FileNotFoundException e) {
     System.out.println(文件 + strFileName + 未找到.);
    } catch (Exception e) {
     e.printStackTrace();
    }
   }
  } catch (Exception e) {
   e.printStackTrace();
  }
 }
}

下面我详细讲解main方法中的具体过程
首先创建一个到服务器http的请求
HttpRequest request = new HttpRequest(http://192.9.200.108/OnlineService/TestFileManager.aspx);
第一次使用的是GET方式
request.setMethod(GET);
紧接着进行一些请求的属性设置
request.setRequestHeader(Cache-Control, no-cache);
这里保持连接,因为后面还要发送数据到服务器呢
request.setRequestHeader(Connection, Keep-Alive);
下面是一些无关紧要的属性设置了。
request.setRequestHeader(Accept, image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*);
request.setRequestHeader(Accept-Encoding, gzip, deflate);
request.setRequestHeader(Accept-Language, en-au);
request.setRequestHeader(Referer, http://rookie/OnlineService/TestFileManager.aspx);
request.setRequestHeader(User-Agent, Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3215; .NET CLR 1.0.3705));

构造好了连接请求,然后连接
request.connect();

紧接着提取Cookie值,在后文的post中可以用到。
String strCookie = request.getResponseHeader(Set-Cookie);
strCookie = strCookie.substring(0,strCookie.indexOf(;));

下面通过循环查找,提取__VIEWSTATE的值,这个值是不能捏造的,每个新的get取得的是不一样的。
for ( int i = 0; i < nlist.getLength(); i++) {
 node = nlist.item(i);
 strName = getNodeAttributeValue(node,name);
 if ( strName.equals(__VIEWSTATE) ) {
  strValue = getNodeAttributeValue(node,value);
  break;
 }
}

往服务器组织发送数据
DataOutputStream dos = new DataOutputStream(request.getOutputStream());
dos.writeBytes(-----------------------------+strBoundary);//这是每个要被发送数据间的间隔
dos.writeBytes(\r\nContent-Disposition: form-data; name=\__VIEWSTATE\);
dos.writeBytes(\r\n\r\n+strValue);
dos.writeBytes(\r\n-----------------------------+strBoundary);
这里面是发送文件的部分
dos.writeBytes(\r\nContent-Disposition: form-data; name=\uploadfile1\; filename=\ + strFileName + \);
dos.writeBytes(\r\nContent-Type: text/xml);
dos.writeBytes(\r\n\r\n);
dos.writeBytes(new String(data));
dos.writeBytes(\r\n-----------------------------+strBoundary);
dos.writeBytes(\r\nContent-Disposition: form-data; name=\Button1\);
dos.writeBytes(\r\n上传);
dos.writeBytes(\r\n-----------------------------+strBoundary+--);
dos.writeBytes(\r\n);
dos.close();
最后发送,也就是执行连接的操作。最后把上面程序部署到HP-UNIX上面,就可以上传文件到我的逻辑层了。以上的过程用j2se的net包也可以实现的,改一改类和方法就是了。
本文叙述的是文本文件的上传方式,对于二进制的文件则需要对文件数据进行编码,一般使用base64的编码。基本步骤是相同的,只要在组织文件数据的时候对文件内容编码并指明编码方式就可以了