用文件上传了解struts2拦截器的使用

struts2中,拦截器是非常核心的内容,框架默认提供的拦截器,我们可以从struts2-core-**.jar/struts-default.xml中查询到,我们以struts2-core-2.3.15.3.jar为例,打开struts-default.xml,可以看到如下的默认拦截器:

<interceptor name="alias" class="com.opensymphony.xwork2.interceptor.AliasInterceptor"/>
<interceptor name="autowiring" class="com.opensymphony.xwork2.spring.interceptor.ActionAutowiringInterceptor"/>
<interceptor name="chain" class="com.opensymphony.xwork2.interceptor.ChainingInterceptor"/>
<interceptor name="conversionError" class="org.apache.struts2.interceptor.StrutsConversionErrorInterceptor"/>
<interceptor name="cookie" class="org.apache.struts2.interceptor.CookieInterceptor"/>
<interceptor name="cookieProvider" class="org.apache.struts2.interceptor.CookieProviderInterceptor"/>
<interceptor name="clearSession" class="org.apache.struts2.interceptor.ClearSessionInterceptor" />
<interceptor name="createSession" class="org.apache.struts2.interceptor.CreateSessionInterceptor" />
<interceptor name="debugging" class="org.apache.struts2.interceptor.debugging.DebuggingInterceptor" />
<interceptor name="execAndWait" class="org.apache.struts2.interceptor.ExecuteAndWaitInterceptor"/>
<interceptor name="exception" class="com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor"/>
<interceptor name="fileUpload" class="org.apache.struts2.interceptor.FileUploadInterceptor"/>
<interceptor name="i18n" class="com.opensymphony.xwork2.interceptor.I18nInterceptor"/>
<interceptor name="logger" class="com.opensymphony.xwork2.interceptor.LoggingInterceptor"/>
<interceptor name="modelDriven" class="com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor"/>
<interceptor name="scopedModelDriven" class="com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor"/>
<interceptor name="params" class="com.opensymphony.xwork2.interceptor.ParametersInterceptor"/>
<interceptor name="actionMappingParams" class="org.apache.struts2.interceptor.ActionMappingParametersInteceptor"/>
<interceptor name="prepare" class="com.opensymphony.xwork2.interceptor.PrepareInterceptor"/>
<interceptor name="staticParams" class="com.opensymphony.xwork2.interceptor.StaticParametersInterceptor"/>
<interceptor name="scope" class="org.apache.struts2.interceptor.ScopeInterceptor"/>
<interceptor name="servletConfig" class="org.apache.struts2.interceptor.ServletConfigInterceptor"/>
<interceptor name="timer" class="com.opensymphony.xwork2.interceptor.TimerInterceptor"/>
<interceptor name="token" class="org.apache.struts2.interceptor.TokenInterceptor"/>
<interceptor name="tokenSession" class="org.apache.struts2.interceptor.TokenSessionStoreInterceptor"/>
<interceptor name="validation" class="org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor"/>
<interceptor name="workflow" class="com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor"/>
<interceptor name="store" class="org.apache.struts2.interceptor.MessageStoreInterceptor" />
<interceptor name="checkbox" class="org.apache.struts2.interceptor.CheckboxInterceptor" />
<interceptor name="profiling" class="org.apache.struts2.interceptor.ProfilingActivationInterceptor" />
<interceptor name="roles" class="org.apache.struts2.interceptor.RolesInterceptor" />
<interceptor name="annotationWorkflow" class="com.opensymphony.xwork2.interceptor.annotations.AnnotationWorkflowInterceptor" />
<interceptor name="multiselect" class="org.apache.struts2.interceptor.MultiselectInterceptor" />

在struts-default.xml中,除了定义了一些默认的拦截器以外,还有一些默认的拦截器堆。这也提示我们,不光可以在使用时引用一个个的拦截器,也可以使用拦截器堆的方式,一次引用多个拦截器。如:我们在struts.xml配置文件中,没有配置拦截器的情况下,会默认引用以下这个拦截器堆:

<interceptor-stack name="defaultStack">
    <interceptor-ref name="exception"/>
    <interceptor-ref name="alias"/>
    <interceptor-ref name="servletConfig"/>
    <interceptor-ref name="i18n"/>
    <interceptor-ref name="prepare"/>
    <interceptor-ref name="chain"/>
    <interceptor-ref name="scopedModelDriven"/>
    <interceptor-ref name="modelDriven"/>
    <interceptor-ref name="fileUpload"/>
    <interceptor-ref name="checkbox"/>
    <interceptor-ref name="multiselect"/>
    <interceptor-ref name="staticParams"/>
    <interceptor-ref name="actionMappingParams"/>
    <interceptor-ref name="params">
        <param name="excludeParams">dojo\..*,^struts\..*,^session\..*,^request\..*,^application\..*,^servlet(Request|Response)\..*,parameters\...*</param>
    </interceptor-ref>
    <interceptor-ref name="conversionError"/>
    <interceptor-ref name="validation">
        <param name="excludeMethods">input,back,cancel,browse</param>
    </interceptor-ref>
    <interceptor-ref name="workflow">
        <param name="excludeMethods">input,back,cancel,browse</param>
    </interceptor-ref>
    <interceptor-ref name="debugging"/>
</interceptor-stack>

为何我如此肯定,因为在这个文件中,有以下代码,我们在struts.xml中定义一个package元素时,通过也会extends这个struts-default.xml,那么也表示我们引用这个拦截器堆:

<default-interceptor-ref name="defaultStack"/>

好了,抄了一阵struts的源码,现在我们开始今天的事情:文件上传

先来进行单文件上传:

从上面的默认拦截器定义,可以看到,struts2给我们提供了一个现成的拦截器fileUpload,并且已经默认引用了。

我们先来做一些准备工作,做一个文件上传的页面,相信大家都还记得文件上传的页面必须满足以下三个条件:

  1. 表单的提交方式必须是post
  2. 表单的enctype必须为multipart/form-data
  3. 表单中必须提供一个type=file的input元素

以下就是这个表单提交的页面:

    <fieldset>
        <legend>单文件上传</legend>
        <s:form action="single/upload.action" enctype="multipart/form-data" method="post">
            <s:textfield name="name" label="姓名"></s:textfield>
            <s:file name="photo" label="靓照"></s:file>
            <s:submit value="上传"></s:submit>
        </s:form>
    </fieldset>

上面使用的是struts2的标签,当然也可以使用普通的html标签。
上面的表单提交,我们需要一个action动作在来支持,我们先来在struts.xml中配置一下这个action动作

    <package name="upload" extends="struts-default" namespace="/single">
        <action name="upload" class="demo.action.SingleFileUploadAction" method="upload">
            <result>/success.jsp</result>
        </action>
    </package>

那个成功的返回页面success.jsp,没有任何展示,大不了就提示一下成功了

<body>
上传成功了
</body>

现在,我们就只差一个动作类了,我们来写配置文件中配置的demo.action.SingleFileUploadAction这个动作类:

package demo.action;

//省略引入的包

/**
 * 这个测试类,简单起见,使用模型和动作为同一个类的方式
 * @author Minhellic
 *
 */
public class SingleFileUploadAction extends ActionSupport {
    private String name; //对应页面上的name字段
    private File photo;  //对应页面上要上传的文件,必须使用File来接收
    private String photoFileName; //上传的文件名,XXXFileName这样的固定写法
    private String photoContentType; //上传文件的MIME类型, XXXContentType这样的固定写法

    public String upload() throws IOException {
        //普通的属性,可以直接使用
        System.out.println(name);

        /*
         * 完全文件上传
         */
        //1.得到文件上要传的真实路径
        ServletContext sc = ServletActionContext.getServletContext();
        String dirPath = sc.getRealPath("/files");//得到文件的真实保存路径,需要在WebRoot根目录下建一个files目录
        //2.构建目标文件
        File target = new File(dirPath, photoFileName);
        //3.复制文件
        FileUtils.copyFile(photo, target);

        return SUCCESS;
    }

    //省略各个属性的getter和setter
}

以上代码为了简洁,省略了导入的包和各个属性的getter和setter,大家可以自己添加上。
通过上面的代码可以看到,我们需要有一个文件夹来存放上传的文件,本例,我们是在工程的根目录下,用一个files文件夹来存放的,所以,我们在WebRoot下,建一个files文件夹

这里写图片描述

好了,最最粗糙的文件上传完成了,先来看看效果

部署到tomcat,访问这个上传页面:

这里写图片描述

随便选张图片,上传下,果然,上传成功了。我们到tomcat下去查看,在项目的根目录下,发现有一个files目录,打开这个目录,发现确实上传成功了

这里写图片描述

感觉是完成了。再来得瑟一下,这回我选择一个视频,大概有几十M吧,然后

这里写图片描述

我操,这一定不是真的,刚才玩得还好好的。关键是,控制台还没报错,这怎么办?仔细看看这个报错,发现报的是没有input对应的逻辑视图,可明明我们的action里只返回了success,哪来的input,除了这个action,就只有一个可能,就是那个fileUpload拦截器干的。
好吧,既然你说我没有input视图,那我给你一个,在struts.xml中,action的定义里,添加一个result元素

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

再次去尝试去上传一个那个几十M的视频文件,这回倒是不报错了,而是重新又回到了上传页面。
那么问题来了,为什么呢?再上传那张图片是可以成功的,为什么视频就不可以吗?是因为格式不对吗?也没有指定格式呀,按理说应该是可以支持所有格式的,毕竟只是一个上传,又不是解析。
那会不会是大小的问题呢,可能性很大。因为文件上传不成功,无非不是路径问题,文件格式问题,然后就是文件大小问题,前面已经成功过,那么路径是没有问题的,格式的问题可能性很小。那么我们来找找有没有设置文件默认上传大小的地方:
我们知道,struts2加载的时候,不单会加载struts-default.xml,还会加载一个叫default.properties的文件,我们在struts2-core-2.3.15.3.jar包中,找到这个文件,仔细一看,找到了:

struts.multipart.maxSize=2097152

原来这里的文件默认大小这么小,难怪上传不上去,好吧,我们可以在struts.xml中,通过constant元素,来修改这个默认值

<constant name="struts.multipart.maxSize" value="100000000"></constant>

再次部署,试一下,终于成功了。在tomcat中,也找到了这个文件

这里写图片描述

感觉像是应该没有问题了。然而如果把这样的上传页面交付给甲方,相信这项目一定就没希望了。我们想想,这个地方明明在页面上写的是要上传“靓照”的,那也就是说这里我们希望要上传的是一张图片。可用户可不管那么多,他什么都有可能上传,就像我刚才一样,居然会上传一个视频上来。而且,如果用户上传的文件不对,应该给出提示。

那么,下面我们就来限制一下用户上传文件的大小和后缀名,如果用户上传的东西不对,那么给用户一个提示。

文件大小的限制,上面已经介绍了,那么现在,就应该是要给出用户提示了。

为了方便测试,我先把上传大小的限制调小一些,这样基本上随便一个文件都会过大,这样好测试:

<constant name="struts.multipart.maxSize" value="1000"></constant>

struts2提供了一些标签,可以用于展示这些提示信息,比如这次的错误提示,我们就可以在页面上用以下标签展示:

<s:actionerror/>

这样,我们再次上传一个超过大小的文件,则会在页面上出现以下提示:

这里写图片描述

至于要把这个提示展示成中文的,则是可以通过国际化的配置来做,就不再是这篇博客要表现的东西了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值