Android笔记(三):整理——利用http上传小文件

本文记录如何使用rfc1867协议来上传文本文件(大小不能超过2M)


首先客户端上传文件时,服务器要收到客户端的请求就必须在客户端人工构造rfc1867协议规定的请求内容。

具体如下:

--UUID

Content-Disposition:form-data;name="字段名"

Content-Type:text/plain;charset=UTF-8       //如果上传的不是文本文件而是图片,则text/plain改为image/jpeg

Content-Transfer-Enconding:8dit       //所传送的内容不符合默认的编码方式,须加上该标题头

字段属性值

--UUID

Content-Disposition:form-data;name="字段名";filename="文件名"

Content-Type:application/octet-stream;charset=UTF-8

文件内容(二进制流)

--UUID--        //最后要加上回车   


其中UUID是随机生成的一串数字,作为分隔符。


下面是客户端的实现:

public class FileUploadActivity extends Activity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        StrictMode
                .setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
                        .detectDiskReads().detectDiskWrites()
                        .detectNetwork().penaltyLog().build());
        StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
                .detectLeakedSqlLiteObjects()
                .detectLeakedClosableObjects().penaltyLog()
                .penaltyDeath().build());
        Button button = new Button(this);
        button.setText("上传");
        setContentView(button);
        button.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                final String actionUrl = "http://36078d58.nat123.cc/FileUploadAndDownload/UploadHandleServlet";
                final Map<String, String> params = new HashMap<>();
                params.put("strParamName", "strParamValue");
                final Map<String, File> files = new HashMap<>();
                files.put("android上传.txt", new File("/storage/emulated/0/eguan.txt"));  // key为上传后的文件名,value为要上传的文件路径
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            String str = post(actionUrl, params, files);
                            Log.d("FileUploadActivity", "结果:" + str);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }).start();

            }
        });
    }

    public static String post(String actionUrl,
                              Map<String, String> params, Map<String, File> files)
            throws IOException {

        String BOUNDARY = java.util.UUID.randomUUID().toString();
        String PREFIX = "--", LINEND = "\r\n";
        String MULTIPART_FROM_DATA = "multipart/form-data";
        String CHARSET = "UTF-8";

        URL uri = new URL(actionUrl);
        HttpURLConnection conn = (HttpURLConnection) uri
                .openConnection();
        conn.setReadTimeout(5 * 1000); // 缓存的最长时间
        conn.setDoInput(true);// 允许输入
        conn.setDoOutput(true);// 允许输出
        conn.setUseCaches(false); // 不允许使用缓存
        conn.setRequestMethod("POST");
        conn.setRequestProperty("connection", "keep-alive");   //保持连接活跃
        conn.setRequestProperty("Charset", "UTF-8");
        conn.setRequestProperty("Content-Type", MULTIPART_FROM_DATA
                + ";boundary=" + BOUNDARY);

        // 首先组拼文本类型的参数
        StringBuilder sb = new StringBuilder();
        for (Map.Entry<String, String> entry : params.entrySet()) {
            sb.append(PREFIX);
            sb.append(BOUNDARY);
            sb.append(LINEND);
            sb.append("Content-Disposition: form-data; name=\""
                    + entry.getKey() + "\"" + LINEND);
            sb.append("Content-Type: text/plain; charset="
                    + CHARSET + LINEND);
            sb.append("Content-Transfer-Encoding: 8bit" + LINEND);
            sb.append(LINEND);
            sb.append(entry.getValue());
            sb.append(LINEND);
        }

        DataOutputStream outStream = new DataOutputStream(
                conn.getOutputStream());
        outStream.write(sb.toString().getBytes());
        // 发送文件数据
        if (files != null)
            for (Map.Entry<String, File> file : files.entrySet()) {
                StringBuilder sb1 = new StringBuilder();
                sb1.append(PREFIX);
                sb1.append(BOUNDARY);
                sb1.append(LINEND);
                sb1.append("Content-Disposition: form-data; name=\"file\"; filename=\""
                        + file.getKey() + "\"" + LINEND);
                sb1.append("Content-Type: application/octet-stream; charset="
                        + CHARSET + LINEND);
                sb1.append(LINEND);
                outStream.write(sb1.toString().getBytes());

                InputStream is = new FileInputStream(file.getValue());
                byte[] buffer = new byte[1024];
                int len;
                while ((len = is.read(buffer)) != -1) {
                    outStream.write(buffer, 0, len);
                }

                is.close();
                outStream.write(LINEND.getBytes());
            }

        // 请求结束标志
        byte[] end_data = (PREFIX + BOUNDARY + PREFIX + LINEND)
                .getBytes();
        outStream.write(end_data);
        outStream.flush();
        // 得到响应码
        int res = conn.getResponseCode();
        StringBuilder sb2 = null;
        InputStream in = conn.getInputStream();
        if (res == 200) {
            int ch;
            sb2 = new StringBuilder();
            while ((ch = in.read()) != -1) {
                sb2.append((char) ch);
            }
        }
        outStream.close();
        conn.disconnect();
        if (sb2==null)
            return null;
        else
            return sb2.toString();
    }
}


 
 

注:

①真机测试

服务端与客户端不在同一个局域网,访问需要外网ip地址映射,如本文为:http://36078d58.nat123.cc/FileUploadAndDownload/UploadHandleServlet;客户端和服务端处在同一个局域网,则可将36078d58.nat123.cc改为服务端所在计算机的局域网ip地址,如192.168.x.x:8080。

②模拟器测试

客户端是android自带的模拟器的,ip改为10.0.2.2:8080;是第三方模拟器的,ip改为服务端所在计算机的ip地址。

下面是服务端的实现:

在eclipse下新建一个web项目,名为FileUploadAndDownload,在src目录下新建一个包,在包内新建一个java文件,名为UploadHandleServlet.java,然后将项目打包成war文件放到Tomcat服务器所在目录下的webapps文件夹内,并启动Tomcat。

@WebServlet("/UploadHandleServlet")
public class UploadHandleServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	/**
	 * @see HttpServlet#HttpServlet()
	 */
	public UploadHandleServlet() {
		super();
		// TODO Auto-generated constructor stub
	}

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// TODO Auto-generated method stub
		// 得到上传文件的保存目录,将上传的文件存放于WEB-INF目录下,不允许外界直接访问,保证上传文件的安全
		String savePath = this.getServletContext().getRealPath("/WEB-INF/upload");
		File file = new File(savePath);
		// 判断上传文件的保存目录是否存在
		if (!file.exists() && !file.isDirectory()) {
			System.out.println(savePath + "目录不存在,需要创建");
			// 创建目录
			file.mkdir();
		}
		// 消息提示
		String message = "";
		try {
			// 使用Apache文件上传组件处理文件上传步骤:
			// 1、创建一个DiskFileItemFactory工厂
			DiskFileItemFactory factory = new DiskFileItemFactory();
			// 2、创建一个文件上传解析器
			ServletFileUpload upload = new ServletFileUpload(factory);
			// 解决上传文件名的中文乱码
			upload.setHeaderEncoding("UTF-8");
			// 3、判断提交上来的数据是否是上传表单的数据
			if (!ServletFileUpload.isMultipartContent(request)) {
				// 按照传统方式获取数据
				return;
			}
			// 4、使用ServletFileUpload解析器解析上传数据,解析结果返回的是一个List<FileItem>集合,每一个FileItem对应一个Form表单的输入项
			List<FileItem> list = upload.parseRequest(request);
			for (FileItem item : list) {
				// 如果fileitem中封装的是普通输入项的数据
				if (item.isFormField()) {
					String name = item.getFieldName();
					// 解决普通输入项的数据的中文乱码问题
					String value = item.getString("UTF-8");
					// value = new String(value.getBytes("GB2312"),"UTF-8");
					System.out.println(name + "=" + value);
				} else {// 如果fileitem中封装的是上传文件
						// 得到上传的文件名称,
					String filename = item.getName();
					System.out.println(filename);
					if (filename == null || filename.trim().equals("")) {
						continue;
					}
					// 注意:不同的浏览器提交的文件名是不一样的,有些浏览器提交上来的文件名是带有路径的,如:
					// c:\a\b\1.txt,而有些只是单纯的文件名,如:1.txt
					// 处理获取到的上传文件的文件名的路径部分,只保留文件名部分
					filename = filename.substring(filename.lastIndexOf("\\") + 1);
					// 获取item中的上传文件的输入流
					InputStream in = item.getInputStream();
					// 创建一个文件输出流
					FileOutputStream out = new FileOutputStream(savePath + "\\" + filename);
					// 创建一个缓冲区
					byte buffer[] = new byte[1024];
					// 判断输入流中的数据是否已经读完的标识
					int len = 0;
					// 循环将输入流读入到缓冲区当中,(len=in.read(buffer))>0就表示in里面还有数据
					while ((len = in.read(buffer)) > 0) {
						// 使用FileOutputStream输出流将缓冲区的数据写入到指定的目录(savePath + "\\"
						// + filename)当中
						out.write(buffer, 0, len);
					}
					// 关闭输入流
					in.close();
					// 关闭输出流
					out.close();
					// 删除处理文件上传时生成的临时文件
					item.delete();
					message = "文件上传成功!";
				}
			}
		} catch (Exception e) {
			message = "文件上传失败!";
			e.printStackTrace();

		}
		request.setAttribute("message", message);
		request.getRequestDispatcher("/message.jsp").forward(request, response);
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// TODO Auto-generated method stub
		RequestContext req = new ServletRequestContext(request);
		if (FileUpload.isMultipartContent(req)) {
			DiskFileItemFactory factory = new DiskFileItemFactory();
			ServletFileUpload fileUpload = new ServletFileUpload(factory);
			fileUpload.setHeaderEncoding("UTF-8");
			fileUpload.setFileSizeMax(1024 * 1024 * 1024);

			List items = new ArrayList();
			try {
				items = fileUpload.parseRequest(request);
			} catch (Exception e) {

			}

			Iterator it = items.iterator();
			while (it.hasNext()) {
				FileItem fileItem = (FileItem) it.next();
				if (fileItem.isFormField()) {
					System.out.println(fileItem.getFieldName() + " " + fileItem.getName() + " "
							+ new String(fileItem.getString().getBytes("UTF-8"), "UTF-8"));
				} else {
					System.out.println(fileItem.getFieldName() + " " + fileItem.getName() + " " + fileItem.isInMemory()
							+ " " + fileItem.getContentType() + " " + fileItem.getSize());
					if (fileItem.getName() != null && fileItem.getSize() != 0) {
						File fullFile = new File(fileItem.getName());
						File newFile = new File("D:\\" + fullFile.getName());
						try {
							fileItem.write(newFile);
						} catch (Exception E) {

						}
						response.getWriter().write("Success!");
					} else {
						System.out.println("no file choosen or empty file");
						response.getWriter().print("Failure!");
					}
				}
			}
		}
	}

}

注:客户端发送文件上传请求后会调用doPost方法,上传后的文件会保存在D盘,上传成功后会返回结果给客户端。doPost部分代码的解释可参照doGet

猜你喜欢

转载自blog.csdn.net/weixin_40855673/article/details/78692824