struts2上传文件显示进度条实例---有图有代码,一看就会

来源:互联网 发布:耶鲁大学法学院知乎 编辑:程序博客网 时间:2024/06/06 07:18

啰嗦两句:显示进度条其实没那么困难

有时候,不知道是环境问题还是人品问题,遇到的bug总是莫名其妙的。可是说到底还是某个知识点不太熟练。这次吐槽一下前端jquery的submit方法。下午的时候测试提交能顺利完成任务,可是到了十一点多的时候就不行了。我知道,程序员十大谎言之一就是:我真的没改这部分代码。好吧,既然不太清除bug到底是怎么出现的,那么就换一种提交方法吧。
所以直接把button类型改成submit,再设置它的click事件,让表单自己提交好了。知识点的盲区就在这时候出现了。由于要轮询后台文件的上传进度信息,不得不一边提交file一遍ajax获取进度。实在是不太清楚setinterval这个方法是异步还是同步,会不会阻塞submit(又和上一段中提到的文件submit不成功混在一起,就测试了好久)。在这个地方也停留了好久。。。
最后,项目还残存的问题就是:明明是每隔500ms向后台请求的进度信息,但是实际上后台并不能够在这段时间内返回对应的信息。亟待优化!
效果图如下:
这里写图片描述

获取文件上传信息的基本步骤:经测试有效

上传文件时如何获取上传进度信息?

从网上查一下资料就可以知道struts2对文件上传的request请求做了封装,也就是说在调用上传文件的action时就已经上传temp完成了。
那么既然这样,我们就可以重写struts2封装request的类:org.apache.struts2.dispatcher.multipart.JakartaMultiPartRequest;
由于这个类的许多方法都是private的,那么也就是说我们是无法通过extends来重写父类的一些方法的。怎么办呢?
暴力一点!
直接自定义一个JakartaMultiPartRequest类型的类,把父类的方法全部copy过来,然后在struts.xml中配置:

<struts>    <bean type="org.apache.struts2.dispatcher.multipart.MultiPartRequest"          name="myRequestParser" class="listener.MultiPartRequest"          scope="default" optional="true" />    <!-- 注意struts2.3.15.1以前版本这里为struts.multipart.handler, struts2.3.15.1(包含2.3.15.1)这里为struts.multipart.parser-->    <constant name="struts.multipart.handler" value="myRequestParser"/>    <!--action-->    ....    </struts>

接下来我们实现上述配置文件中的MultiPartRequest类:
通过intellij的反编译插件,我们decode JakartaMultiPartRequest这个类:源码如下—-大量代码来袭,直接copy这部分吧 不用细看

/* * $Id: JakartaMultiPartRequest.java 1384107 2012-09-12 20:14:23Z lukaszlenart $ * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements.  See the NOTICE file * distributed with this work for additional information * regarding copyright ownership.  The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License.  You may obtain a copy of the License at * *  http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied.  See the License for the * specific language governing permissions and limitations * under the License. */package org.apache.struts2.dispatcher.multipart;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;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 javax.servlet.http.HttpServletRequest;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;/** * Multipart form data request adapter for Jakarta Commons Fileupload package. */public class JakartaMultiPartRequest implements MultiPartRequest {    static final Logger LOG = LoggerFactory.getLogger(JakartaMultiPartRequest.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<FileItem> parseRequest(HttpServletRequest servletRequest, String saveDir) throws FileUploadException {        DiskFileItemFactory fac = createDiskFileItemFactory(saveDir);        ServletFileUpload upload = new ServletFileUpload(fac);        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();                }            }        }    }}

好的,我们把上面这部分代码copy到我们自定义的public class MultiPartRequest extends JakartaMultiPartRequest {}中
复制粘贴完了之后,我们要ctrl f找到parseRequest方法。在这里,我们要设置文件上传进度监听器

  /**     * 自定义的parseRequest方法     * @param servletRequest     * @param saveDir     * @return     * @throws FileUploadException     */    private List<FileItem> parseRequest(HttpServletRequest servletRequest, String saveDir) throws FileUploadException {        System.out.println("调用parseRequest方法");        UploadProgressListener listener = new UploadProgressListener(servletRequest);        DiskFileItemFactory fac = createDiskFileItemFactory(saveDir);        ServletFileUpload upload = new ServletFileUpload(fac);        upload.setSizeMax(maxSize);        upload.setProgressListener(listener);        System.out.println("设置监听器成功");        return upload.parseRequest(createRequestContext(servletRequest));    }

在上面这个代码片段中可以看到:我们new了一个监听器UploadProgressListener 的实例,然后调用了ServletFileUpload .setProgressListener(listener)方法。也就是说:这里的监听器与我们以前写过的request,session等等监听器不同,不需要在web.xml中配置。这里只需要一行代码即可解决。

那么我们就来实现这个监听器吧!

这个监听器需要实org.apache.commons.fileupload.ProgressListener这个接口:我们直接implement一下。
在update方法中我们可以获取到已上传的文件长度,上传的文件的总长度,当前上传第几个文件。(当你上传一个文件的时候,打印日志就会发现这里会输出2。个人猜测是先上传到temp然后再上传到指定路径…)
我们在update方法中设置了文件上传状态实体类的实例,并且保存到session。这一步就是能让前端使用ajax访问到文件当前的上传进度信息

package listener;import entity.FileUploadProgress;import org.apache.commons.fileupload.ProgressListener;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpSession;/** * Created by zipple on 2017/10/13. * 监听文件上传情况 * 实现org.apache.commons.fileupload.ProgressListener接口 */public class UploadProgressListener implements ProgressListener {    private HttpSession session;//创建监听器实例的时候获取session    //在自定义的MultiPartRequest 类中 创建此监听器的实例    public UploadProgressListener(HttpServletRequest request) {        session = request.getSession();        FileUploadProgress fileUploadProgress = new FileUploadProgress();        fileUploadProgress.setFlag(false);        session.setAttribute("fileUploadProgress", fileUploadProgress);    }    @Override    public void update(long readBytes, long totalBytes, int currentItem) {        //实现文件上传的核心方法        Object attribute = session.getAttribute("fileUploadProgress");//        System.out.println("当前已读取:"+readBytes+" 总长度:"+totalBytes+" 正在保存:"+currentItem);        FileUploadProgress fileUploadProgress;        if(null == attribute){            fileUploadProgress = new FileUploadProgress();            fileUploadProgress.setFlag(false);            System.out.println("uploadListener文件上传的开始时间:"+fileUploadProgress.getStartTime());            session.setAttribute("fileUploadProgress", fileUploadProgress);        }else{            fileUploadProgress = (FileUploadProgress)attribute;        }        fileUploadProgress.setCurrentLength(readBytes);        fileUploadProgress.setTotalLength(totalBytes);        if(readBytes==totalBytes){            fileUploadProgress.setFlag(true);        }else{            fileUploadProgress.setFlag(false);        }        session.setAttribute("fileUploadProgress", fileUploadProgress);    }}

文件上传状态实体类代码:

package entity;/** * Created by zipple on 2017/10/14. * 上传文件进度信息实体类 */public class FileUploadProgress {    private long startTime = System.currentTimeMillis();//开始时间    private long totalLength=1;//文件上传的总长度    private long currentLength=0;//当前文件上传的长度    private boolean flag;//是否上传完成    public long getTotalLength() {        return totalLength;    }    public void setTotalLength(long totalLength) {        this.totalLength = totalLength;    }    public long getCurrentLength() {        return currentLength;    }    public void setCurrentLength(long currentLength) {        this.currentLength = currentLength;    }    public boolean isFlag() {        return flag;    }    public void setFlag(boolean flag) {        this.flag = flag;    }    public long getStartTime() {        return startTime;    }    public void setStartTime(long startTime) {        this.startTime = startTime;    }    public FileUploadProgress(){        super();    }}

前端获取后台文件上传的进度信息

好的,前面已经做完了所有的基本工作了。万事俱备,我们最后只需要实现对应的查询action即可。在这个地方我也要记录一个bug。在使用ajax访问这个action的时候,一直报错。当然,我在前面的博客中也吐槽过了,这个报错信息一点用没有。我又找了好久。后来发现jsonData只是单纯的定义了map对象,并没有new出它的实例,所以空指针异常了!!!
这里我们使用的是返回json数据。(需要struts2-json-plugin-2.3.16.jar

package action;import com.opensymphony.xwork2.Action;import entity.FileUploadProgress;import org.apache.struts2.ServletActionContext;import util.DataUtil;import java.util.HashMap;import java.util.Map;/** * Created by zipple on 2017/10/15. * 获取文件进度信息 */public class ProgressAction implements Action {    private Map<String,Object> jsonData;    @Override    public String execute() throws Exception {        System.out.println("获取上传文件进度信息");        jsonData = new HashMap<>();//初始化jsonData!!!!        FileUploadProgress p;        Object attribute = ServletActionContext.getRequest().getSession().getAttribute("fileUploadProgress");        if(null == attribute){            System.out.println("session中没有fileupload信息");            jsonData.put("completed", false);            jsonData.put("isStarted", false);            setJsonData(jsonData);            return SUCCESS;        }else{            System.out.println("session中有fileupload信息");            p = (FileUploadProgress)attribute;        }        System.out.println("action中获取到的文件上传的开始时间:"+p.getStartTime());        System.out.println("action运行到这里的时间:"+System.currentTimeMillis());        long time = (System.currentTimeMillis() - p.getStartTime())/ 1000 + 1; //已传输的时间 单位:s        System.out.println("截至目前上传时间:"+time);        double v = ((double)p.getCurrentLength()) / (double)time; // b/s        System.out.println("传输速度:"+v);        System.out.println("pAction:当前上传--"+p.getCurrentLength());        jsonData.put("percent", DataUtil.percent(p.getCurrentLength(),p.getTotalLength()));        jsonData.put("remain", (int)(p.getTotalLength()/v-time));        jsonData.put("isStarted", true);        jsonData.put("completed", p.isFlag());        if (p.isFlag()){            System.out.println("已完成,重置fileUploadProgress");            ServletActionContext.getRequest().getSession().removeAttribute("fileUploadProgress");        }        setJsonData(jsonData);        return SUCCESS;    }    public Map<String,Object> getJsonData() {        return jsonData;    }    public void setJsonData(Map<String,Object> jsonData) {        this.jsonData = jsonData;    }}

返回json数据的struts.xml配置如下:

 <package name="json" extends="struts-default,json-default">        <action name="getProgress" class="action.ProgressAction" method="execute">            <result name="success" type="json">                <param name="root">jsonData</param><!-- action中的要返回的属性 -->            </result>        </action>        </package>

项目做到这里,后端的事情已经做完了。接下来就是前端显示进度条的事情。需要的同学可以继续往下看咯。

前端那些事儿——css实现进度条控件

css:可以直接copy,无需细看(firefox下测试无问题)

.progress{    height: 20px;    background: #ebebeb;    border-left: 1px solid transparent;    border-right: 1px solid transparent;    border-radius: 10px;}.progress .blue {    background: #5aaadb;    border-color: #459fd6 #3094d2 #277db2;    background-image: -webkit-linear-gradient(top, #aed5ed 0%, #7bbbe2 70%, #5aaadb 100%);    background-image: -moz-linear-gradient(top, #aed5ed 0%, #7bbbe2 70%, #5aaadb 100%);    background-image: -o-linear-gradient(top, #aed5ed 0%, #7bbbe2 70%, #5aaadb 100%);    background-image: linear-gradient(to bottom, #aed5ed 0%, #7bbbe2 70%, #5aaadb 100%);}.progress > span {    position: relative;    float: left;    margin: 0 -1px;    min-width: 30px;    height: 18px;    line-height: 16px;    text-align: right;    background: #cccccc;    border: 1px solid;    border-color: #bfbfbf #b3b3b3 #9e9e9e;    border-radius: 10px;    background-image: -webkit-linear-gradient(top, #f0f0f0 0%, #dbdbdb 70%, #cccccc 100%);    background-image: -moz-linear-gradient(top, #f0f0f0 0%, #dbdbdb 70%, #cccccc 100%);    background-image: -o-linear-gradient(top, #f0f0f0 0%, #dbdbdb 70%, #cccccc 100%);    background-image: linear-gradient(to bottom, #f0f0f0 0%, #dbdbdb 70%, #cccccc 100%);    -webkit-box-shadow: inset 0 1px rgba(255, 255, 255, 0.3), 0 1px 2px rgba(0, 0, 0, 0.2);    box-shadow: inset 0 1px rgba(255, 255, 255, 0.3), 0 1px 2px rgba(0, 0, 0, 0.2);}.progress > span > span {    padding: 0 8px;    font-size: 11px;    font-weight: bold;    color: #404040;    color: rgba(0, 0, 0, 0.7);    text-shadow: 0 1px rgba(255, 255, 255, 0.4);}.progress > span:before {    content: '';    position: absolute;    top: 0;    bottom: 0;    left: 0;    right: 0;    z-index: 1;    height: 18px;    background: url("http://js.itivy.com/5-progress-bars/img/progress.png") 0 0 repeat-x;    border-radius: 10px;}

html调用progress代码很简单,就一行:这里设置隐藏,上传文件时再显示

      <div class="progress" style="width: 400px;" hidden="hidden"><span class="blue" style="width: 1%;"><span>1%</span></span></div>

控制进度条代码:在提交文件时同步调用此计时器即可。

setInterval(progressBar,500);    /**      * 展示上传进度条      */function progressBar () {         console.log("询问后台进度...");         $.ajax({             type : "GET",  //提交方式             url : "getProgress.action",//路径             success : function(result) {//返回数据根据结果进行相应的处理                 console.log(result);                 console.log("文件是否上传完成"+result.completed);                 if (result.isStarted){                     if (result.completed){                         $(".progress").hide();                         clearInterval(progressBar);//清除计时器                     }else{                         $(".progress >span").css({"width":result.percent});                         $(".progress >span>span").text(result.percent);                         $(".remain").text(result.remain);                     }                 }else{                     console.log("文件还没有提交");                 }             },             //异常处理             error:function (XMLHttpRequest, textStatus, errorThrown) {                 console.log(XMLHttpRequest+"---"+textStatus+"---"+errorThrown);             }         });      }

看到这里,上传文件显示进度条的相关内容基本上是结束了。
有问题的,可以留言交流~

生活有许多的不如意,如果一不开心,就寄希望于“如果当初”,那你永远都不会开心。

阅读全文
1 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 华为畅享7plus忘记密码怎么办 华为畅享8plus卡顿怎么办 华为畅享7plus卡机怎么办 华为畅享8plus图标字小怎么办 华为畅享6反应慢发热怎么办 华为畅享5S反应迟钝怎么办 华为畅玩5x玩王者荣耀卡怎么办 不小心把手机里的照片删了怎么办 u盘文件在手机上删了怎么办 荒野行动透视挂功能加载失败怎么办 白色t桖衫被奶茶弄脏了该怎么办 游戏文件不小心解压到c盘了怎么办 装系统时c盘0mb怎么办 电脑设置的开机密码忘了怎么办 电脑开机密码忘了怎么办xp系统 我的电脑在开机时忘了密码怎么办? xp桌面我的电脑图标不见了怎么办 游戏全屏时卡了无法退到界面怎么办 u盘插电脑上提示有病毒怎么办 三星手机文件怎么删除不掉怎么办 用夜神模拟器玩第五人格太卡怎么办 雷电模拟器玩刺激战场太卡了怎么办 绝地求生刺激战场模拟器太卡怎么办 ddj sb2打碟功能没了怎么办 驼背怎么办 要能快速矫正的方法 苹果7中间的home键坏了怎么办 苹果6p的home键不管用怎么办 华为获取数据失败请检查网络怎么办 三星手机未解锁刷机变砖怎么办 手机显示充电但是充不进去怎么办 手机拔出显示无法连接移动网怎么办 手机上的音乐老是显示网络忙怎么办 华为手机账号换手机忘记密码怎么办 墨墨背单词的注册邮箱忘了怎么办 华为手机华为账号密码忘记了怎么办 手机玩游戏降频特别厉害怎么办 苹果应用商店id登录老卡怎么办 苹果id忘记了自动续费怎么办 红米手机小米账号密码忘了怎么办 小米5splus没系统卡米怎么办 注册谷歌账号输入手机好怎么办