欢迎使用CSDN-markdown编辑器

基于浏览器的文件上传,特别是对于通过标签来实现上传的情况, 存在着严重的性能问题,因为用户提交了文件之后,在浏览器把文件上传到服务器的过程中,界面看上去似乎是静止的,如果是小文件还好些,如果不幸需要上传的是几兆、几十兆甚至上百兆的文件,我相信那是一种非常痛苦的体验,我们中间的很多人应该都有过此种不堪的经历。
我们为了改善用户界面,通常会在处理量大或者是网络速度较慢的时候,给用户显示一个处理进度,让用户心理有底,增强用户等待结果的耐心,以改善用户体验。
  现在我就针对这个问题给出一个解决方案,我们将实现一个具有监控能力的WEB上传的程序——它不仅把文件上传到服务器,而且”实时地”监视文件上传的实际过程。
解决方案的基本思路是这样的:
  在Form提交上传文件同时,使用AJAX周期性地从Action轮询上传状态信息
  然后,根据此信息更新进度条和相关文字,及时反映文件传输状态

实现一个文件监听类,实现对文件上传进度的实时监听,并将监听结果存放到session中,公前台界面读取。
[java] view plain copy print?
/*
* Copyright (c) 2012-2032 Accounting Center of China Aviation(ACCA).
* All Rights Reserved.
*/
package com.wallet.myWallet.listener;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.apache.commons.fileupload.ProgressListener;

import com.wallet.myWallet.entity.State;

/**
*
*
* @author zhouhua, 2014-7-16
*/
public class FileUploadListener implements ProgressListener {

// 声明一个HttpSession,目的是把State对象放到这个HttpSession中  
private HttpSession session;  

// 此构造函数由MyJakartaMultiPartRequest.java类parseRequest()方法调用  
public FileUploadListener(HttpServletRequest request) {  
    super();  
    session = request.getSession();  
}  

public void update(long uploadByte, long fileSizeByte, int fileIndex) {  
    if (fileSizeByte == -1) {  
        // 如果上传的大小为-1则上传已经完成  
        System.out.println("上传文件结束!");  
    } else {  
        if (session.getAttribute("uploadState") == null) {  
            // 如果为空就new一个State对象并设置里面的文本内容  
            State state = new State();  
            state.setState(uploadByte, fileSizeByte, (fileIndex - 1));  
            session.setAttribute("uploadState", state);  
        } else {  
            // 如果session中有uploadState对象就取出来,然后设置里面文本内容  
            State state = (State) session.getAttribute("uploadState");  
            state.setState(uploadByte, fileSizeByte, (fileIndex - 1));  
        }  
    }  
}  

}

接下来是一个文件状态类:
[java] view plain copy print?
/*
* Copyright (c) 2012-2032 Accounting Center of China Aviation(ACCA).
* All Rights Reserved.
*/
package com.wallet.myWallet.entity;

import java.text.NumberFormat;
import java.text.SimpleDateFormat;

/**
*
*
* @author zhouhua, 2014-7-16
*/
public class State {

private long uploadByte; // 已经上传的字节数,单位:字节  
private long fileSizeByte; // 所有文件的总长度,单位:字节  
private int fileIndex; // 正在上传第几个文件  
private long startTime; // 开始上传的时间,用于计算上传速度等  
private int percent; // 上传百分比  
private long speed;  
private long time;   
private static final SimpleDateFormat SIMPLEFORMAT = new SimpleDateFormat("HH:mm:ss");  

public State() {  
    startTime = System.currentTimeMillis();  
    percent = 0;  
    speed=0L;  
}  

// 从State状态类中取得状态的字符串,用字符串的形式拼成XML文件内容  
public synchronized String getStateString() {  
    StringBuilder sb = new StringBuilder("<info>");  
    sb.append("<uploadByte>" + NumberFormat.getInstance().format(uploadByte/(1024*1024)) + "</uploadByte>");  
    sb.append("<fileSizeByte>" + NumberFormat.getInstance().format(fileSizeByte/(1024*1024))  
            + "</fileSizeByte>");  
    sb.append("<speed>" + NumberFormat.getInstance().format((speed/(1024*1024))/time) + "</speed>");  
    sb.append("<fileIndex>" + fileIndex + "</fileIndex>");  
    sb.append("<percent>" + percent + "</percent>");  
    sb.append("<startTime>" + SIMPLEFORMAT.format(startTime) + "</startTime>");  
    sb.append("</info>");  
    return sb.toString();  
}  

public synchronized void setState(long uploadByte, long fileSizeByte, int fileIndex) {  
    this.uploadByte = uploadByte;  
    this.fileSizeByte = fileSizeByte;  
    this.fileIndex = fileIndex;  
    this.speed=uploadByte-speed;  
    this.time=(System.currentTimeMillis()-startTime)/1000;  
    if ((Long.valueOf(uploadByte) * 100 / Long.valueOf(fileSizeByte) <= 100)) {  
        // 生成当前上传进度的公式,加入判断条件的含义在于不需要重复计算  
        percent = (int) (Long.valueOf(uploadByte) * 100 / Long.valueOf(fileSizeByte));  
    }  
}  

}

如果想通过Struts2监听文件上传的进度,我们需要自己实现Struts2的MultiPartRequest类并将自己的文件上传监听类注入,实现类如下:
[java] view plain copy print?
/*
* Copyright (c) 2012-2032 Accounting Center of China Aviation(ACCA).
* All Rights Reserved.
*/
package com.wallet.myWallet.listener;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadBase;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.RequestContext;
import org.apache.commons.fileupload.disk.DiskFileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.struts2.StrutsConstants;
import org.apache.struts2.dispatcher.multipart.MultiPartRequest;

import com.opensymphony.xwork2.LocaleProvider;
import com.opensymphony.xwork2.inject.Inject;
import com.opensymphony.xwork2.util.LocalizedTextUtil;
import com.opensymphony.xwork2.util.logging.Logger;
import com.opensymphony.xwork2.util.logging.LoggerFactory;

/**
*
*
* @author zhouhua, 2014-7-16
*/
public class MyJakartaMultiPartRequest implements MultiPartRequest {

static final Logger LOG = LoggerFactory.getLogger(MyJakartaMultiPartRequest.class);  
// maps parameter name -> List of FileItem objects  
protected Map<String, List<FileItem>> files = new HashMap<String, List<FileItem>>();  
// maps parameter name -> List of param values  
protected Map<String, List<String>> params = new HashMap<String, List<String>>();  
// any errors while processing this request  
protected List<String> errors = new ArrayList<String>();  
protected long maxSize;  
private Locale defaultLocale = Locale.ENGLISH;  

@Inject(StrutsConstants.STRUTS_MULTIPART_MAXSIZE)  
public void setMaxSize(String maxSize) {  
    this.maxSize = Long.parseLong(maxSize);  
}  

@Inject  
public void setLocaleProvider(LocaleProvider provider) {  
    defaultLocale = provider.getLocale();  
}  

/** 
 * Creates a new request wrapper to handle multi-part data using methods adapted from Jason 
 * Pell's multipart classes (see class description). 
 *  
 * @param saveDir the directory to save off the file 
 * @param request the request containing the multipart 
 * @throws java.io.IOException is thrown if encoding fails. 
 */  
public void parse(HttpServletRequest request, String saveDir) throws IOException {  
    try {  
        setLocale(request);  
        processUpload(request, saveDir);  
    } catch (FileUploadBase.SizeLimitExceededException e) {  
        if (LOG.isWarnEnabled()) {  
            LOG.warn("Request exceeded size limit!", e);  
        }  
        String errorMessage = buildErrorMessage(e,  
                new Object[] { e.getPermittedSize(), e.getActualSize() });  
        if (!errors.contains(errorMessage)) {  
            errors.add(errorMessage);  
        }  
    } catch (Exception e) {  
        if (LOG.isWarnEnabled()) {  
            LOG.warn("Unable to parse request", e);  
        }  
        String errorMessage = buildErrorMessage(e, new Object[] {});  
        if (!errors.contains(errorMessage)) {  
            errors.add(errorMessage);  
        }  
    }  
}  

protected void setLocale(HttpServletRequest request) {  
    if (defaultLocale == null) {  
        defaultLocale = request.getLocale();  
    }  
}  

protected String buildErrorMessage(Throwable e, Object[] args) {  
    String errorKey = "struts.messages.upload.error." + e.getClass().getSimpleName();  
    if (LOG.isDebugEnabled()) {  
        LOG.debug("Preparing error message for key: [#0]", errorKey);  
    }  
    return LocalizedTextUtil.findText(this.getClass(), errorKey, defaultLocale, e.getMessage(),  
            args);  
}  

private void processUpload(HttpServletRequest request, String saveDir)  
    throws FileUploadException, UnsupportedEncodingException {  
    for (FileItem item : parseRequest(request, saveDir)) {  
        if (LOG.isDebugEnabled()) {  
            LOG.debug("Found item " + item.getFieldName());  
        }  
        if (item.isFormField()) {  
            processNormalFormField(item, request.getCharacterEncoding());  
        } else {  
            processFileField(item);  
        }  
    }  
}  

private void processFileField(FileItem item) {  
    if (LOG.isDebugEnabled()) {  
        LOG.debug("Item is a file upload");  
    }  
    // Skip file uploads that don't have a file name - meaning that no file was selected.  
    if (item.getName() == null || item.getName().trim().length() < 1) {  
        LOG.debug("No file has been uploaded for the field: " + item.getFieldName());  
        return;  
    }  
    List<FileItem> values;  
    if (files.get(item.getFieldName()) != null) {  
        values = files.get(item.getFieldName());  
    } else {  
        values = new ArrayList<FileItem>();  
    }  
    values.add(item);  
    files.put(item.getFieldName(), values);  
}  

private void processNormalFormField(FileItem item, String charset)  
    throws UnsupportedEncodingException {  
    if (LOG.isDebugEnabled()) {  
        LOG.debug("Item is a normal form field");  
    }  
    List<String> values;  
    if (params.get(item.getFieldName()) != null) {  
        values = params.get(item.getFieldName());  
    } else {  
        values = new ArrayList<String>();  
    }  
    // note: see http://jira.opensymphony.com/browse/WW-633  
    // basically, in some cases the charset may be null, so  
    // we're just going to try to "other" method (no idea if this  
    // will work)  
    if (charset != null) {  
        values.add(item.getString(charset));  
    } else {  
        values.add(item.getString());  
    }  
    params.put(item.getFieldName(), values);  
    item.delete();  
}  

private List parseRequest(HttpServletRequest servletRequest, String saveDir)
throws FileUploadException {
DiskFileItemFactory fac = createDiskFileItemFactory(saveDir);
ServletFileUpload upload = new ServletFileUpload(fac);
upload.setProgressListener(new FileUploadListener(servletRequest));// 设置上传进度的监听
upload.setSizeMax(maxSize);
return upload.parseRequest(createRequestContext(servletRequest));
}

private DiskFileItemFactory createDiskFileItemFactory(String saveDir) {  
    DiskFileItemFactory fac = new DiskFileItemFactory();  
    // Make sure that the data is written to file  
    fac.setSizeThreshold(0);  
    if (saveDir != null) {  
        fac.setRepository(new File(saveDir));  
    }  
    return fac;  
}  

/* 
 * (non-Javadoc) 
 *  
 * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#getFileParameterNames() 
 */  
public Enumeration<String> getFileParameterNames() {  
    return Collections.enumeration(files.keySet());  
}  

/* 
 * (non-Javadoc) 
 *  
 * @see 
 * org.apache.struts2.dispatcher.multipart.MultiPartRequest#getContentType(java.lang.String) 
 */  
public String[] getContentType(String fieldName) {  
    List<FileItem> items = files.get(fieldName);  
    if (items == null) {  
        return null;  
    }  
    List<String> contentTypes = new ArrayList<String>(items.size());  
    for (FileItem fileItem : items) {  
        contentTypes.add(fileItem.getContentType());  
    }  
    return contentTypes.toArray(new String[contentTypes.size()]);  
}  

/* 
 * (non-Javadoc) 
 *  
 * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#getFile(java.lang.String) 
 */  
public File[] getFile(String fieldName) {  
    List<FileItem> items = files.get(fieldName);  
    if (items == null) {  
        return null;  
    }  
    List<File> fileList = new ArrayList<File>(items.size());  
    for (FileItem fileItem : items) {  
        File storeLocation = ((DiskFileItem) fileItem).getStoreLocation();  
        if (fileItem.isInMemory() && storeLocation != null && !storeLocation.exists()) {  
            try {  
                storeLocation.createNewFile();  
            } catch (IOException e) {  
                if (LOG.isErrorEnabled()) {  
                    LOG.error(  
                            "Cannot write uploaded empty file to disk: "  
                                    + storeLocation.getAbsolutePath(), e);  
                }  
            }  
        }  
        fileList.add(storeLocation);  
    }  
    return fileList.toArray(new File[fileList.size()]);  
}  

/* 
 * (non-Javadoc) 
 *  
 * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#getFileNames(java.lang.String) 
 */  
public String[] getFileNames(String fieldName) {  
    List<FileItem> items = files.get(fieldName);  
    if (items == null) {  
        return null;  
    }  
    List<String> fileNames = new ArrayList<String>(items.size());  
    for (FileItem fileItem : items) {  
        fileNames.add(getCanonicalName(fileItem.getName()));  
    }  
    return fileNames.toArray(new String[fileNames.size()]);  
}  

/* 
 * (non-Javadoc) 
 *  
 * @see 
 * org.apache.struts2.dispatcher.multipart.MultiPartRequest#getFilesystemName(java.lang.String) 
 */  
public String[] getFilesystemName(String fieldName) {  
    List<FileItem> items = files.get(fieldName);  
    if (items == null) {  
        return null;  
    }  
    List<String> fileNames = new ArrayList<String>(items.size());  
    for (FileItem fileItem : items) {  
        fileNames.add(((DiskFileItem) fileItem).getStoreLocation().getName());  
    }  
    return fileNames.toArray(new String[fileNames.size()]);  
}  

/* 
 * (non-Javadoc) 
 *  
 * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#getParameter(java.lang.String) 
 */  
public String getParameter(String name) {  
    List<String> v = params.get(name);  
    if (v != null && v.size() > 0) {  
        return v.get(0);  
    }  
    return null;  
}  

/* 
 * (non-Javadoc) 
 *  
 * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#getParameterNames() 
 */  
public Enumeration<String> getParameterNames() {  
    return Collections.enumeration(params.keySet());  
}  

/* 
 * (non-Javadoc) 
 *  
 * @see 
 * org.apache.struts2.dispatcher.multipart.MultiPartRequest#getParameterValues(java.lang.String) 
 */  
public String[] getParameterValues(String name) {  
    List<String> v = params.get(name);  
    if (v != null && v.size() > 0) {  
        return v.toArray(new String[v.size()]);  
    }  
    return null;  
}  

/* 
 * (non-Javadoc) 
 *  
 * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#getErrors() 
 */  
public List<String> getErrors() {  
    return errors;  
}  

/** 
 * Returns the canonical name of the given file. 
 *  
 * @param filename the given file 
 * @return the canonical name of the given file 
 */  
private String getCanonicalName(String filename) {  
    int forwardSlash = filename.lastIndexOf("/");  
    int backwardSlash = filename.lastIndexOf("\\");  
    if (forwardSlash != -1 && forwardSlash > backwardSlash) {  
        filename = filename.substring(forwardSlash + 1, filename.length());  
    } else if (backwardSlash != -1 && backwardSlash >= forwardSlash) {  
        filename = filename.substring(backwardSlash + 1, filename.length());  
    }  
    return filename;  
}  

/** 
 * Creates a RequestContext needed by Jakarta Commons Upload. 
 *  
 * @param req the request. 
 * @return a new request context. 
 */  
private RequestContext createRequestContext(final HttpServletRequest req) {  
    return new RequestContext() {  
        public String getCharacterEncoding() {  
            return req.getCharacterEncoding();  
        }  

        public String getContentType() {  
            return req.getContentType();  
        }  

        public int getContentLength() {  
            return req.getContentLength();  
        }  

        public InputStream getInputStream() throws IOException {  
            InputStream in = req.getInputStream();  
            if (in == null) {  
                throw new IOException("Missing content in the request");  
            }  
            return req.getInputStream();  
        }  
    };  
}  

/* 
 * (non-Javadoc) 
 *  
 * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#cleanUp() 
 */  
public void cleanUp() {  
    Set<String> names = files.keySet();  
    for (String name : names) {  
        List<FileItem> items = files.get(name);  
        for (FileItem item : items) {  
            if (LOG.isDebugEnabled()) {  
                String msg = LocalizedTextUtil.findText(this.getClass(),  
                        "struts.messages.removing.file", Locale.ENGLISH, "no.message.found",  
                        new Object[] { name, item });  
                LOG.debug(msg);  
            }  
            if (!item.isInMemory()) {  
                item.delete();  
            }  
        }  
    }  
}  

}

自己的类实现MultiPartRequest后,需要在Struts.xml文件中进行装配:
[html] view plain copy print?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值