mint mvc上传文件的实现封装在mint.mvc.core.upload包内,见下图:
一张大图弥补我拙劣的语言表达能力:
下面来细说upload包中6个类(也就是六个小图···)。
MultipartConfig注解是用来配置文件上传的处理信息的,用法如下:
@MultipartConfig(attributeName = "files", limitSize = 1024*1024*1024, tempFilePath = "D:/upload") @Mapping(urls={"/index", "/index/{id}"}, method="post") public String index(Integer id, String name, String username, MultipartParameter[] files, HttpServletRequest request){ return "index"; }暂时有4个配置项:
MultipartHttpServletRequest继承javax.servlet.http.HttpServletRequestWrapper,是用来封装多媒体表请求。
MultipartHttpServletRequest重写了HttpServletRequestWrapper 的 getPart、getParts、getParameter、getParameterMap方法。并且添加下面的几个方法:
MultipartParameter用来封装多媒体表单的参数,每一个文件域或者文本域封装为一个MultipartParameter对象。该接口继承javax.servlet.http.Part,并且额外声明4个方法:
DefaultMultipartParameter是MultipartParameter的一个实现,详见MultipartParameter和javax.servlet.http.Part
FileUpload是文件上传的工具类,介绍它的两个方法:
UploadExecutor是上传文件的真正执行者。负责多媒体表单的解析,把解析得到的参数封装到一个MultipartParamter数组里,最后调用request的SetAttribute方法,以指定attributeName把MultipartParamter数组保存request内。
如图所示,当接到头部声明有形如"Content-Type:multipart/form-data; boundary=----WebKitFormBound"的请求时,mint-mvc就会开启线程处理多媒体参数,并阻塞当前前端控制器的线程,待多媒体参数解析完毕后,唤醒前端控制器的线程。
以往文件上传的情况是,servlet应用服务器会包办文件上传这个过程,直到把请求数据接受完毕才调用指定的servlet,这样的做法有不少缺点:
mint mvc如此实现文件上传,是试图用servlet3的异步特性,迫使servelt 服务器把文件上传的过程完全交给mint mvc或者使用者来处理,这样做希望达到如下效果:
实际上有点遗憾,servlet3并没有规定在异步功能开启时,文件接收由谁来完成——servlet服务器还是servlet。所以不同servlet服务器有不同的实现。测试中发现tomcat7在开启异步功能时,会把文件上传的工作交给servlet处理,而jetty则不会,至于其他服务器就不知道了
解析文件和参数的过程这里只做简单介绍。
先看看一个包含多个文件域和文本域的http请求头的结构:
再来看对应请求体的结构(请忽略行号):
请求头中的 boundary指的是请求体中的分隔符,但是请求体中的分隔符前面还要多“--”两个字符。请求体最后一个分隔符末尾还额外添加“--”两个字符。
请求体中分隔符和参数描述信息后面还有回车符(\r)和换行符(\n),最后一个分隔符后面有一个换行符(\n)。每个参数的描述头和参数值之间用回车换行符隔开。这些字符作为字符串输出时,看到的效果就是换行。提交数据实际上的格式是这样的:
综上所述,假如HTTP头指定的分隔符是“xxxx”,那么实际上请求体内的数据的格式是这样的:
--xxxx\r\n\r\n<数据>\r\n--xxxx\r\n\r\n<数据>\r\n--xxxx--\n
然后可以知道从请求体中解析参数的大致过程如下:
至于代码怎么写,在此就不说了。
项目地址:http://git.oschina.net/895925636/mint-mvc
收录地址:http://www.oschina.net/p/mint-mvc
博客地址:http://www.wemakers.net/home/blog?cate=1001
(完)