`
rentianchou
  • 浏览: 69773 次
  • 性别: 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文件上传原理的详细解释: 1. **HTTP协议与表单提交** 在HTML表单中,如果需要上传文件,`&lt;form&gt;`标签必须包含`enctype="multipart/form-data"`属性。这是因为普通POST请求无法处理二进制数据,...

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

    在本文中,我们将深入探讨如何使用Servlet来理解Struts2中的文件上传原理。Servlet是Java Web应用程序中的一个组件,用于处理HTTP请求和响应。而Struts2是一个基于MVC(模型-视图-控制器)设计模式的开源Web应用框架...

    Struts2多个文件上传

    在Struts2中,文件上传功能是一个常用特性,尤其在处理用户提交的多个文件时。本文将详细讲解如何使用Struts2进行多个文件的上传,重点是使用List集合进行上传。 首先,要实现Struts2的文件上传,必须引入必要的...

    struts2 文件上传

    在本篇中,我们将深入探讨Struts2实现文件上传的原理、步骤以及需要注意的关键点。 首先,理解文件上传的基本流程: 1. 用户在表单中选择文件,并提交表单。 2. Struts2 框架接收到请求,解析请求体中的文件数据。...

    Struts2文件上传源码

    本文将详细讲解Struts2文件上传的实现原理以及源码分析。 首先,理解文件上传的基本流程。当用户通过HTML表单选择文件并提交时,这些文件数据会被封装到HTTP请求中。Struts2框架提供了内置的支持来处理这样的请求,...

    struts2文件上传

    Struts2 文件上传是Java Web开发中常见的功能,主要用于接收用户通过表单上传的文件。在Struts2框架中,虽然它自身不处理`multipart/form-data`类型的请求,但它依赖于第三方库,如Apache Commons FileUpload,来...

    struts2文件上传源码和步骤

    1. **文件上传原理**: 文件上传的本质是客户端浏览器将本地文件以二进制流的形式发送到服务器端。在 Struts2 中,我们通常会创建一个 Action 类,该类包含用于接收文件的属性,并通过表单提交来处理文件。 2. **...

    Struts2文件上传

    2. **文件上传原理** 文件上传涉及到HTTP协议中的multipart/form-data编码类型,它允许在一个表单中包含多个部分,每个部分可以视为一个单独的数据单元,包括文件数据。 3. **Struts2文件上传组件** Struts2的`...

    struts多文件上传

    首先,理解多文件上传的基本原理至关重要。在Web应用中,文件上传通常依赖于HTTP协议的`multipart/form-data`编码类型,这种编码允许在表单提交时包含二进制数据(如文件)。Struts框架通过处理这些请求并将其转化为...

    struts2上传文件源代码

    Struts2是一个强大的Java web应用...通过这个示例,开发者可以学习到如何在Struts2项目中实现文件上传功能,并了解其背后的原理和最佳实践。同时,也可以了解到如何与其他开发者共享和学习代码,从而提升自己的技能。

    完整struts2文件上传示例

    在Struts2中,实现文件上传并不复杂,但需要理解其背后的原理和配置。以下是对"完整Struts2文件上传示例"的详细解释: 1. **配置Struts2框架** 在Struts2中,我们首先需要在`struts.xml`配置文件中添加相关的拦截...

    struts2文件上传原理说明

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

    struts2s上传文件

    在Struts2中,文件上传功能是一项常用的功能,允许用户通过Web表单上传文件到服务器。本篇将深入探讨Struts2中的文件上传机制、步骤以及常见问题。 首先,我们要理解文件上传的基本原理。在Web应用中,文件上传通常...

    struts 单文件上传和多文件上传带进度条

    首先,我们需要了解Struts中处理文件上传的基本原理。Struts2提供了一个`FileUpload`拦截器,用于处理文件上传请求。在Action类中,我们需要定义一个或多个`java.io.File`或`org.apache.struts2.dispatcher....

    struts2文件上传的一个简单的例子

    首先,我们需要理解Struts2文件上传的基本原理。Struts2提供了一个名为`FileUpload interceptor`的拦截器,用于处理文件上传请求。这个拦截器会解析请求中的multipart/form-data数据,将文件内容保存到服务器的临时...

    Struts2+上传文件源码

    Struts2是一个非常流行的Java Web框架,用于...通过研究这些代码,你可以更好地理解Struts2框架下文件上传的工作原理,以及如何在实际项目中应用。记住,实践是最好的老师,动手尝试并理解每一行代码是提升技能的关键。

    struts2 文件上传,也可以多文件上传

    首先,我们要了解Struts2文件上传的基本原理。Struts2使用Apache的Commons FileUpload库来处理文件上传。这个库将HTTP请求中的multipart/form-data解析为一个个单独的文件和字段,使得我们可以方便地访问上传的文件...

Global site tag (gtag.js) - Google Analytics