springboot框架下基于commons-fileupload实现文件上传、下载

先来讲述一下commons-fileupload实现上传的流程。
1.添加依赖。

   <!-- commons 文件操作 -->    
    <dependency>
        <groupId>commons-io</groupId>
        <artifactId>commons-io</artifactId>
        <version>2.5</version>
    </dependency>   
    
    <!-- FILE UPLOAD begin -->
    <dependency>
        <groupId>commons-fileupload</groupId>
        <artifactId>commons-fileupload</artifactId>
        <version>1.3.1</version>
    </dependency>          

1.创建一个文件上传解析器
我们知道上传有一些限制条件,比如上传文件大小,显示的上传进度等,如果是多文件上传,还有总文件大小的限制条件。
由于是个组件,这些参数都需要开发者自己定义,因此,在创建文件上传解析器时,我才用了builder模式。

public class UploadBuilder {
   
    
    public ServletFileUpload upload = new ServletFileUpload();
    
    public UploadBuilder(Builder builder){
   
        upload.setSizeMax(builder.sizeMax);
        upload.setFileSizeMax(builder.fileSizeMax);
        upload.setHeaderEncoding(builder.headerEncoding);
        upload.setFileItemFactory(builder.factory);
        upload.setProgressListener(builder.listener);
    }
    
    public static final class Builder {
   
        //总文件大小上限,默认无限大
        private long sizeMax = -1;
        //单个文件的大小上限,默认无限大
        private long fileSizeMax = -1;
        //编码方式
        private String headerEncoding;
        
        private DiskFileItemFactory factory;
        //进度条Listener
        private UploadProgressListener listener;
        
        public Builder(DiskFileItemFactory factory) {
   
            this.factory = factory;
        } 
        
        public Builder sizeMax(long value){
   
            this.sizeMax = value;
            return this;
        }
        
        public Builder fileSizeMax(long value){
   
            this.fileSizeMax = value;
            return this;
        }
        
        public Builder headerEncoding(String value){
   
            this.headerEncoding = value;
            return this;
        }
        
        public Builder listener(UploadProgressListener listener){
   
            this.listener = listener;
            return this;
        }
        
        public ServletFileUpload build() {
   
            return new UploadBuilder(this).upload;
        } 
        
    }

}

由于需求要展示上传文件的进度条,因此在这里设置了进度条Listener

public class UploadProgressListener implements ProgressListener {
   

    private HttpSession session;

    public UploadProgressListener(HttpServletRequest request) {
   
        this.session = request.getSession();
    }

    @Override
    public void update(long pBytesRead, long pContentLength, int pItems) {
   
        /**
         * 进度条信息,自行定义
         */
                //进度条回写到session中
        session.setAttribute("processInfo", info);
    }

}
2.使用ServletFileUpload解析器解析上传数据

public default ParseUploadInfoModel parseFileItems(ServletFileUpload upload,HttpServletRequest request){
   
        List<FileItem> items = null;
        if (!ServletFileUpload.isMultipartContent(request)) {
   
            return new ParseUploadInfoModel(UploadFileCodeEnmu.NOT_MULTIPART_CONTENT,null);
        }
        try {
   
            items = upload.parseRequest(request);
        } catch (FileUploadBase.SizeLimitExceededException e){
   
            return new ParseUploadInfoModel(UploadFileCodeEnmu.Q_EXCEED_SIZE_LIMIT,null);
        } catch (FileUploadBase.FileSizeLimitExceededException e) {
   
            return new ParseUploadInfoModel(UploadFileCodeEnmu.F_EXCEED_SIZE,null);
        }catch (FileUploadException e) {
   
        }
        return new ParseUploadInfoModel(UploadFileCodeEnmu.SUCCESS,items);
    }

这里获取到了解析数据,但是由于框架使用的是SpringBoot,其中spring mvc在处理请求的时候,有一个判断是否是上传请求,如果是上传请求,则进行解析转为MultipartHttpServletRequest请求。这样一来,我通过以上方式去获取请求参数时,就没法获取到了。源码分析如下:

springmvc判断是否是上传请求:

protected HttpServletRequest checkMultipart(HttpServletRequest request) throws MultipartException {
   
        if (this.multipartResolver != null && this.multipartResolver.isMultipart(request)) {
   
            if (WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class) != null) {
   
                logger.debug("Request is already a MultipartHttpServletRequest - if not in a forward, " +
                        "this typically results from an additional MultipartFilter in web.xml");
            }
            else if (hasMultipartException(request) ) {
   
                logger.debug("Multipart resolution failed for current request before - " +
                        "skipping re-resolution for undisturbed error rendering");
            }
            else {
   
                try {
   
                    return this.multipartResolver.resolveMultipart(request);
                }
                catch (MultipartException ex) {
   
                    if (request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) != null) {
   
                        logger.debug("Multipart resolution failed for error dispatch", ex);
                        // Keep processing error dispatch with regular request handle below
                    }
                    else {
   
                        throw ex;
                    }
                }
            }
        }
        // If not returned before: return original request.
        return request;
    }

主要通过this.multipartResolver.isMultipart(request)来判断的,这里MultipartResolver.class接口有两个实现类:CommonsMultipartResolver.class和StandardServletMultipartResolver.class。我们看看CommonsMultipartResolver.class的实现。

@Override
    public boolean isMultipart(HttpServletRequest request) {
   
        return ServletFileUpload.isMultipartContent(request);
    }

ServletFileUpload.isMultipartContent(request);

public static final boolean isMultipartContent(
            HttpServletRequest request) {
   
        if (!POST_METHOD.equalsIgnoreCase(request.getMethod())) {
   
            return false;
        }
        return FileUploadBase.isMultipartContent(new ServletRequestContext(request));
    }


 public static final boolean isMultipartContent(RequestContext ctx) {
   
        String contentType = ctx.getContentType();
        if (contentType == null) {
   
            return false;
        }
        if (contentType.toLowerCase(Locale.ENGLISH).startsWith(MULTIPART)) {
   
            return true;
        }
        return false;
    }

其实就是根据两个条件:1.一个是请求方式是POST。2.请求的contentType是multipart/,这个是前端页面定义上传的时候就必须定义好的。
那我们这里通过这种方式判断是否是上传请求,如果是上传请求,就进行解析并封装成MultipartHttpServletRequest.class。

@Override
    public MultipartHttpServletRequest resolveMultipart(final HttpServletRequest request) throws MultipartException {
   
        Assert.notNull(request, "Request must not be null");
        if (this.resolveLazily) {
   
            return new DefaultMultipartHttpServletRequest(request) {
   
                @Override
                protected void initializeMultipart(
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值