`
rentianchou
  • 浏览: 68345 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

struts2文件上传及原理

阅读更多
但在Struts2 中为我们提供了更为简单易用的上传功能,当然虽然易用,但其实际不是对底层文件IO和HTTP的封装。下面我们介绍一下,如何在Struts2 中使用文件上传的功能。

我们知识Strust2中大部分的功能都是通过拦截器实现的,当然,这里的文件上传也不例外。同样也是也采用拦截器来支持的。



下面以例子来看一下如何使用strsut2 实现文件上传:

1.   在myeclipse 下创建一个strust2  web 工程,正常配置struts.xml。

2.   在web目录下面创建一个upload.jsp 页面,做为页面上传的界面,代码如下:

<%@ page language="java"  contentType="text/html;charset=UTF-8" pageEncoding="UTF-8"%>

<%@ taglib uri="/struts-tags" prefix="s" %>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>

  <head>

    <title>register page</title>

    <meta http-equiv="pragma" content="no-cache">

    <meta http-equiv="cache-control" content="no-cache">

    <meta http-equiv="expires" content="0">   

    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">

    <meta http-equiv="description" content="This is my page">

    <!--

    <link rel="stylesheet" type="text/css" href="styles.css">

    -->

    <script type="text/javascript">

        function addMore(){

            var td=document.getElementById("more");

            var br=document.createElement("br");

            var input=document.createElement("input");

            var button=document.createElement("input");

            input.type="file";

            input.name="file";

            button.type="button";

            button.value="remove";

           

            button.onclick=function(){

                td.removeChild(br);

                td.removeChild(input);

                td.removeChild(button);

            }

           

            td.appendChild(br);

            td.appendChild(input);

            td.appendChild(button);

        }

    </script>

  </head>

 

  <body>

    <br>

    <s:fielderror />

    <s:form action="upload" theme="simple" enctype="multipart/form-data" >

    <table border="1" width="500">

         <tr>

             <td colspan="2">文件上传</td>

         </tr>

         <tr>

             <td>username</td>

             <td><s:textfield name="username"/></td>

         </tr>

         <tr>

             <td>password</td>

             <td><s:password name="password" id="password"/></td>

         </tr>

         <tr>

             <td>file1</td>

             <td id="more"><s:file name="file" id="file"/><input type="button" onclick="addMore()" value="添加..."/></td>

         </tr>

         <tr>

             <td></td>

             <td><s:submit name="submit"/></td>

         </tr>

    </table>

    </s:form>

  </body>

</html>

界面显示如下:





该例子是一个用户可以指定上传文件个数进行上伟的例子,单击添加按钮可以新增上传控制,这个通过javascript 脚本实现的。注意添加的组件的名字都是file,这样上传的文件会传到Action中的一个List中,下面会看到。

1.4创建对应的Action;  UploadAction 代码如下:

package com.snt.struts2.action;



import java.io.File;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.InputStream;

import java.io.OutputStream;

import java.util.List;



import org.apache.struts2.ServletActionContext;



import com.opensymphony.xwork2.ActionSupport;



public class UploadAction extends ActionSupport{

         private String username;                           //对应页面的属性

         private String password;

         private List<File> file;                              //上传文件列表

         private List<String> fileFileName;           //上传文件名

         private List<String> fileContentType;   //上传文件内容类型   这两个值strust2会自动注入

         public List<File> getFile() {

                   return file;

         }

         public void setFile(List<File> file) {

                   this.file = file;

         }

         public List<String> getFileContentType() {

                   return fileContentType;

         }

         public void setFileContentType(List<String> fileContentType) {

                   this.fileContentType = fileContentType;

         }

         public List<String> getFileFileName() {

                   return fileFileName;

         }

         public void setFileFileName(List<String> fileFileName) {

                   this.fileFileName = fileFileName;

         }

         public String getPassword() {

                   return password;

         }

         public void setPassword(String password) {

                   this.password = password;

         }

         public String getUsername() {

                   return username;

         }

         public void setUsername(String username) {

                   this.username = username;

         }

         @Override

         public String execute() throws Exception {

                   for(int i=0;i<file.size();i++){

                            InputStream is=new FileInputStream(file.get(i));

                            String root=ServletActionContext.getRequest().getRealPath("/upload");

                            File destFile=new File(root,this.getFileFileName().get(i));

                            OutputStream os=new FileOutputStream(destFile);

                           

                            byte[] buffer=new byte[400];

                            int length=0;

                            while((length=is.read(buffer))>0){

                                     os.write(buffer,0,length);

                            }

                            is.close();

                            os.close();

                   }

                  

                   return SUCCESS;

         }

}

代码中橙色背景显示的代码 List<File> file 对应页面中要上传的文件,映射到Action中就是File 对象,这种映射是由Strust2的拦截器来实现的。

我们查看strust2 中的strust-detault.xml 文件中,会在默认的拦截器链中发一个fileUpload 的拦截,

在strust2 核心包中 org.apache.struts2.interceptor.FileUploadIntercepotr 这个拦截器,下面是这个拦截器的拦截方法:

public String intercept(ActionInvocation invocation) throws Exception {

        ActionContext ac = invocation.getInvocationContext();    Action上下文

            //获取用户请求判断是否是文件上传请求

        HttpServletRequest request = (HttpServletRequest) ac.get(ServletActionContext.HTTP_REQUEST);

        if (!(request instanceof MultiPartRequestWrapper)) {

            if (log.isDebugEnabled()) {

                ActionProxy proxy = invocation.getProxy();

                log.debug(getTextMessage("struts.messages.bypass.request", new Object[]{proxy.getNamespace(), proxy.getActionName()}, ActionContext.getContext().getLocale()));

            }



            return invocation.invoke();

        }

           

        final Object action = invocation.getAction();

        ValidationAware validation = null;

            //验证

        if (action instanceof ValidationAware) {

            validation = (ValidationAware) action;

        }

            //获取文件上传请求的一个包装类对象

        MultiPartRequestWrapper multiWrapper = (MultiPartRequestWrapper) request;



        if (multiWrapper.hasErrors()) {

            for (Iterator errorIter = multiWrapper.getErrors().iterator(); errorIter.hasNext();) {

                String error = (String) errorIter.next();



                if (validation != null) {

                    validation.addActionError(error);

                }



                log.error(error);

            }

        }

            //大家看这句话,是从Action上下文件环境中取出所以的参数

        Map parameters = ac.getParameters();



        // Bind allowed Files

             //下面是关键的代码,先取得上传文件的参数

             //然后再设置到Action中的File 对象

        Enumeration fileParameterNames = multiWrapper.getFileParameterNames();

        while (fileParameterNames != null && fileParameterNames.hasMoreElements()) {

            // get the value of this input tag

            String inputName = (String) fileParameterNames.nextElement();



            // get the content type

            String[] contentType = multiWrapper.getContentTypes(inputName);



            if (isNonEmpty(contentType)) {

                // get the name of the file from the input tag

                String[] fileName = multiWrapper.getFileNames(inputName);



                if (isNonEmpty(fileName)) {

                    // Get a File object for the uploaded File

                    File[] files = multiWrapper.getFiles(inputName);

                    if (files != null) {

                        for (int index = 0; index < files.length; index++) {



                            if (acceptFile(files[index], contentType[index], inputName, validation, ac.getLocale())) {

                                parameters.put(inputName, files);

                                                            //下面这两行代码下好解释我们在Action中声明的两个属性,

                                                            //fileFileName   fileContentType ,拦截器会自动给它们注入值勤

                                parameters.put(inputName + "ContentType", contentType);

                                parameters.put(inputName + "FileName", fileName);

                            }

                        }

                    }

                } else {

                    log.error(getTextMessage("struts.messages.invalid.file", new Object[]{inputName}, ActionContext.getContext().getLocale()));

                }

            } else {

                log.error(getTextMessage("struts.messages.invalid.content.type", new Object[]{inputName}, ActionContext.getContext().getLocale()));

            }

        }



        // invoke action

        String result = invocation.invoke();



        // cleanup

        fileParameterNames = multiWrapper.getFileParameterNames();

        while (fileParameterNames != null && fileParameterNames.hasMoreElements()) {

            String inputValue = (String) fileParameterNames.nextElement();

            File[] file = multiWrapper.getFiles(inputValue);

            for (int index = 0; index < file.length; index++) {

                File currentFile = file[index];

                log.info(getTextMessage("struts.messages.removing.file", new Object[]{inputValue, currentFile}, ActionContext.getContext().getLocale()));



                if ((currentFile != null) && currentFile.isFile()) {

                    currentFile.delete();

                }

            }

        }



        return result;

    }



通过这个拦截器,Strsut2 2自动将上传文件对应到Action中的File对象,Action中再通过IO流将其写入到磁盘文件。这就是上传的原理。

在execute方法 中的代码是简单的文件流操作。

1.5上面UploadAction写在,在strust.xml 文件中如下配置:



<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE struts PUBLIC

    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"

    "http://struts.apache.org/dtds/struts-2.0.dtd">

   <struts>

        <constant name="struts.custom.i18n.resources" value="message" />

        <constant name="struts.multipart.saveDir" value="D:\"></constant>

        <package name="struts2" extends="struts-default">

            <!-- 配置拦截器 -->

            <interceptors>

                <!-- 自定义拦截器栈 -->

                <interceptor-stack name="myStack">

                    <interceptor-ref name="defaultStack" />

                </interceptor-stack>

            </interceptors>

            <action name="upload" class="com.snt.struts2.action.UploadAction">

                <!-- 注意拦截顺序,需要覆盖的先配置 -->

                <interceptor-ref name="fileUpload">

                <result name="success">/uploadResult.jsp</result>

                <result name="input">/upload.jsp</result>

            </action>  

        </package>

   </struts>

  

好配置好了!

1.6 部署应用程序到tomcat 下面,运行测试:

可以正常上传文件。

1.7 上面的我们实现的文件上传,但是在实际的开发应用中,上传文件的文件类型和大小都是有限制的。

在Strust2 中通过配置方式就可以实现。

我们先看一下拦截器FileUploadInterceptor 拦截器中的属性如下:

public class FileUploadInterceptor extends AbstractInterceptor {

    private static final long serialVersionUID = -4764627478894962478L;



    protected static final Log log = LogFactory.getLog(FileUploadInterceptor.class);

    private static final String DEFAULT_DELIMITER = ",";

    private static final String DEFAULT_MESSAGE = "no.message.found";



    protected Long maximumSize;

    protected String allowedTypes;

    protected Set allowedTypesSet = Collections.EMPTY_SET;

当我们看到上面三个属性时,应该可以想到strust2 是如何限制上传文件类型的大小的。

所以我们只需要在配置Action时,修改一个拦截器的配置就可以了,如下配置:

<action name="upload" class="com.snt.struts2.action.UploadAction">

                <!-- 注意拦截顺序,需要覆盖的先配置 -->

                <interceptor-ref name="fileUpload">

                    <param name="maximumSize">409600</param>

                    <param name="allowedTypes">application/vnd.ms-excel</param>

                </interceptor-ref>

                <interceptor-ref name="myStack" />

                <result name="success">/uploadResult.jsp</result>

                <result name="input">/upload.jsp</result>

            </action>

在配置文件上传拦截器时加两个参数配置即可。

再次部署测试应用程序,发现可以如果文件类型不对或大小过限,则页面又跳回上传页面,说明我们配置的起作用,这是因为上传程序出现异常,程序跳转到页面.在控制我们可以看到“严重”的报错信息.

如果我们在页面上加一句: <s:filederror /> ,运行就可以显示出错的原因,但是这样的报错信息显示太不友好。其实报错的信息就是一条Field 级别的错误信息。

如何屏蔽呢?

之前在struts2 输入校验的时候,讲在message.proeprties 文件中配置可以屏蔽校验的出错信息。

所以我们可以在这里配置信息:

但是现在又不知道,报告的信息的key 值是什么?

我们打开sturst2 核心包中strust-message.proeprties 文件,内容如下:

struts.messages.invalid.token=The form has already been processed or no token was supplied, please try again.

struts.internal.invalid.token=Form token {0} does not match the session token {1}.



struts.messages.bypass.request=Bypassing {0}/ {1}

struts.messages.current.file=File {0} {1} {2} {3}

struts.messages.invalid.file=Could not find a Filename for {0}. Verify that a valid file was submitted.

struts.messages.invalid.content.type=Could not find a Content-Type for {0}. Verify that a valid file was submitted.

struts.messages.removing.file=Removing file {0} {1}

struts.messages.error.uploading=Error uploading: {0}

struts.messages.error.file.too.large=File too large: {0} "{1}" {2}

struts.messages.error.content.type.not.allowed=Content-Type not allowed: {0} "{1}" {2}



我们可以找到其中几个就是我们想要信息。

struts.messages.error.file.too.large 代表上传文件过大会显示的信息

struts.messages.error.content.type.not.allowed 代表上传文件类型不允许,会显示的信息,我们要覆盖这样的信息,需要在classes 目录下[src目录下]的

message.proeprteis 文件中配置

truts.messages.error.content.type.not.allowed=\u4e0a\u4f20\u6587\u4ef6\u7c7b\u578b\u4e0d\u5339\u914d,\u8bf7\u91cd\u8bd5

struts.messages.error.file.too.large=\u4e0a\u4f20\u6587\u4ef6\u8fc7\u5927,\u8bf7\u91cd\u8bd5

上面显示的汉字要通过native2ascii 工具进行编码转化。

再次运行测试就可以正常显示我们配置的信息。

到此,我们已经实现了一个完整功能的文件上传例子。



当然上面是个多文件上传的例子,如果是单个文件,只要在Action中将List改为单个对象,execute 代码稍作修改即可。

另外需要注意的是strsuts.xml 中配置的两具常量,这个常量:

国际化信息配置文件指定

<constant name="struts.custom.i18n.resources" value="message" />

上传文件的临时保存目录

<constant name="struts.multipart.saveDir" value="D:\"></constant>  
分享到:
评论

相关推荐

    Struts2.0文件上传原理

    我的Struts2.0文件上传原理实例 博文链接:https://zmx.iteye.com/blog/459187

    通过Servlet文件上传理解Struts2文件上传原理(附源码)

    NULL 博文链接:https://88548886.iteye.com/blog/1558943

    struts2文件上传原理说明

    struts2文件上传原理分析文档。使用Commons_fileupload的框架实现上传。

    Struts2 文件上传下载代码 Struts2

    Struts2 文件上传下载代码 tomcat6.x运行 内有文件上传原理代码

    Struts2文件的上传和下载

    1. 文件上传的原理: 表单元素的enctype属性指定的是表单数据的编码方式,该属性有3个值: 1) application/x-www-form-urlencoded:这是默认编码方式,它只处理表单域里的value属性值,采用这种编码方式的表单会...

    Struts2 上传文件

    Struts2 上传文件详解!关于Struts2上传下载原理及实例讲解。

    struts2实现文件上传

    struts2文件上传。上传原理,想下载的哥们看看了

    02_张孝祥09年Struts视频_文件上传单元

    struts文件上传单元目录列表: 01.文件上传的网页设置与数据格式分析 02.阐释软件分层的设计思想 03.文件上传组件的实现原理与应用分析 04.用struts获取上传文件名和解决中文乱码 05.保存用struts获取的上传文件内容...

    11_张孝祥09年Struts视频_文件上传单元

    struts文件上传单元目录列表: 01.文件上传的网页设置与数据格式分析 02.阐释软件分层的设计思想 03.文件上传组件的实现原理与应用分析 04.用struts获取上传文件名和解决中文乱码 05.保存用struts获取的上传文件内容...

    struts文件上传详解

    详细介绍了struts文件上传的原理机制和注意事项

    Struts2.0 实现文件上传进度

    Struts2.0 实现文件上传进度 原理和实现 主要是实现Struts2.0的监听器

    struts2入门学习源码

    struts2学习笔记和源码,struts2原理。文件上传、i18n等等

    struts2 上传 带有进度条

    在struts2中上传是很简单的,struts2会先把文件写到临时文件中,以后在提供这个文件的File对象到action中。具体原理看这里:

    Struts2入门教程(全新完整版)

    九、文件上传下载(了解) 55 1. 上传实例 55 2.下载实例 57 十、类型转换 57 1.基于Action的直接属性转换 57 2.基于Action的间接属性vo转换 59 十一、注解配置 59 十二、总结 本教程对struts2的基本知识进行了一些...

    struts2+swfupload实现大文件多文件上传

    资源绝对可以用,经本人测试。。 原理:一次可以全选N个文件,然后将文件放入队列中,依次单个文件上传。可以设定上传文件大小类型,只需要更改路径就可以了

    struts2讲义_吴峻申

    4.4 Struts2文件上传拦截器应用 61 4.4.1 Struts2文件上传功能开发 61 4.4.2 Struts2文件下载功能开发 68 第5章 Struts2标签库 73 5.1 Struts2标签使用原理解疑 73 5.2 OGNL表达式语言介绍 75 5.3 Struts2控制标签...

    struts2.0文件的上传与下载

    里面包括了文件上传的jsp页面和action中的处理代码。可以清楚的知道文件上传与下载的工作原理

    Struts2 in action中文版

    3.5 案例研究:文件上传 56 3.5.1 通过struts-default包获得内建的支持 56 3.5.2 fileUpload拦截器做什么 57 3.5.3 Struts 2公文包示例代码研究 58 3.6 小结 60 第4章 使用拦截器追加工作流 61 4.1 为什么要拦截...

    struts2-core-2.3.31.jar

    该漏洞与Apache Struts2 (S2-045)远程代码执行漏洞原理基本相同,均是由于上传功能的异常处理函数没有正确处理用户输入的错误信息,导致远程攻击者可通过发送恶意的数据包,利用该漏洞在受影响服务器上执行任意...

    张孝祥09年Struts视频—03文件上传组件的实现原理与应用分析

    03文件上传组件的实现原理与应用分析,分析很到位!

Global site tag (gtag.js) - Google Analytics