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

xiaoxiao2021-02-28  96

我们在之前的文章

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.htmljspsmart的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,没问题的话 再写入目录和文件。

转载请注明原文地址: https://www.6miu.com/read-50004.html

最新回复(0)