java上传文件到远程服务器(一)---HttpURLConnection方式

142 篇文章 2 订阅
47 篇文章 1 订阅



我们在之前的文章


JavaWeb静态资源分离思路


中已经了解到要把文件上传到静态资源服务器有三种方式:

java上传文件到ftp服务器(这个方案需要在静态资源服务器安装ftp服务)

java使用HttpURLConnection上传文件到远程服务器  (分为客户端和服务端,客户端负责上传,服务端负责接收文件)

java使用HttpClient通过Post上传文件到远程服务器  (分为客户端和服务端,客户端负责上传,服务端负责接收文件)


本章我们就来尝试HttpURLConnection上传文件到远程服务器。





我们在之前的文章中已经在SpringMVC基础框架的基础上应用了BootStrap的后台框架,在此基础上记录HttpURLConnection上传文件到远程服务器。

应用bootstrap模板


基础项目源码下载地址为:

SpringMVC+Shiro+MongoDB+BootStrap基础框架


我们在基础项目中已经做好了首页index的访问。
现在就在index.jsp页面和index的路由Controller上做修改,HttpURLConnection上传文件到远程服务器。




客户端

客户端HttpURLConnection上传文件到远程服务器的原理是通过构造参数模仿form提交文件的http请求,把文件提交到远程服务器的接收路由中。


index.jsp的代码为:

<%@ include file="./include/header.jsp"%>
        <div id="page-wrapper">
            <div id="page-inner">


                <div class="row">
                    <div class="col-md-12">
                        <h1 class="page-header">
                            HttpURLConnection <small>HttpURLConnection</small>
                        </h1>
                    </div>
                </div>
                <!-- /. ROW  -->

     <form class="form-horizontal" name="upform" action="upload" method="post" enctype="multipart/form-data">
                    <div class="form-group">
                    <label for="sourceModule" class="col-sm-2 control-label">上传文件:</label>
                    <div class="col-sm-10">
                  <input type="file" name="filename"/><br/>  
                                               <input type="submit" value="提交" /><br/> 
                    </div>
                </div>
           </form>  
                <!-- /. ROW  -->
            </div>
            <!-- /. PAGE INNER  -->
        </div>
        <!-- /. PAGE WRAPPER  -->

    

        
        


 <%@ include file="./include/footer.jsp"%>

<script type="text/javascript">
    $(document).ready(function () {
   

    });

</script>


</body>

</html>


当提交表单里包含文件上传的时候,即Form的enctype属性值为multipart/form-data时,后台是无法像普通表单那样通过request.getParameter来获取用户提交的数据的。


这时候,当然可以通过解析提交到服务器的数据流来得到数据了,但是这样不但麻烦而且容易出错。

最好的方式是使用第三方的jar包获取数据,这方面有很多现成的成熟优秀的jar包。最常用的时以下三个:

apache的commons-fileupload : http://commons.apache.org/fileupload/

O'Reilly的cos: http://www.servlets.com/cos/index.html

jspsmart的SmartUpload:官方不提供下载了,google搜吧。

其中,据评测效率最高的是COS,最慢的是SmartUpload;最常用的是common-upload;文件太大时SmartUpland会崩溃。


我们这里使用commons-fileupload,需要引入两个jar包:commons-fileupload-1.3.1.jar和commons-io-2.4.jar。

下载地址:

http://central.maven.org/maven2/commons-fileupload/commons-fileupload/1.3.1/commons-fileupload-1.3.1.jar

http://central.maven.org/maven2/commons-io/commons-io/2.4/commons-io-2.4.jar


如果是maven项目,在pom.xml中增加:

<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.3.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.4</version>
</dependency>



路由中upload方法接受form提交的file文件,并且上传到服务器:

IndexController.java代码如下:

package com.test.web.controller;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.shiro.SecurityUtils;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.alibaba.fastjson.JSONObject;
import com.test.web.message.response.JSONResult;

/**
 * IndexController
 * 
 * 
 */
@Controller
public class IndexController {

	private static final String FAR_SERVICE_DIR = "http://192.168.30.39:8080/receive";//远程服务器接受文件的路由
	private static final long yourMaxRequestSize = 10000000;

	@RequestMapping("/")
	public String index(Model model) throws IOException {

		return "/index";
	}

	@RequestMapping("/upload")
	public String upload(HttpServletRequest request) throws Exception {
		// 判断enctype属性是否为multipart/form-data
		boolean isMultipart = ServletFileUpload.isMultipartContent(request);
		if (!isMultipart)
			throw new IllegalArgumentException(
					"上传内容不是有效的multipart/form-data类型.");

		// Create a factory for disk-based file items
		DiskFileItemFactory factory = new DiskFileItemFactory();

		// Create a new file upload handler
		ServletFileUpload upload = new ServletFileUpload(factory);

		// 设置上传内容的大小限制(单位:字节)
		upload.setSizeMax(yourMaxRequestSize);

		// Parse the request
		List<?> items = upload.parseRequest(request);

		Iterator iter = items.iterator();
		while (iter.hasNext()) {
			FileItem item = (FileItem) iter.next();

			if (item.isFormField()) {
				// 如果是普通表单字段
				String name = item.getFieldName();
				String value = item.getString();
				// ...
			} else {
				// 如果是文件字段
				String fieldName = item.getFieldName();
				String fileName = item.getName();
				String contentType = item.getContentType();
				boolean isInMemory = item.isInMemory();
				long sizeInBytes = item.getSize();
				// ...

				//上传到远程服务器
					InputStream uploadedStream = item.getInputStream();
					HashMap<String, InputStream> files = new HashMap<String, InputStream>();
					files.put(fileName, uploadedStream);
					uploadToFarService(files);
					uploadedStream.close();
			}
		}
		return "redirect:/";
	}

	public void uploadToFarService(HashMap<String, InputStream> files) {
		try {
			String BOUNDARY = "---------7d4a6d158c9"; // 定义数据分隔线
			URL url = new URL(FAR_SERVICE_DIR);
			HttpURLConnection conn = (HttpURLConnection) url.openConnection();
			// 发送POST请求必须设置如下两行
			conn.setDoOutput(true);
			conn.setDoInput(true);
			conn.setUseCaches(false);
			conn.setRequestMethod("POST");
			conn.setRequestProperty("connection", "Keep-Alive");
			conn.setRequestProperty("user-agent",
					"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)");
			conn.setRequestProperty("Charsert", "UTF-8");
			conn.setRequestProperty("Content-Type",
					"multipart/form-data; boundary=" + BOUNDARY);

			OutputStream out = new DataOutputStream(conn.getOutputStream());
			byte[] end_data = ("\r\n--" + BOUNDARY + "--\r\n").getBytes();// 定义最后数据分隔线
			Iterator iter = files.entrySet().iterator();
			int i=0;
			while (iter.hasNext()) {
				i++;
				Map.Entry entry = (Map.Entry) iter.next();
				String key = (String) entry.getKey();
				InputStream val = (InputStream) entry.getValue();
				String fname = key;
				File file = new File(fname);
				StringBuilder sb = new StringBuilder();
				sb.append("--");
				sb.append(BOUNDARY);
				sb.append("\r\n");
				sb.append("Content-Disposition: form-data;name=\"file" + i
						+ "\";filename=\"" + key + "\"\r\n");
				sb.append("Content-Type:application/octet-stream\r\n\r\n");

				byte[] data = sb.toString().getBytes();
				out.write(data);
				DataInputStream in = new DataInputStream(val);
				int bytes = 0;
				byte[] bufferOut = new byte[1024];
				while ((bytes = in.read(bufferOut)) != -1) {
					out.write(bufferOut, 0, bytes);
				}
				out.write("\r\n".getBytes()); // 多个文件时,二个文件之间加入这个
				in.close();
			}
			out.write(end_data);
			out.flush();
			out.close();

			// 定义BufferedReader输入流来读取URL的响应
			BufferedReader reader = new BufferedReader(new InputStreamReader(
					conn.getInputStream(), "UTF-8"));
			String line = null;
			while ((line = reader.readLine()) != null) {
				System.out.println(line);
			}

		} catch (Exception e) {
			System.out.println("发送POST请求出现异常!" + e);
			e.printStackTrace();
		}
	}

}







服务端


我们仍然在基础项目上fileController中实现接收文件。代码如下:

FileController.java

package com.test.web.controller;

import java.io.File;
import java.util.Iterator;
import java.util.List;

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

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * IndexController
 * 
 * 
 */
@Controller
public class FileController {

	//private static final String STORE_FILE_DIR="/usr/local/image/";//文件保存的路径
	private static final String STORE_FILE_DIR="D:\\";//文件保存的路径

	@RequestMapping("/receive")
	public String receive(HttpServletRequest request,HttpServletResponse response) throws Exception {
		// 判断enctype属性是否为multipart/form-data
		boolean isMultipart = ServletFileUpload.isMultipartContent(request);
		if (!isMultipart)
			throw new IllegalArgumentException(
					"上传内容不是有效的multipart/form-data类型.");

		// Create a factory for disk-based file items
		DiskFileItemFactory factory = new DiskFileItemFactory();

		// Create a new file upload handler
		ServletFileUpload upload = new ServletFileUpload(factory);

		// Parse the request
		List<?> items = upload.parseRequest(request);

		Iterator iter = items.iterator();
		while (iter.hasNext()) {
			FileItem item = (FileItem) iter.next();
			if (item.isFormField()) {
				// 如果是普通表单字段
				String name = item.getFieldName();
				String value = item.getString();
				// ...
			} else {
				// 如果是文件字段
				String fieldName = item.getFieldName();
				String fileName = item.getName();
				String contentType = item.getContentType();
				boolean isInMemory = item.isInMemory();
				long sizeInBytes = item.getSize();
				
				String filePath=STORE_FILE_DIR+fileName;
				//写入文件到当前服务器磁盘
				File uploadedFile = new File(filePath);
				// File uploadedFile = new File("D:\haha.txt");
				item.write(uploadedFile);
			}
		}
		response.setCharacterEncoding("UTF-8");  
		 response.getWriter().println("上传成功");
		return null;
	}

}

我们需要把服务端发布到 远程服务器上 使用tomcat等运行起来。

如果项目中有shiro拦截的话记得设置成  /receive = anon 。让接收文件的路由不被拦截。

然后运行客户端,选择文件就可以上传了。对安全有要求的,可以在客户端加一个key,服务器端接收到请求后验证key,没问题的话 再写入目录和文件。







评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

张小凡vip

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值