栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

SpringBoot核心技术-Web开发-文件上传

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

SpringBoot核心技术-Web开发-文件上传

一、页面表单
二、文件上传代码
    
    @PostMapping("/upload")
    public String upload(@RequestParam("email") String email,
                         @RequestParam("username") String username,
                         @RequestPart("headerImg") MultipartFile headerImg,
                         @RequestPart("photos") MultipartFile[] photos) throws IOException {

        log.info("上传的信息:email={},username={},headerImg={},photos={}",
                email,username,headerImg.getSize(),photos.length);

        if(!headerImg.isEmpty()){
            //保存到文件服务器,OSS服务器
            String originalFilename = headerImg.getOriginalFilename();
            headerImg.transferTo(new File("H:\cache\"+originalFilename));
        }

        if(photos.length > 0){
            for (MultipartFile photo : photos) {
                if(!photo.isEmpty()){
                    String originalFilename = photo.getOriginalFilename();
                    photo.transferTo(new File("H:\cache\"+originalFilename));
                }
            }
        }


        return "main";
    }

 配置文件修改:

#文件上传的相关配置,第一个是单个文件最大大小,第二个是总的文件最大大小
spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=100MB
三、自动配置原理

文件上传自动配置类-MultipartAutoConfiguration-MultipartProperties配置属性类

//MultipartAutoConfiguration类中
@ConditionalOnMissingBean(MultipartResolver.class)
	public StandardServletMultipartResolver multipartResolver() {
		StandardServletMultipartResolver multipartResolver = new StandardServletMultipartResolver();
		multipartResolver.setResolveLazily(this.multipartProperties.isResolveLazily());
		return multipartResolver;
	}

自动配置好了 StandardServletMultipartResolver 【文件上传解析器(判断是否是文件请求)】

文件上传原理:

1、请求进来 使用文件上传解析器判断(checkMultipart中的isMultipart方法判断)并封装(resolveMultipart,返回MultipartHttpServletRequest)文件上传请求

//doDispatch方法中,先判断是否是文件请求
processedRequest = this.checkMultipart(request);
//通过请求是否被包装,确定是否是文件上传请求
multipartRequestParsed = processedRequest != request;
mappedHandler = this.getHandler(processedRequest);

 文件上传解析器multipartResolver只有一个StandardServletMultipartResolver :

 checkMultipart的具体代码:

protected HttpServletRequest checkMultipart(HttpServletRequest request) throws MultipartException {
        //判断是否是文件请求
        if (this.multipartResolver != null && this.multipartResolver.isMultipart(request)) {
            if (WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class) != null) {
                if (DispatcherType.REQUEST.equals(request.getDispatcherType())) {
                    this.logger.trace("Request already resolved to MultipartHttpServletRequest, e.g. by MultipartFilter");
                }
            } else if (this.hasMultipartException(request)) {
                this.logger.debug("Multipart resolution previously failed for current request - skipping re-resolution for undisturbed error rendering");
            } else {
                try {
                    //封装文件请求,变为MultipartHttpServletRequest请求类型
                    return this.multipartResolver.resolveMultipart(request);
                } catch (MultipartException var3) {
                    if (request.getAttribute("javax.servlet.error.exception") == null) {
                        throw var3;
                    }
                }

                this.logger.debug("Multipart resolution failed for error dispatch", var3);
            }
        }

this.multipartResolver.isMultipart(request):判断是否是文件请求

return this.multipartResolver.resolveMultipart(request);封装文件请求为请求类型MultipartHttpServletRequest,具体的是StandardMultipartHttpServletRequest。

2、参数解析器来解析请求中的文件内容封装成MultipartFile

最终选择RequestPartMethodArgumentResolver参数解析器解析,

 RequestPartMethodArgumentResolver调用resolveArgument方法,如下是方法中的关键代码:

Object mpArg = MultipartResolutionDelegate.resolveMultipartArgument(name, parameter, servletRequest);

 而上面这个resolveMultipartArgument方法关键代码如下:

//如果参数是文件数组,从请求的Map中 拿取请求的文件 赋给请求参数
parts = ((MultipartHttpServletRequest)multipartRequest).getFiles(name);

 

3、StandardServletMultipartResolver 将request中的文件信息封装为一个Map。

StandardServletMultipartResolver 将普通request包装为MultipartHttpServletRequest(接口),更具体的是StandardMultipartHttpServletRequest类

public MultipartHttpServletRequest resolveMultipart(HttpServletRequest request) throws MultipartException {
        return new StandardMultipartHttpServletRequest(request, this.resolveLazily);
}

StandardMultipartHttpServletRequest的parseRequest方法中将request中文件信息封装为一个Map,上述的getFiles方法就是从Map中拿取对应的文件

//AbstractMultipartHttpServletRequest类
public List getFiles(String name) {
        List multipartFiles = (List)this.getMultipartFiles().get(name);
        return multipartFiles != null ? multipartFiles : Collections.emptyList();
}

getMultipartFiles()会返回一个Map,MultiValueMap

protected MultiValueMap getMultipartFiles() {
        if (this.multipartFiles == null) {
            this.initializeMultipart();
        }

        return this.multipartFiles;
}
//StandardMultipartHttpServletRequest类 上面代码的initializeMultipart具体实现
private void parseRequest(HttpServletRequest request) {
        try {
            Collection parts = request.getParts();
            this.multipartParameterNames = new linkedHashSet(parts.size());
            MultiValueMap files = new linkedMultiValueMap(parts.size());
            Iterator var4 = parts.iterator();

            while(var4.hasNext()) {
                Part part = (Part)var4.next();
                String headerValue = part.getHeader("Content-Disposition");
                ContentDisposition disposition = ContentDisposition.parse(headerValue);
                String filename = disposition.getFilename();
                if (filename != null) {
                    if (filename.startsWith("=?") && filename.endsWith("?=")) {
                        filename = StandardMultipartHttpServletRequest.MimeDelegate.decode(filename);
                    }

                    files.add(part.getName(), new StandardMultipartHttpServletRequest.StandardMultipartFile(part, filename));
                } else {
                    this.multipartParameterNames.add(part.getName());
                }
            }

            this.setMultipartFiles(files);
        } catch (Throwable var9) {
            this.handleParseFailure(var9);
        }

 

FileCopyUtils,实现文件流的拷贝

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/445532.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号