欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

springmvc/springboot 上传文件(Servlet3.0支持)

程序员文章站 2024-03-24 09:16:10
...
Controller代码
/**
     * 文件上传
     * @param
     * @return
     */
    @ResponseBody
    @RequestMapping(value = "/uploadMiltiFile",consumes = "multipart/form-data", method = RequestMethod.POST)
    public String instantUploadMiltiFile(HttpServletRequest request, String account) {
        MultipartHttpServletRequest muti = (MultipartHttpServletRequest) request;
        MultiValueMap<String, MultipartFile> map = muti.getMultiFileMap();
        for (Map.Entry<String, List<MultipartFile>> entry : map.entrySet()) {
            List<MultipartFile> list = entry.getValue();
            for (MultipartFile multipartFile : list) {
                try {
                    read(multipartFile.getInputStream());
                } catch (Exception ex) {

                }
            }
        }
        return "上传文件";
    }
MultipartFile的getInputStream()方法可以获取InputStream。接下去read函数就可以处理了

这里有个奇怪的地方就是  MultipartHttpServletRequest muti = (MultipartHttpServletRequest) request;为什么request可以转型成MultipartHttpServletRequest,我们看看请求在到达Controller做了什么。springmvc/springboot 上传文件(Servlet3.0支持)

实际上在请求到达DispatcherServlet通过进行了请求的转型。主要进行了两个步骤,一个是判断请求是上传文件类型,另外一个是对请求进行转型。关键函数是checkMultipart。

protected HttpServletRequest checkMultipart(HttpServletRequest request) throws MultipartException {
        if (this.multipartResolver != null && this.multipartResolver.isMultipart(request)) {
            if (WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class) != null) {
                this.logger.debug("Request is already a MultipartHttpServletRequest - if not in a forward, this typically results from an additional MultipartFilter in web.xml");
            } else if (this.hasMultipartException(request)) {
                this.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 var3) {
                    if (request.getAttribute("javax.servlet.error.exception") == null) {
                        throw var3;
                    }
                }

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

        return request;
    }

实际上调用了multipartResolver的isMultipart方法。multipartResolver是接口,它默认标准实现是StandardServletMultipartResolver那我们看下StandardServletMultipartResolver.isMultipart方法

public boolean isMultipart(HttpServletRequest request) {
        if (!"post".equalsIgnoreCase(request.getMethod())) {
            return false;
        } else {
            String contentType = request.getContentType();
            return StringUtils.startsWithIgnoreCase(contentType, "multipart/");
        }
    }

转换的逻辑是return this.multipartResolver.resolveMultipart(request);实际上也是调用StandardServletMultipartResolver.resolveMultipart方法。我们看下方法的源码

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

调了StandardMultipartHttpServletRequest的构造

public StandardMultipartHttpServletRequest(HttpServletRequest request, boolean lazyParsing) throws MultipartException {
        super(request);
        if (!lazyParsing) {
            this.parseRequest(request);
        }

    }

    private void parseRequest(HttpServletRequest request) {
        try {
            Collection<Part> parts = request.getParts();
            this.multipartParameterNames = new LinkedHashSet(parts.size());
            MultiValueMap<String, MultipartFile> 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);
        }

    }

这里还有一个疑问就是 Collection<Part> parts = request.getParts();

实际上在Servlet3.0支持request.getParts()获取上传文件