WebWork 2 : File Upload Interceptor

This page last changed on Nov 30, 2004 by jcarreira.

We can create a nice reusable Interceptor which can hadle file uploads absolutely transparently and Action will not know anything about web-app and just gets its files:

  1. Before further invocation it scans multipart request for files, and if content-type and size is acceptable it puts collected java.io.File instance to invocationContext.parameters Map named according to their <input> names.
  2. In Action we can just declare properties of type File which will be set by parameters Inteceptor, in execute() we can move file with aFile.renameTo(...) to the right place, or just read the it and leave alone.
  3. After invocation it removes all uploaded files via aFile.delete(). (Action should not care for iles uploaded waste disk space)

This Interceptor may be configured to filter files with certain mime type or size, and of course to be applied to any action(s) or even included into stack.

 

<interceptor name="fileUpload" class="neuro.util.xwork.FileUploadInterceptor">
    <param name="allowedTypes">image/jpeg</param>
    <param name="maximumSize">8192</param>
</interceptor>

This removes (duplicate) web-app specific code from Action and gives ua a nice reusable component that handles 90% of all typical file upload tasks. Neat. Also illustrates power of Interceptor concept of XW:XWork/WW:WebWork. Try to do this in Struts. 8)

Things to improve: error handling, reporting & i18n.
//FileUploadInterceptor.java

package neuro.util.xwork;

import com.opensymphony.webwork.ServletActionContext;
import com.opensymphony.webwork.dispatcher.multipart.MultiPartRequestWrapper;
import com.opensymphony.xwork.ActionInvocation;
import com.opensymphony.xwork.interceptor.Interceptor;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.io.File;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Iterator;

/**
 *
 */
public class FileUploadInterceptor implements Interceptor {
    protected static final Log log = LogFactory.getLog(FileUploadInterceptor.class);

    protected String allowedTypes;
    protected String disallowedTypes;
    protected Long maximumSize;

    /**
     */
    public FileUploadInterceptor() {
        if (log.isDebugEnabled()) log.debug("new FileUploadInterceptor()");
    }

    /**
     */
    public void init() {
        if (log.isDebugEnabled()) log.debug("init()");
    }

    /**
     */
    public void destroy() {
        if (log.isDebugEnabled()) log.debug("destroy()");
    }

    /**
     * list of allowed mime-types, optional
     */
    public void setAllowedTypes(String allowedTypes) {
        this.allowedTypes = allowedTypes;
    }

    /**
     * list of diallowed mime-types, optional
     */
    public void setDisallowedTypes(String disallowedTypes) {
        this.disallowedTypes = disallowedTypes;
    }

    /**
     * maximum file Size, optional
     */
    public void setMaximumSize(Long maximumSize) {
        this.maximumSize = maximumSize;
    }

    /**
     *
     * TODO: i18n!
     */
    public String intercept(ActionInvocation invocation) throws Exception {
        if (!(ServletActionContext.getRequest() instanceof MultiPartRequestWrapper)) {
            if (log.isDebugEnabled()) log.debug("bypass " + invocation.getProxy().getNamespace() + "/" + invocation.getProxy().getActionName());
            return invocation.invoke();
        }
        MultiPartRequestWrapper multiWrapper = (MultiPartRequestWrapper) ServletActionContext.getRequest();
        if (multiWrapper.hasErrors()) {
            Collection errors = multiWrapper.getErrors();
            Iterator i = errors.iterator();
            while (i.hasNext()) {
                //how to get to addError() from here?
                log.error((String) i.next());
            }
        }

        Enumeration e = multiWrapper.getFileNames();

        //Bind allowed Files
        while (e.hasMoreElements()) {
            // get the value of this input tag
            String inputName = (String) e.nextElement();
            // get the content type
            String contentType = multiWrapper.getContentType(inputName);
            // get the name of the file from the input tag
            String fileName = multiWrapper.getFilesystemName(inputName);
            // Get a File object for the uploaded File
            File file = multiWrapper.getFile(inputName);

            log.info("file " + inputName + " " + contentType + " " + fileName + " " + file);

            // If it's null the upload failed
            if (file == null) {
                log.error("Error uploading: " + fileName);
            } else {
                if (acceptFile(file, contentType, inputName))
                    invocation.getInvocationContext().getParameters().put(inputName, file);
                // Do additional processing/logging...
            }
        }

        //Invoke Action
        String result = invocation.invoke();

        //Cleanup
        e = multiWrapper.getFileNames();
        while (e.hasMoreElements()) {
            String inputValue = (String) e.nextElement();
            File file = multiWrapper.getFile(inputValue);
            log.info("removing file " + inputValue + " " + file);
            if (file != null && file.isFile()) file.delete();
        }

        return result;
    }

    //overload this method to modify accept behaviour
    //TODO: addErrors?
    //TODO: i18n!
    protected boolean acceptFile(File file, String contentType, String inputName) {
        if (log.isDebugEnabled()) log.debug("checking" + inputName + " " + file.getName() + " " + file.length() + " " + contentType);
        if (maximumSize != null && maximumSize.longValue() < file.length())
            log.error("file is too long:" + inputName + " " + file.getName() + " " + file.length());
        else if (allowedTypes != null && allowedTypes.indexOf(contentType) < 0)
            log.error("Content-Type not allowed:" + inputName + " " + file.getName() + " " + contentType);
        else if (disallowedTypes != null && disallowedTypes.indexOf(contentType) >= 0)
            log.error("Content-Type disallowed:" + inputName + " " + file.getName() + " " + contentType);
        //somehow we need to set error messages here...
        else {
            if (log.isDebugEnabled()) log.debug("accepted");
            return true;
        }
        if (log.isDebugEnabled()) log.debug("not accepted");
        return false;
    }

}

Example Page code:
<form .... enctype="multipart/form-data">
    ....
    select user icon:
    <input type="file" name="picture">
<form>

Example Action code:
/**
     */
    protected File picture;

    public void setPicture(File picture) {
        this.picture = picture;
    }

    /**
     */
    public String execute() {
        if (picture != null && picture.isFile()) {
            final File target = new File("...");
            if (target.exists()) {
                if (log.isDebugEnabled()) log.debug("Removed previous picture version");
                target.delete();
            }
            picture.renameTo(target);
        }
    }

If this Interceptor considered generally useful - may be it will be incorporated into WW2 codebase?

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值