struts2.x多文件上传(使用注解)

一般网站都会提供文件的上传与下载的功能,尤其是资料管理型网站。刚好在工作中需要用到,就提前学习了一下,并建了一个maven工程做练习。

 

1.      本工程使用maven创建工程,是为了省去包导入细节,其中maven工程的pom.xml文件主要如下:

<!-- struts2 core -->
<dependency>
     <groupId>org.apache.struts</groupId>
     <artifactId>struts2-core</artifactId>
     <version>2.3.16.3</version>
</dependency>
<!-- struts2注解包依赖,实现零配置 -->
<dependency>
     <groupId>org.apache.struts</groupId>
     <artifactId>struts2-convention-plugin</artifactId>
     <version>2.3.16.3</version>
</dependency>

引入struts2-convention-plugin,是为了使用注解,从而实现零配置,实例中将看到这个好处。仔细查看struts2-core的pom.xml,可以发现如下依赖

<!-- File upload -->
<dependency>
     <groupId>commons-fileupload</groupId>
     <artifactId>commons-fileupload</artifactId>
</dependency>
<dependency>
     <groupId>commons-io</groupId>
     <artifactId>commons-io</artifactId>
</dependency>

可见,struts2.x已经默认使用Jakarta的Components-FileUpload组件作为其文件上传的框架。

 

2.       了解表单enctype属性

在表单元素<form>中有一个属性enctype是用来设置上传数据的编码方式,enctype属性规定在发送到服务器之前浏览器应该对表单数据进行何种编码。默认的,表单数据会编码为application/x-www-form-urlencoded。具体enctype有是3个值,含义具体如下

描述

application/x-www-form-urlencoded

在发送前编码所有字符(默认)

该种方式主要用于能输出网页的应用。当传送的内容包含大量的非ASCII字符的文本或二进制数据时,效率比较低

multipart/form-data

不对字符编码。

在使用包含文件上传控件的表单时,必须使用该值。

该方式主要用于文件上传等应用,当利用该种方式上传文件时,首先会把数据转化成二进制数据,然后才会进行上传

text/plain

空格转换为 "+" 加号,但不对特殊字符编码。该方式主要用于电子邮件方面的应用

从上述表中可以看出,只有把属性enctype的值设置为multipart/form-data,就能实现文件上传。

 

3.       struts.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN" "http://struts.apache.org/dtds/struts-2.1.dtd">
 
<struts>
    <!-- 常量配置-->
    <constant name="struts.convention.package.locators" value="web,action" />
    <constant name="struts.convention.package.locators.basePackage" value="com.ljx" />
    <constant name="struts.convention.action.name.lowercase" value="true" />
    <constant name="struts.convention.action.name.separator" value="-" />
    <constant name="struts.date.format" value="yyyy-MM-dd HH:mm:ss" />
    <!--<constant name="struts.convention.default.parent.package" value="ljx-default" />-->
    <constant name="struts.convention.result.path" value="/WEB-INF/views" />
    <constant name="struts.convention.action.includeJars" value=".*/struts*.*jar(!/)?" />
   
    <!-- 存放上传文件的临时位置 -->
    <constant name="struts.multipart.maxSize" value="10701096"/>
    <constant name="struts.multipart.saveDir" value="D:/Download/tmp"/>
 
    <!-- 调试模式 -->
   <constant name="struts.devMode" value="false" />
    <constant name="struts.convention.classes.reload" value="true" />
   
    <!-- 其余的零配置 -->
 
</struts>

使用struts2-convention-plugin,只需要再struts.xml中配置一些常量值,其余的元素<package>,<interceptor>等都不需要在这里配置。

 

由简到难,接下来先介绍单文件上传

4.       单文件上传

前端jsp文件如下

<body background="${images}/bonjour-bg.jpg">
    <form name="file-upload-form" action="${ctx}/file/upload.action" method="post" enctype="multipart/form-data">
        <br/>
        选择上传的文件:
        <input type="file" name="upload"/><br/><br/>
        <input type="submit" value="提交"/>
    </form>
</body>

备注,上传文件,form提交方式不能为Get,而应该为post。使用原生的html<input type=”file”>。题外话,因为struts-tag标签有过安全漏洞,所以组里开发严禁使用,楼主小生,不是特别理解xss漏洞原理,特别摘引了一篇大作(http://huaidan.org/archives/3433.html),留作后续研读。当然,这里只是作为输入,所以应该使用<s:file>没有太大问题的。

后台Action如下:

/**
 * 文件上传
 *
 * @author linjx
 * @date 2014年7月17日  下午5:13:12
 * @version: 1.0.0
 */
@ParentPackage(value = "struts-default")
public class FileUploadAction {
   
    /**
     * 上传的文件
     */
    private File upload;
   
    /**
     * 文件名称
     */
    private String uploadFileName;
   
    /**
     * 文件类型
     */
    private String uploadContentType;
   
    @Action(value = "/file/upload")
    public String saveUploadFile() {
        //String realpath = ServletActionContext.getServletContext().getRealPath("/images"); //需要依赖javax.servlet.jar
        String realpath = "D:/download/download";  //指定存储位置
        System.out.println("realpath: " + realpath);
        if (CommonUtils.isNotNull(upload)) {
            File saveFile = new File(new File(realpath), uploadFileName);
            if (!saveFile.getParentFile().exists()) {
                saveFile.getParentFile().mkdirs();
            }
            try {
                org.apache.commons.io.FileUtils.copyFile(upload, saveFile);
            } catch (IOException e) {
                e.printStackTrace();
            }
            ActionContext.getContext().put("message", "文件上传成功");
        }
        return ActionSupport.SUCCESS;
    }
 
    public File getUpload() {
        return upload;
    }
 
    public void setUpload(File upload) {
        this.upload = upload;
    }
 
    public String getUploadFileName() {
        return uploadFileName;
    }
 
    public void setUploadFileName(String uploadFileName) {
        this.uploadFileName = uploadFileName;
    }
 
    public String getUploadContentType() {
        return uploadContentType;
    }
 
    public void setUploadContentType(String uploadContentType) {
        this.uploadContentType = uploadContentType;
    }
   
}

通过@ParenPackage和@Action注解,实现类似

<package name="file" extends="struts-default" namespace="/file ">
     <action name=" saveUploadFile " class="……. FileUploadAction ">
           <result>../upload.jsp</result>
           <result name="input">../file-upload.jsp</result>
     </action>
</package>

显然,注解的优势就是简练。

结果返回upload.jsp代码如下:

<body background="${images}/bonjour-bg.jpg">
        <br/><br/>
        <h2>${message}</h2>
        <p>${uploadFileName}</p>
        <hr />
</body>

具体运行结果如下:


选定上传文件,点击提交,后台报错:

WARNING: Request exceeded size limit!
org.apache.commons.fileupload.FileUploadBase$SizeLimitExceededException: the request was rejected because its size (29488656) exceeds the configured maximum (10701096)

非常直观,是因为上传文件超过在struts.xml文件中设定的上传文件最大值。我们选择一个小文件重新上传,并观察文件上传的流程,打调试断点于FileUtils.copyFile(upload, saveFile)行上,如下


可以发现,程序运行到这一步

D:/Download/tmp路径下会有个临时文件,

继续运行,则该临时文件会主动清除;文件成功上传到D:/Download/download文件夹下,文件名保持不变。

跳转到upload.action,显示如下

 


5.       多文件上传

       了解了单文件上传流程,就可以开始开发多文件上传。其实,没有太大的差别,只是多文件上传在表单提交时,由文件列表接收多个文件,表单上传后,会将多个文件缓存在临时路径,从操作上看,我们只需要将文件列表拷贝到相应的路径就行了。

具体代码如下:

上传jsp

<body background="${images}/bonjour-bg.jpg">
        <form name="file-upload-form" action="${ctx}/file/multi-upload.action" method="post"
            enctype="multipart/form-data">
            <br/>
            选择上传的文件:
            <br/>
            <input type="file" name="upload"/><br/>
            <input type="file" name="upload"/><br/>
            <input type="file" name="upload"/><br/>
            <input type="submit" value="提交"/>
        </form>
</body>

返回upload.jsp不变

Action代码如下:

/**
 * @author linjx
 * @date 2014-7-17
 * @version 1.0.0
 */
@ParentPackage(value = "struts-default")
public class MultiFileUploadAction {
   
    /**
     * 上传的文件
     */
    private List<File> upload;
   
    /**
     * 文件名称
     */
    private List<String> uploadFileName;
   
    /**
     * 文件类型
     */
    private List<String> uploadContentType;
   
    @Action(value = "/file/multi-upload", //view还是指向upload.jsp
            results = {@Result(name=ActionSupport.SUCCESS, location="/WEB-INF/views/file/upload.jsp")})
    public String saveUploadFile() {
        //需要javax.servlet.jar
        //String realpath = ServletActionContext.getServletContext().getRealPath("/images");
        String realpath = "D:/Download/download";
        System.out.println("realpath: " + realpath);
        if (CommonUtils.isNotNull(upload)) {
            if (CollectionUtils.isNotEmpty(upload)) {
                for (int i = 0; i < upload.size(); i ++) {
                    File saveFile = new File(realpath, uploadFileName.get(i));
                    if (!saveFile.getParentFile().exists()) {
                        saveFile.getParentFile().mkdirs();
                    }
                    try {
                        FileUtils.copyFile(upload.get(i), saveFile);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            ActionContext.getContext().put("message", "文件上传成功");
        }
        return ActionSupport.SUCCESS;
    }
 
    public List<File> getUpload() {
        return upload;
    }
 
    public void setUpload(List<File> upload) {
        this.upload = upload;
    }
 
    public List<String> getUploadFileName() {
        return uploadFileName;
    }
 
    public void setUploadFileName(List<String> uploadFileName) {
        this.uploadFileName = uploadFileName;
    }
 
    public List<String> getUploadContentType() {
        return uploadContentType;
    }
 
    public void setUploadContentType(List<String> uploadContentType) {
        this.uploadContentType = uploadContentType;
    }
}

上传结果如下,选定上传文件:


成功界面:


查看download路径下文件有:


就此,完成多文件上传。

备注:还可以通过fileUpload拦截器对上传的文件进行过滤。

@InterceptorRef(value="fileUpload",params= {"allowedTypes", "image/bmp, /image/gif"})这个注解只限于类级别,如果加上这个过滤器,png格式的图片上传将被过滤掉,并且后台并不会报错。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值