struts2 实现文件上传原理

  通过struts2实现文件上传功能,主要jar包是不可少的包括:

复制代码
aopalliance.jar  ------------------------------------为aop(面向切面)提供了最普通和通用的接口
asm-3.3.jar  ----------------------------------------操作java字节码的类库
asm-commons-3.3.jar  --------------------------------提供了基于事件的表现形式
commons-fileupload-1.2.2.jar  -----------------------实现struts文件的上传下载
commons-io-2.0.1.jar  -------------------------------文件上传读取文件
commons-lang3-3.1.jar  ------------------------------为java.lang包提供扩展
commons-logging-1.1.1.jar  --------------------------jakarta的通用日志记录包
freemarker-2.3.19.jar  ------------------------------FreeMarker是一个模板引擎,一个基于模板生成文本输 出的通用工具
javassist-3.11.0.GA.jar  ----------------------------Javassist是一个开源的分析、编辑和创建Java字节码的类库
ognl-3.0.5.jar  -------------------------------------标签库
struts2-convention-plugin-2.3.3.jar  ----------------在默认情况下该公约插件查找操作类在以下软件包支,struts2的行为或行动,任何包相匹配这些名称将被考虑
struts2-core-2.3.3.jar  -----------------------------strut2的核心处理包
struts2-json-plugin-2.3.3.jar  ----------------------struts2所用到的json插件包
xwork-core-2.3.3.jar  -------------------------------webwork的核心库
复制代码

  1.  struts2没有提供自己的请求解析器,也就是就struts2不会自己去处理multipart/form-data的请求,它需要调用其他请求解析器,将HTTP请求中的表单域解析出来。但struts2在原有的上传解析器基础上做了进一步封装,更进一步简化了文件上传。 

  2. struts2默认使用的是Jakarta的Common-FileUpload框架来上传文件,因此,要在web应用中增加Jar文 件:commons-fileupload-1.2.jar和commons-io-1.3.1.jar。它在原上传框架上做了进一步封装,简化了文件上传的代码实现,取消了不同上传框架上的编程差异。 

  3. 如果要改成其它的文件上传框架,可以修改struts.multipart.parser或(struts.multipart.hander)常量的值为cos/pell,默认值是jakata。并在classpath中增加相应上传组件的类库。

  4. struts2所用的文件上传框架都是先将Http上传的文件保存到临时目录下, 然后struts2通过FileUpload拦截器将文件绑定到Action实例中。临时目录可以在struts.xml中配置,如果不配置则会将临时文件存在默认临时目录下(具体目录忘记了。。)。也可以理解为struts2上传文件是通过Action完成的,而Action的工作主要是将缓存目录中的文件复制到目的地址,在Action执行之前,系统已经将文件上传到服务器的临时目录中了。

  5. struts2的文件上传工作都要通过FileUploadInterceptor,这个拦截器对文件大小,文件类型,文件信息进行了拦截设置,但是并没有做IO的监控操作。 

复制代码
贴出FileUploadInterceptor中的一段代码:可以看出当http发出上传请求时,是由MultiPartRequestWrapper类来提供文件名称及文件元素的处理操作的。

 1 public String intercept(ActionInvocation invocation) throws Exception {
 2         ActionContext ac = invocation.getInvocationContext();
 3 
 4         HttpServletRequest request = (HttpServletRequest) ac.get(ServletActionContext.HTTP_REQUEST);
 5 
 6         if (!(request instanceof MultiPartRequestWrapper)) {
 7             if (LOG.isDebugEnabled()) {
 8                 ActionProxy proxy = invocation.getProxy();
 9                 LOG.debug(getTextMessage("struts.messages.bypass.request", new String[]{proxy.getNamespace(), proxy.getActionName()}));
10             }
11 
12             return invocation.invoke();
13         }
14 
15         ValidationAware validation = null;
16 
17         Object action = invocation.getAction();
18 
19         if (action instanceof ValidationAware) {
20             validation = (ValidationAware) action;
21         }
22 
23         MultiPartRequestWrapper multiWrapper = (MultiPartRequestWrapper) request;
24 
25         if (multiWrapper.hasErrors()) {
26             for (String error : multiWrapper.getErrors()) {
27                 if (validation != null) {
28                     validation.addActionError(error);
29                 }
30             }
31         }
32 
33         // bind allowed Files
34         Enumeration fileParameterNames = multiWrapper.getFileParameterNames();
35         while (fileParameterNames != null && fileParameterNames.hasMoreElements()) {
36             // get the value of this input tag
37             String inputName = (String) fileParameterNames.nextElement();
38 
39             // get the content type
40             String[] contentType = multiWrapper.getContentTypes(inputName);
41 
42             if (isNonEmpty(contentType)) {
43                 // get the name of the file from the input tag
44                 String[] fileName = multiWrapper.getFileNames(inputName);
45 
46                 if (isNonEmpty(fileName)) {
47                     // get a File object for the uploaded File
48                     File[] files = multiWrapper.getFiles(inputName);
49                     if (files != null && files.length > 0) {
50                         List<File> acceptedFiles = new ArrayList<File>(files.length);
51                         List<String> acceptedContentTypes = new ArrayList<String>(files.length);
52                         List<String> acceptedFileNames = new ArrayList<String>(files.length);
53                         String contentTypeName = inputName + "ContentType";
54                         String fileNameName = inputName + "FileName";
55 
56                         for (int index = 0; index < files.length; index++) {
57                             if (acceptFile(action, files[index], fileName[index], contentType[index], inputName, validation)) {
58                                 acceptedFiles.add(files[index]);
59                                 acceptedContentTypes.add(contentType[index]);
60                                 acceptedFileNames.add(fileName[index]);
61                             }
62                         }
63 
64                         if (!acceptedFiles.isEmpty()) {
65                             Map<String, Object> params = ac.getParameters();
66 
67                             params.put(inputName, acceptedFiles.toArray(new File[acceptedFiles.size()]));
68                             params.put(contentTypeName, acceptedContentTypes.toArray(new String[acceptedContentTypes.size()]));
69                             params.put(fileNameName, acceptedFileNames.toArray(new String[acceptedFileNames.size()]));
70                         }
71                     }
72                 } else {
73                     if (LOG.isWarnEnabled()) {
74                         LOG.warn(getTextMessage(action, "struts.messages.invalid.file", new String[]{inputName}));
75                     }
76                 }
77             } else {
78                 if (LOG.isWarnEnabled()) {
79                     LOG.warn(getTextMessage(action, "struts.messages.invalid.content.type", new String[]{inputName}));
80                 }
81             }
82         }
83 
84         // invoke action
85         return invocation.invoke();
86     }
复制代码

   6. 继续深入,MartiPartRequestWarpper对MartiPartRequest接口的主要功能进行的封装应用,因此要继续深入到MartiPartRequest接口的实现类,可以了解到struts2是如何对文件上传进行控制操作的。

复制代码
 1 MartiPartRequestWrapper的构造方法:
 2 
 3 public MultiPartRequestWrapper(MultiPartRequest multiPartRequest, HttpServletRequest request, String saveDir, LocaleProvider provider) {
 4         super(request);
 5         errors = new ArrayList<String>();
 6         multi = multiPartRequest;
 7         defaultLocale = provider.getLocale();
 8         setLocale(request);
 9         try {
10             multi.parse(request, saveDir);
11             for (String error : multi.getErrors()) {
12                 addError(error);
13             }
14         } catch (IOException e) {
15             if (LOG.isWarnEnabled()) {
16                 LOG.warn(e.getMessage(), e);
17             }
18             addError(buildErrorMessage(e, new Object[] {e.getMessage()}));
19         } 
20     }
复制代码

  7. 从上面的代码中可以知道,MultiPartRequest提供了主要的功能框架,JarkatMultiPartRequest是MultiPartRequest的实现类,对文件上传具体功能进行了封装。可以通过改写此类实现对文件上传进度的监控,实现进度条功能(在后面的知识中详细介绍进度条功能的实现)。

  在JarkatMultiPartRequest源码中提供了方法parse(HttpServletRequest request, String saveDir),通过调用progressUpload(HttpServletRequest request, String saveDir)对文件上传进度进行控制。在其中通过DiskFileItemFactory、 ServletFileUpload对上传文件进行加载,并读取。

阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭