zoukankan      html  css  js  c++  java
  • struts2文件上传

    1. 文件的上传:

    1). 表单需要注意的 3 点

          

    <%@ page language="java" contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8"%>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Insert title here</title>
    </head>
    <body>
        <!--
         1,form表单请求要是post请求
         2,enctype="multipart/form-data"
         3,上传控件<input type="file" name="file" />
         -->
        <form action="${pageContext.request.contextPath }/fileUploadAction"
            method="post" enctype="multipart/form-data">
            文件1:<input type="file" name="file" /><br /> 
            文件2:<input type="file" name="file" /><br /> 
            <input type="submit" value="上传文件2">
        </form>
    </body>
    </html>

    2). Struts2 的文件上传实际上使用的是 Commons FileUpload 组件, 所以需要导入

    commons-fileupload-1.3.jar
    commons-io-2.0.1.jar(这里使用了该jar包下的FileUtils的copyFile方法,来做io流的转化)

    3). Struts2 进行文件上传需要使用 FileUpload 拦截器

    4). 基本的文件的上传: 直接在 Action 中定义如下 3 个属性, 并提供对应的 getter 和 setter

    单个文件上传:

    //文件对应的 File 对象
    private File [fileFieldName];//注意这里的名字要和<input type="file" name="file" />控件的name名称一致
    //文件类型
    private String [fileFieldName]ContentType;//控件的name名+ContentType 
    //文件名
    private String [fileFieldName]FileName;//控件的name名+FileName

    如果是多个文件上传:

    //文件对应的 File 对象集合

    private List<File> file;//注意这里的名字要和<input type="file" name="file" />控件的name名称一致

    //文件类型集合
    private List<String> fileContentType;//控件的name名+ContentType

    //文件名集合
    private List<String> fileFileName;//控件的name名+FileName


    5). 使用 IO 流进行文件的上传即可.

    commons-io-2.0.1.jar(这里使用了该jar包下的FileUtils的copyFile方法,来做io流的转化)

    6). 一次传多个文件怎么办 ?

    若传递多个文件, 则上述的 3 个属性, 可以改为 List 类型! 多个文件域的 name 属性值需要一致.

    action代码:

    package com.ibm.action;
    
    import java.io.File;
    import java.util.List;
    
    import org.apache.commons.io.FileUtils;
    import org.apache.struts2.ServletActionContext;
    import org.apache.struts2.convention.annotation.Action;
    import org.apache.struts2.convention.annotation.Namespace;
    import org.apache.struts2.convention.annotation.ParentPackage;
    import org.apache.struts2.convention.annotation.Result;
    
    import com.opensymphony.xwork2.ActionSupport;
    
    /**
     * Description: //模块目的、功能描述
     * 
     * @author Administrator Date: 2018年3月10日
     */
    @ParentPackage("struts-default")
    @Namespace("/")
    public class HelloAction extends ActionSupport {
    	private List<File> file;//注意这里的名字要和<input type="file" name="file" />控件的name名称一致
    	private List<String> fileContentType;//控件的name名+ContentType  
    	private List<String> fileFileName;//控件的name名+FileName
    
    	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;
    	}
    
    	@Action(value = "fileUploadAction", results = { @Result(name = "success", location = "/WEB-INF/success.jsp") })
    	public String fileUpLoad() throws Exception {
    		System.out.println(file);
    		System.out.println(fileContentType);
    		System.out.println(fileFileName);//如:SecureCRT.rar
    		// 参数:web资源路径 返回值 项目发布到服务器后的真实磁盘路径
    		String filesRealPath = ServletActionContext.getServletContext().getRealPath("/files");
    		for (int i = 0; i < file.size(); i++) {
    			File destFile = new File(filesRealPath, fileFileName.get(i));//参数一:文件夹路径,参数二:文件名 结果:返回file对象
    			FileUtils.copyFile(file.get(i), destFile);//参数一:原文件对象,参数二:目标文件对象  作用,将原文件对象的内容copy到目标文件对象
              //注意:这段代码有些bug,如果服务器的files文件夹下已经有了同名同类型的文件,则上传会替换之前的内容,所以这里要给上传的文件设置一个新的名字,推荐uuid } return SUCCESS; } }

    7). 可以对上传的文件进行限制吗 ? 例如扩展名, 内容类型, 上传文件的大小 ? 若可以, 则若出错, 显示什么错误消息呢 ? 消息可以定制吗 ?

    可以的!

    对上传文件的限制有两种配置:

    方式1,struts.multipart.maxSize,(一次请求上传的所有文件的总的大小,以字节为单位,全局起作用

    如果不设置,struts2 的核心包org.apache.struts2下的default.properties文件里有默认的大小设置struts.multipart.maxSize=2097152,即2M.这是struts2文件上传的第一道关,这个配置是一次请求所能上传的文件的总的大小的限制,即如果一次请求上传多个文件,多个文件大小总和不能超过这个设置。

    可以使用常量的方式来修改该限制

    struts.multipart.maxSize=2097152   2兆字节(mb)=2097152字节(b)

    方式2,(一次请求上传的单个文件的大小,以字节为单位,适用于局部action起作用,注意:并不是说这一次请求只能上传一个文件,可以是多个,不要误解,只是不管上传一个还是多个,每个文件的大小最大为这个设置的值)

    可以通过配置 FileUploadInterceptor 拦截器的参数的方式来进行限制,适用于局部action请求的文件上传大小

      maximumSize (optional) - 上传单个文件的最大长度(以字节为单位),默认值为2MB,即人话就是默认一个<input type="file" name="file" />所能上传文件的最大大小为2MB

      allowedTypes (optional) - 允许的上传文件的类型. 多个使用 , 分割(mime类型)

      allowedExtensions (optional) - 允许的上传文件的扩展名. 多个使用 , 分割.

     举例:

    	<!--  全局配置:修改一次请求上传文件的总的最大大小为20M -->
    	<constant name="struts.multipart.maxSize" value="20971520"></constant>
    	<package name="default" extends="struts-default" namespace="/">
    		<interceptors>
    			<interceptor-stack name="atguigustack">
    				<interceptor-ref name="defaultStack">
    					<param name="fileUpload.maximumSize">12582912</param><!--修改一次请求上传的单个文件的大小为 12M -->
    					<!-- <param name="fileUpload.allowedTypes">text/html,text/xml</param> 
    					<param name="fileUpload.allowedExtensions">html,dtd,xml</param> -->
    				</interceptor-ref>
    			</interceptor-stack>
    		</interceptors>
    		<default-interceptor-ref name="atguigustack"></default-interceptor-ref>
    	</package>
    

     详解:原文链接,http://blog.csdn.net/moshenglv/article/details/51991197

    struts2中文件上传的两个限制,

    一个是struts.multipart.maxSize,如果不设置,struts2 的核心包下的default.properties文件里有默认的大小设置struts.multipart.maxSize=2097152,即2M.这是struts2文件上传的第一道关。

    第二道关是inteceptor中的maximumSize. 当真实的文件大小能通过第一道关时.针对不同的action中配置的inteceptor,maximumSize才能发挥相应的拦截作用.

     

    比如struts.multipart.maxSize=50M

    actionA中inteceptorA的maximumSize=30M

    actionB中inteceptorB的maximumSize=10M

     

    struts.multipart.maxSize=50M对于inteceptorA,B都会起到第一关的作用.

    inteceptorA和inteceptorB可以在通过第一关之后,根据自己的业务定制各自针对拦截器起作用的maximumSize

     

    如果真实的文件>50M. 抛出会抛出Request exceeded allowed size limit! Max size allowed is: XXXX but request was: XXXX!异常,他是不能被国际化的,因为这个信息是commons-fileupload组件抛出的,是不支持国际化这信息。

     

    源码可以看struts2.2 org.apache.commons.fileupload.FileUploadBase.java

     

    如果InteceptorA上传的是40M的真实文件

    那么此时拦截器InteceptorA会访问国际化信息:struts.messages.error.file.too.larges对应的值.当且仅当上传文件<=30M的时候,InteceptorA才会成功上传。

     

     

    A:下面是解决struts.multipart.maxSize提示信息不友好的问题.(全局配置)

    当超过50M时.commons-fileupload抛出运行时异常

    struts2会把这个异常看到是action级别的异常.所以会将异常信息

    Request exceeded allowed size limit! Max size allowed is: XXXX but request was: XXXX!写到actionError里面。

    我们需要做的就是在action里覆盖addActionError方法。

     

    @Override
    public void addActionError(String anErrorMessage)
    
    {
         //改从国际化里取值
        if (anErrorMessage.startsWith("Request exceeded allowed size limit!"))
    
        {
            super.addActionError(getText("struts.multipart.maxSize.limit"));  //国际化资源文件的key
        }
    
       else
    
       {
            super.addActionError(anErrorMessage);
       }
    }

     

    国际化资源的配置文件:

    struts.multipart.maxSize.limit=系统上传的文件最大为50M
    struts.messages.error.file.too.larges=新广告批量上传的文件最大为5M
    struts.messages.error.content.type.not.allowed=上传的文件格式目前仅支持xls格式
    struts.messages.error.uploading=上传文件失败
    struts.messages.invalid.token=您已经提交了表单,请不要重复提交。
    fileupload.filenums.exceed=已经有超过5个文件在运行,请稍候再试
    filedownload.rows.exceed=由于您选择的广告组内广告数量太多,请分组下载
    accountNotExist=客户不存在
    invalidTask=无效的任务

     

    B:局部action定制错误消息

     

    定制错误消息. 可以在国际化资源文件中定义如下的消息:

     

    struts.messages.error.uploading - 文件上传出错的消息

     

    struts.messages.error.file.too.large - 文件超过最大值的消息

     

    struts.messages.error.content.type.not.allowed - 文件内容类型不合法的消息

     

    struts.messages.error.file.extension.not.allowed - 文件扩展名不合法的消息

     

    问题: 此种方式定制的消息并不完善. 可以参考 org.apache.struts2 下的 struts-messages.properties, 可以提供更多的定制信息.
    struts.messages.error.uploading=Error uploading: {0}
    struts.messages.error.file.too.large=File {0} is too large to be uploaded. Maximum allowed size is {4} bytes!
    struts.messages.error.content.type.not.allowed=Content-Type not allowed: {0} "{1}" "{2}" {3}
    struts.messages.error.file.extension.not.allowed=File extension not allowed: {0} "{1}" "{2}" {3}

     

     

     

    在页面上显示文件上传的错误消息

    1(A配置的显示),当一次请求上传的所有文件的总的大小超过struts.multipart.maxSize限制的大小时,

    在页面上使用 actionerror:<s:actionerror/>  <!-- 上传文件的总的大小超出,这个会有提示 -->

     

    2(B配置的显示), 如果上传的单个文件出现问题,这个显示错误消息,可以在国际化资源文件中定制

    在页面上使用fielderror: <s:fielderror name="file"></s:fielderror>   name的值是上传的控件的name对应的属性值,也即是后台的File的成员变量名

     

    注意:

    由于inteceptor中途返回,原来页面上输入的其他文本内容也都不见了,也就是说params注入失败。

    因为这个异常是在文件上传之前捕获的,文件未上传,同时params也为注入,所以这时最好到一个jsp文件,提示上传失败,然后重写填写相应信息。

    解决办法:最好跳到一个专门显示错误的页.而不要返回操作页。

    具体如下:

    当上传文件出错时,action会自动找<result name="input" >对应的结果页面

    所以一般配置如下全局结果视图:

    <global-results>
    <result name="input" >/WEB-INF/error.jsp</result>
    </global-results>

    error.jsp是文件上传失败时显示的结果页面

    ---------------------------------当上传的总的文件大小超过设置的值时会出现的tomcat请求问题(注意,这种修改一旦再次重启tomcat修改就会默认还原到没有修改之前的设置,下次还需要重新设置)---------------

    Struts2文件上传 超过大小限制无法跳转至指定input页面问题。浏览器提示连接已重置问题:

    根本原因:

    此问题在用tomcat7/8/9版本会出现。根本原因是Tomcat7/8/9与struts2的兼容性问题:

    当request的最大的字节数(不包括传输编码开销)超过tomcat服务器conf文件server.xml中
    maxSwallowSize的设置值将会被Tomcat终止上传,tomcat会判定是个失败的上传,
    不会把这个request再传送到应用的servlet对象,所以不会有应用的servlet对这个request没有任何响应。
    但是客户端收不到超过上传限制的response,所以客户端会仍然发送它。所以tomcat会发送一个

    连接重置给客户端(浏览器)。

    这样就会出现文件上传 超过大小限制无法跳转至指定input页面,浏览器提示连接已重置的问题

    解决方法:修改maxSwallowSize为-1,

    详细信息可以去tomcat官网查看说明文档,下面是配置信息详细介绍页面:https://tomcat.apache.org/tomcat-9.0-doc/config/http.html
    tomcat服务器conf文件server.xml中maxPostSize与maxSwallowSize的设置值:如果没有指定默认的2097152(2MB)的默认值,小于0表示无限制。

    例子:

    <Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443" maxSwallowSize="-1"/>

    这样就会正常跳转到自己定义好的input错误页面。

    参考链接:

    https://www.cnblogs.com/biehongli/p/6509557.html

  • 相关阅读:
    【今日CV 视觉论文速览】 19 Nov 2018
    【numpy求和】numpy.sum()求和
    【今日CV 视觉论文速览】16 Nov 2018
    【今日CV 视觉论文速览】15 Nov 2018
    poj 2454 Jersey Politics 随机化
    poj 3318 Matrix Multiplication 随机化算法
    hdu 3400 Line belt 三分法
    poj 3301 Texas Trip 三分法
    poj 2976 Dropping tests 0/1分数规划
    poj 3440 Coin Toss 概率问题
  • 原文地址:https://www.cnblogs.com/zxwBj/p/8540334.html
Copyright © 2011-2022 走看看