Multipart Form File Upload

原创
2015/06/09 23:32
阅读数 72

主要类:


/**
 * <code>MultiPartFormOutputStream</code> is used to write
 * "multipart/form-data" to a <code>java.net.URLConnection</code> for POSTing.
 * This is primarily for file uploading to HTTP servers.
 * 
 * @since JDK1.3
 */
public class MultiPartFormOutputStream
{
	/**
	 * The line end characters.
	 */
	private static final String NEWLINE = "\r\n";

	/**
	 * The boundary prefix.
	 */
	private static final String PREFIX = "--";

	/**
	 * The output stream to write to.
	 */
	private DataOutputStream out = null;

	/**
	 * The multipart boundary string.
	 */
	private String boundary = null;

	/**
	 * Creates a new <code>MultiPartFormOutputStream</code> object using the
	 * specified output stream and boundary. The boundary is required to be
	 * created before using this method, as described in the description for the
	 * <code>getContentType(String)</code> method. The boundary is only
	 * checked for <code>null</code> or empty string, but it is recommended to
	 * be at least 6 characters. (Or use the static createBoundary() method to
	 * create one.)
	 * 
	 * @param os
	 *            the output stream
	 * @param boundary
	 *            the boundary
	 * @see #createBoundary()
	 * @see #getContentType(String)
	 */
	public MultiPartFormOutputStream(OutputStream os, String boundary)
	{
		if (os == null)
		{
			throw new IllegalArgumentException("Output stream is required.");
		}
		if (boundary == null || boundary.length() == 0)
		{
			throw new IllegalArgumentException("Boundary stream is required.");
		}
		this.out = new DataOutputStream(os);
		this.boundary = boundary;
	}

	/**
	 * Writes an boolean field value.
	 * 
	 * @param name
	 *            the field name (required)
	 * @param value
	 *            the field value
	 * @throws java.io.IOException
	 *             on input/output errors
	 */
	@SuppressLint("UseValueOf")
	public void writeField(String name, boolean value) throws java.io.IOException
	{
		writeField(name, new Boolean(value).toString());
	}

	/**
	 * Writes an double field value.
	 * 
	 * @param name
	 *            the field name (required)
	 * @param value
	 *            the field value
	 * @throws java.io.IOException
	 *             on input/output errors
	 */
	public void writeField(String name, double value) throws java.io.IOException
	{
		writeField(name, Double.toString(value));
	}

	/**
	 * Writes an float field value.
	 * 
	 * @param name
	 *            the field name (required)
	 * @param value
	 *            the field value
	 * @throws java.io.IOException
	 *             on input/output errors
	 */
	public void writeField(String name, float value) throws java.io.IOException
	{
		writeField(name, Float.toString(value));
	}

	/**
	 * Writes an long field value.
	 * 
	 * @param name
	 *            the field name (required)
	 * @param value
	 *            the field value
	 * @throws java.io.IOException
	 *             on input/output errors
	 */
	public void writeField(String name, long value) throws java.io.IOException
	{
		writeField(name, Long.toString(value));
	}

	/**
	 * Writes an int field value.
	 * 
	 * @param name
	 *            the field name (required)
	 * @param value
	 *            the field value
	 * @throws java.io.IOException
	 *             on input/output errors
	 */
	public void writeField(String name, int value) throws java.io.IOException
	{
		writeField(name, Integer.toString(value));
	}

	/**
	 * Writes an short field value.
	 * 
	 * @param name
	 *            the field name (required)
	 * @param value
	 *            the field value
	 * @throws java.io.IOException
	 *             on input/output errors
	 */
	public void writeField(String name, short value) throws java.io.IOException
	{
		writeField(name, Short.toString(value));
	}

	/**
	 * Writes an char field value.
	 * 
	 * @param name
	 *            the field name (required)
	 * @param value
	 *            the field value
	 * @throws java.io.IOException
	 *             on input/output errors
	 */
	@SuppressLint("UseValueOf")
	public void writeField(String name, char value) throws java.io.IOException
	{
		writeField(name, new Character(value).toString());
	}

	/**
	 * Writes an string field value. If the value is null, an empty string is
	 * sent ("").
	 * 
	 * @param name
	 *            the field name (required)
	 * @param value
	 *            the field value
	 * @throws java.io.IOException
	 *             on input/output errors
	 */
	public void writeField(String name, String value) throws java.io.IOException
	{
		if (name == null)
		{
			throw new IllegalArgumentException("Name cannot be null or empty.");
		}
		if (value == null)
		{
			value = "";
		}
		/*
		 * --boundary\r\n Content-Disposition: form-data; name="<fieldName>"\r\n
		 * \r\n <value>\r\n
		 */
		// write boundary
		out.writeBytes(PREFIX);
		out.writeBytes(boundary);
		out.writeBytes(NEWLINE);
		// write content header
		out.writeBytes("Content-Disposition: form-data; name=\"" + name + "\"");
		out.writeBytes(NEWLINE);
		out.writeBytes(NEWLINE);
		// write content
		out.writeBytes(new String(value.getBytes("UTF-8"), "ISO-8859-1"));
		out.writeBytes(NEWLINE);
		out.flush();
	}

	/**
	 * Writes a file's contents. If the file is null, does not exists, or is a
	 * directory, a <code>java.lang.IllegalArgumentException</code> will be
	 * thrown.
	 * 
	 * @param name
	 *            the field name
	 * @param mimeType
	 *            the file content type (optional, recommended)
	 * @param file
	 *            the file (the file must exist)
	 * @throws java.io.IOException
	 *             on input/output errors
	 */
	public void writeFile(String name, String mimeType, File file) throws java.io.IOException
	{
		if (file == null)
		{
			throw new IllegalArgumentException("File cannot be null.");
		}
		if (!file.exists())
		{
			throw new IllegalArgumentException("File does not exist.");
		}
		if (file.isDirectory())
		{
			throw new IllegalArgumentException("File cannot be a directory.");
		}
		writeFile(name, mimeType, file.getCanonicalPath(), new FileInputStream(file));
	}

	/**
	 * Writes a input stream's contents. If the input stream is null, a
	 * <code>java.lang.IllegalArgumentException</code> will be thrown.
	 * 
	 * @param name
	 *            the field name
	 * @param mimeType
	 *            the file content type (optional, recommended)
	 * @param fileName
	 *            the file name (required)
	 * @param is
	 *            the input stream
	 * @throws java.io.IOException
	 *             on input/output errors
	 */
	public void writeFile(String name, String mimeType, String fileName, InputStream is)
			throws java.io.IOException
	{
		if (is == null)
		{
			throw new IllegalArgumentException("Input stream cannot be null.");
		}
		if (fileName == null || fileName.length() == 0)
		{
			throw new IllegalArgumentException("File name cannot be null or empty.");
		}
		/*
		 * --boundary\r\n Content-Disposition: form-data; name="<fieldName>";
		 * filename="<filename>"\r\n Content-Type: <mime-type>\r\n \r\n
		 * <file-data>\r\n
		 */
		// write boundary
		out.writeBytes(PREFIX);
		out.writeBytes(boundary);
		out.writeBytes(NEWLINE);
		// write content header
		out.writeBytes("Content-Disposition: form-data; name=\"" + name + "\"; filename=\""
				+ new String(fileName.getBytes("UTF-8"), "ISO-8859-1") + "\"");
		out.writeBytes(NEWLINE);
		if (mimeType != null)
		{
			out.writeBytes("Content-Type: " + mimeType);
			out.writeBytes(NEWLINE);
		}
		out.writeBytes(NEWLINE);
		// write content
		byte[] data = new byte[1024];
		int r = 0;
		while ((r = is.read(data, 0, data.length)) != -1)
		{
			out.write(data, 0, r);
		}
		// close input stream, but ignore any possible exception for it
		try
		{
			is.close();
		}
		catch (Exception e)
		{
		}
		out.writeBytes(NEWLINE);
		out.flush();
	}

	/**
	 * Writes the given bytes. The bytes are assumed to be the contents of a
	 * file, and will be sent as such. If the data is null, a
	 * <code>java.lang.IllegalArgumentException</code> will be thrown.
	 * 
	 * @param name
	 *            the field name
	 * @param mimeType
	 *            the file content type (optional, recommended)
	 * @param fileName
	 *            the file name (required)
	 * @param data
	 *            the file data
	 * @throws java.io.IOException
	 *             on input/output errors
	 */
	public void writeFile(String name, String mimeType, String fileName, byte[] data)
			throws java.io.IOException
	{
		if (data == null)
		{
			throw new IllegalArgumentException("Data cannot be null.");
		}
		if (fileName == null || fileName.length() == 0)
		{
			throw new IllegalArgumentException("File name cannot be null or empty.");
		}
		/*
		 * --boundary\r\n Content-Disposition: form-data; name="<fieldName>";
		 * filename="<filename>"\r\n Content-Type: <mime-type>\r\n \r\n
		 * <file-data>\r\n
		 */
		// write boundary
		out.writeBytes(PREFIX);
		out.writeBytes(boundary);
		out.writeBytes(NEWLINE);
		// write content header
		out.writeBytes("Content-Disposition: form-data; name=\"" + name + "\"; filename=\""
				+ new String(fileName.getBytes("UTF-8"), "ISO-8859-1") + "\"");
		out.writeBytes(NEWLINE);
		if (mimeType != null)
		{
			out.writeBytes("Content-Type: " + mimeType);
			out.writeBytes(NEWLINE);
		}
		out.writeBytes(NEWLINE);
		// write content
		out.write(data, 0, data.length);
		out.writeBytes(NEWLINE);
		out.flush();
	}

	/**
	 * Flushes the stream. Actually, this method does nothing, as the only write
	 * methods are highly specialized and automatically flush.
	 * 
	 * @throws java.io.IOException
	 *             on input/output errors
	 */
	public void flush() throws java.io.IOException
	{
		// out.flush();
	}

	/**
	 * Closes the stream. <br />
	 * <br />
	 * <b>NOTE:</b> This method <b>MUST</b> be called to finalize the
	 * multipart stream.
	 * 
	 * @throws java.io.IOException
	 *             on input/output errors
	 */
	public void close() throws java.io.IOException
	{
		// write final boundary
		out.writeBytes(PREFIX);
		out.writeBytes(boundary);
		out.writeBytes(PREFIX);
		out.writeBytes(NEWLINE);
		out.flush();
		out.close();
	}

	/**
	 * Gets the multipart boundary string being used by this stream.
	 * 
	 * @return the boundary
	 */
	public String getBoundary()
	{
		return this.boundary;
	}

	/**
	 * Creates a new <code>java.net.URLConnection</code> object from the
	 * specified <code>java.net.URL</code>. This is a convenience method
	 * which will set the <code>doInput</code>, <code>doOutput</code>,
	 * <code>useCaches</code> and <code>defaultUseCaches</code> fields to
	 * the appropriate settings in the correct order.
	 * 
	 * @return a <code>java.net.URLConnection</code> object for the URL
	 * @throws java.io.IOException
	 *             on input/output errors
	 */
	public static URLConnection createConnection(URL url) throws java.io.IOException
	{
		URLConnection urlConn = url.openConnection();
		if (urlConn instanceof HttpURLConnection)
		{
			HttpURLConnection httpConn = (HttpURLConnection)urlConn;
			httpConn.setRequestMethod("POST");
		}
		urlConn.setDoInput(true);
		urlConn.setDoOutput(true);
		urlConn.setUseCaches(false);
		urlConn.setDefaultUseCaches(false);
		return urlConn;
	}

	/**
	 * Creates a multipart boundary string by concatenating 20 hyphens (-) and
	 * the hexadecimal (base-16) representation of the current time in
	 * milliseconds.
	 * 
	 * @return a multipart boundary string
	 * @see #getContentType(String)
	 */
	public static String createBoundary()
	{
		return "--------------------" + Long.toString(System.currentTimeMillis(), 16);
	}

	/**
	 * Gets the content type string suitable for the
	 * <code>java.net.URLConnection</code> which includes the multipart
	 * boundary string. <br />
	 * <br />
	 * This method is static because, due to the nature of the
	 * <code>java.net.URLConnection</code> class, once the output stream for
	 * the connection is acquired, it's too late to set the content type (or any
	 * other request parameter). So one has to create a multipart boundary
	 * string first before using this class, such as with the
	 * <code>createBoundary()</code> method.
	 * 
	 * @param boundary
	 *            the boundary string
	 * @return the content type string
	 * @see #createBoundary()
	 */
	public static String getContentType(String boundary)
	{
		return "multipart/form-data; boundary=" + boundary;
	}
}

测试代码:

public static void main(String[] args) throws Exception {
		String boundary = MultiPartFormOutputStream.createBoundary();
		InputStream is = null;
		ByteArrayOutputStream baos = null;
		try {
			String url = "http://localhost:8080/test";
			HttpURLConnection conn = (HttpURLConnection)MultiPartFormOutputStream.createConnection(new URL(url));
			conn.addRequestProperty("Content-Type", MultiPartFormOutputStream.getContentType(boundary));
			MultiPartFormOutputStream s = new MultiPartFormOutputStream(conn.getOutputStream(), boundary);
			s.writeField("id", 3L);
			s.writeField("content", "测试内容22abc");
			s.writeFile("file", null, new File("/Users/test/image.png"));
			s.close();
			
			int responseCode = conn.getResponseCode();
			if (responseCode != 200) {
                throw new Exception(String.format("Received the response code %d from the URL %s", responseCode, url));
            }
            // Read the response
            is = conn.getInputStream();
            baos = new ByteArrayOutputStream();
            byte[] bytes = new byte[1024];
            int bytesRead;
            while((bytesRead = is.read(bytes)) != -1) {
                baos.write(bytes, 0, bytesRead);
            }
            byte[] bytesReceived = baos.toByteArray();
            String response = new String(bytesReceived);
            System.out.println(response);
			
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			baos.close();
            is.close();
		}


展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部