前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Tomcat NIO(16)-文件上传

Tomcat NIO(16)-文件上传

作者头像
TA码字
发布2020-12-14 11:53:52
8760
发布2020-12-14 11:53:52
举报
文章被收录于专栏:TA码字TA码字

上一篇文章中我们主要介绍了 tomcat nio 中的长连接,包括长连接开启和关闭的条件,每个长连接可以复用的请求数目等等,在这里我们介绍 tomcat 对文件上传的支持。

对于 http 协议来说,文件上传一般会为 POST 请求的 muti-part 类型,即请求中会包含 content-type 值为 multipart/form-data 的请求头。对于这种请求主要包含下面两个项:

  • 文件上传的 trigger
  • 文件上传的本质

文件上传的trigger

根据以前文章,消费 servlet 的 inputstream 就会触发解析请求体,对于 multipart/form-data 类型的请求就会完成对文件上传的支持。对于 servlet API 来说,调用 HttpServletRequest 对象实例的 getParameter()

/getParameterMap()/getParameterNames()/getParameterValues() 等方法都会触发解析请求体,所以对这些 API 的调用就间接完成了文件上传的支持。

另外如果我们调用 HttpServletRequest 对象实例的 getParts() 或者是 getPart() 方法, 就会直接获取到 multipart/form-data 类型的请求体中的各个 part,可以得到每个 part(文件) 的 inputstream ,name,size 等信息。并且如果获取了文件的 inputstream 之后,就可以根据逻辑完成我们对文件的操作。所以这两个 API 会直接完成文件上传操作。

文件上传的本质

对于 tomcat 上传文件来说,其本质是把文件上传到 tomcat 工作目录中,通过getPart() 等 API 得到的 inputstream 已经是上传在工作目录中磁盘中文件的输入流了。关于文件上传路径的核心代码在以前文章介绍的 tomcat request 对象的 parseParts() 方法里,核心逻辑如下:

代码语言:javascript
复制
// parseParts() method in org.apache.catalina.connector.Request
String locationStr = mce.getLocation();
if (locationStr == null || locationStr.length() == 0) {
    location = ((File) context.getServletContext().getAttribute(ServletContext.TEMPDIR));
} else {
    location = new File(locationStr);
if (!location.isAbsolute()) {
        location = new File((File) context.getServletContext().getAttribute(ServletContext.TEMPDIR), locationStr).getAbsoluteFile();
    }
}
  • 文件位置由配置 muti-part location 决定,如果没有该配置, 那么该位置将会由上下文属性ServletContext.TEMPDIR(javax.servlet.context.tempdir) 决定,一般值为 tomcat 工作目录中的 Tomcat/{FQDN}/{Context} 。
  • 以下例子我们在 basic-service 上下文的项目里上传两张图片,由上传结果可以看到文件在工作目录下的 Tomcat/localhost/basic-service 中,并且物理文件名字已经改变(但是通过getPart()依然可以得到原始文件名字,大小等信息)

总结一下 tomcat 对于文件上传的支持:

  • 调用消费 servlet 输入流相关的 API 会完成对上传文件的支持,如 getParameter() 和 getPart() 等相关 API。
  • 文件上传的本质是把文件写到 tomcat 工作目录的磁盘中,由 getPart() 相关 API 得到磁盘中文件的大小,文件名,输入流等信息,然后根据业务逻辑进行操作。
  • 这样的上传方式需要考虑空间大小,因为文件保存在磁盘上,长时间不清理会占用大量空间。当然一些框架(如springmvc)对于 muti-part 请求的处理已经帮我们自动清理了上传的文件,但是如果在并发上传文件比较多的时候,依然会占用大量的磁盘空间。
  • 这样的上传方式需要考虑 os 权限问题,因为是保存在磁盘上,所以我们的 java 进程必须要对这个目录有读写权限。当然如果是默认配置,路径在 tomcat 工作目录下,是不需要过多担心权限问题的。但是如果配置了其他路径,就需要考虑权限问题。
  • 这样的上传方式有效率问题,从应用程序角度看,读取文件流有一系列步骤,即文件从网络设备写入磁盘文件,文件再从磁盘读入应用程序。
  • 上面涉及了网络设备,操作系统内核空间,磁盘设备,tomcat 自身应用空间,开发者应用空间的几次切换,当文件比较大的时候会费时间,从优化角度来说我们一般采用流式上传来避免多次切换。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-12-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 TA码字 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档