热门标签 | HotTags
当前位置:  开发笔记 > 前端 > 正文

Java中用Socket实现HTTP文件上传实例

我想做过web开发的程序员大部分都做过文件上传的功能,大多数时候我们都是借助于commons-fileupload这样的jar包实现的。下面

我想做过web开发的程序员大部分都做过文件上传的功能,大多数时候我们都是借助于commons-fileupload这样的jar包实现的。下面我试着通过读取Socket的输入流来实现一个文件上传的功能。

在做文件上传之前我们需要先了解一下HTTP POST的附件上传协议。HTTP附件上传协议是RFC1876协议,RFC1876协议是在HTTP协议的基础上为INPUT标签增加了file属性,同时限定了Form的method必须为POSTENCTYPE必须为multipart/form-data。RFC1867协议对HTTP头作了适当地变更,content-type头由以前的:content-type:application/x-www-form-urlencoded变为content-type:multipart/form-data;+空格+boundary=字符串。RFC1867增加了文件上传得功能,而上传文件内容自然也会被加入到HTTP的实体中。现在因为既有HTTP一般的参数实体,又有上传文件的实体,所以用boundary把每种实体进行了分割。具体的看下图:

接下来就开始我们的代码部分吧。

我在前面的文章中写过创建一个自己的Web服务器,现在我们的重点要放在对socket的输入流的解析中。具体代码如下:

public void parseRequest() { 
  LineNumberReader br = new LineNumberReader(new InputStreamReader(inputStream)); 
  StringBuffer sb = new StringBuffer(); 
  String str = null; 
  try { 
    //读取请求行 
    String requestLine = br.readLine(); 
    if (!StringUtils.isEmpty(requestLine)) { 
      sb.append(requestLine); 
      String[] reqs = requestLine.split(" "); 
      if (reqs != null && reqs.length > 0) { 
        if ("GET".equals(reqs[0])) { 
          method = "GET"; 
        } else { 
          method = "POST"; 
        } 
      } 
    } 
    //读取请求头 
    while ((str = br.readLine()) != null) { 
      if ("".equals(str)) { 
        break; 
      } 
      if (!StringUtils.isEmpty(str)) { 
        if (str.indexOf(":") > 0) { 
          String[] strs = str.split(":"); 
          headers.put(strs[0].toLowerCase(), strs[1].trim()); 
        } 
      } 
      sb.append(str).append("\n"); 
    } 
    //POST请求,Content-type为 multipart/form-data 
    String cOntentType= null; 
    if ("POST".equals(method) && ((cOntentType= headers.get("content-type")) != null 
        && headers.get("content-type").startsWith("multipart/form-data"))) { 
      //文件上传的分割位 这里只处理单个文件的上传 
      String boundary = contentType.substring(contentType.indexOf("boundary") + 
          "boundary=".length()); 
      //解析消息体 
      while ((str = br.readLine()) != null) { 
        //解析结束的标记 
        do { 
          //读取boundary中的内容 
          //读取Content-Disposition 
          str = br.readLine(); 
          //说明是文件上传 
          if (str.indexOf("Content-Disposition:") >= 0 && str.indexOf("filename") > 0) { 
            str = str.substring("Content-Disposition:".length()); 
            String[] strs = str.split(";"); 
            String fileName = strs[strs.length - 1].replace("\"", "").split("=")[1]; 
            System.out.println("fileName = " + fileName); 
            //这一行是Content-Type 
            br.readLine(); 
            //这一行是换行 
            br.readLine(); 
            //正式去读文件的内容 
            BufferedWriter bw = null; 
            try { 
              bw = new BufferedWriter(new OutputStreamWriter(new 
                  FileOutputStream("G:\\LearnVideo\\fileLoad" + 
                  File.separator + fileName), "UTF-8")); 
              while (true) { 
                str = br.readLine(); 
                if (str.startsWith("--" + boundary)) { 
                  break; 
                } 
                bw.write(str); 
                bw.newLine(); 
              } 
              bw.flush(); 
            } catch (Exception e) { 
 
            } finally { 
              if (bw != null) { 
                bw.close(); 
              } 
            } 
          } 
          if (str.indexOf("Content-Disposition:") >= 0) { 
            str = str.substring("Content-Disposition:".length()); 
            String[] strs = str.split(";"); 
            String name = strs[strs.length - 1].replace("\"", "").split("=")[1]; 
            br.readLine(); 
            StringBuilder stringBuilder = new StringBuilder(); 
            while (true) { 
              str = br.readLine(); 
              if (str.startsWith("--" + boundary)) { 
                break; 
              } 
              stringBuilder.append(str); 
            } 
            parameters.put(name, stringBuilder.toString()); 
          } 
        } while (("--" + boundary).equals(str)); 
        //解析结束 
        if (str.equals("--" + boundary + "--")) { 
          break; 
        } 
      } 
    } 
    //System.out.println(sb.toString()); 
    //获取URI 
    uri = StringUtils.parserUri(sb.toString(), " "); 
    int flag = -1; 
    //说明有参数 
    if ((flag = uri.indexOf('?')) >= 0) { 
      String oldUri = uri; 
      uri = uri.substring(0,flag); 
      String parameterPath = oldUri.substring(flag+1); 
      String[] parameter = parameterPath.split("&"); 
      if (parameter != null && parameter.length > 0) { 
        for (int i = 0; i = 0){ 
            String key = str1.substring(0,flag); 
            String value = str1.substring(flag+1); 
            parameters.put(key,value); 
          }else{ 
            parameters.put(str,null); 
          } 
        } 
      } 
    } 
  } catch (IOException e) { 
    e.printStackTrace(); 
  } 
} 

我们启动自己创建的Web服务器,然后在浏览器中输入:http://localhost:8004/static/uploadPage.html,页面如下:

选择我们要上次的文件,然后点击上传按钮,我们会发现我们的功能已经被上传到G:\LearnVideo\fileLoad这个目录下了。示例如下:

完整的代码请从这里下载:FullStackTraining_jb51.rar

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


推荐阅读
  • 探索新一代API文档工具,告别Swagger的繁琐
    对于后端开发者而言,编写和维护API文档既繁琐又不可或缺。本文将介绍一款全新的API文档工具,帮助团队更高效地协作,简化API文档生成流程。 ... [详细]
  • Hybrid 应用的后台接口与管理界面优化
    本文探讨了如何通过优化 Hybrid 应用的后台接口和管理界面,提升用户体验。特别是在首次加载 H5 页面时,为了减少用户等待时间和流量消耗,介绍了离线资源包的管理和分发机制。 ... [详细]
  • 本文探讨了Java编程的核心要素,特别是其面向对象的特性,并详细介绍了Java虚拟机、类装载器体系结构、Java类文件和Java API等关键技术。这些技术使得Java成为一种功能强大且易于使用的编程语言。 ... [详细]
  • 如何将本地Docker镜像推送到阿里云容器镜像服务
    本文详细介绍将本地Docker镜像上传至阿里云容器镜像服务的步骤,包括登录、查看镜像列表、推送镜像以及确认上传结果。通过本文,您将掌握如何高效地管理Docker镜像并将其存储在阿里云的镜像仓库中。 ... [详细]
  • 阿里云ecs怎么配置php环境,阿里云ecs配置选择 ... [详细]
  • 本文介绍了如何利用 Spring Boot 和 Groovy 构建一个灵活且可扩展的动态计算引擎,以满足钱包应用中类似余额宝功能的推广需求。我们将探讨不同的设计方案,并最终选择最适合的技术栈来实现这一目标。 ... [详细]
  • Windows 7 64位系统下Redis的安装与PHP Redis扩展配置
    本文详细介绍了在Windows 7 64位操作系统中安装Redis以及配置PHP Redis扩展的方法,包括下载、安装和基本使用步骤。适合对Redis和PHP集成感兴趣的开发人员参考。 ... [详细]
  • 本文详细介绍了在腾讯云服务器上配置 phpMyAdmin 的方法,包括安装、配置和解决常见问题。通过这些步骤,您可以轻松地在腾讯云环境中部署并使用 phpMyAdmin。 ... [详细]
  • Nginx 反向代理与负载均衡实验
    本实验旨在通过配置 Nginx 实现反向代理和负载均衡,确保从北京本地代理服务器访问上海的 Web 服务器时,能够依次显示红、黄、绿三种颜色页面以验证负载均衡效果。 ... [详细]
  • 本文深入探讨了SQL数据库中常见的面试问题,包括如何获取自增字段的当前值、防止SQL注入的方法、游标的作用与使用、索引的形式及其优缺点,以及事务和存储过程的概念。通过详细的解答和示例,帮助读者更好地理解和应对这些技术问题。 ... [详细]
  • 本文介绍了如何使用JavaScript的Fetch API与Express服务器进行交互,涵盖了GET、POST、PUT和DELETE请求的实现,并展示了如何处理JSON响应。 ... [详细]
  • 深入解析Java虚拟机(JVM)架构与原理
    本文旨在为读者提供对Java虚拟机(JVM)的全面理解,涵盖其主要组成部分、工作原理及其在不同平台上的实现。通过详细探讨JVM的结构和内部机制,帮助开发者更好地掌握Java编程的核心技术。 ... [详细]
  • HTML基础入门指南
    本文将深入浅出地介绍HTML的基础知识,包括其定义、开发工具、制定机构、特性、基本标签及更多实用内容。 ... [详细]
  • SpringMVC RestTemplate的几种请求调用(转)
    SpringMVCRestTemplate的几种请求调用(转),Go语言社区,Golang程序员人脉社 ... [详细]
  • docker镜像重启_docker怎么启动镜像dock ... [详细]
author-avatar
议Music_Rose_954
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有