• Spring 中的文件上传与下载控制


    • 先创建根应用上下文配置,WebDemo/src/main/java/com/seliote/webdemo/config/RootContextConfig.java
    package com.seliote.webdemo.config;
    
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.stereotype.Controller;
    
    // 配置类必须标注 @Configuration 注解
    @Configuration
    // 设置注解扫描,默认扫描所有标注了 @Component 的类(@Component 标注的标注也算),都将变为 Spring 管理的 bean(自动实例化与注入依赖)
    @ComponentScan(
            // 注解扫描的起始包
            basePackages = "com.seliote.webdemo",
            // 排除对标注了 @Configuration 与 @Controller 类的实例化
            excludeFilters = @ComponentScan.Filter({Configuration.class, Controller.class})
    )
    public class RootContextConfig {
    }
    
    • 创建 Servlet 上下文配置,注意其中注册了一个 MultipartResolver 用于 Servlet 3.0- 的文件下载,WebDemo/src/main/java/com/seliote/webdemo/config/ServletContextConfig.java
    package com.seliote.webdemo.config;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.multipart.MultipartResolver;
    import org.springframework.web.multipart.support.StandardServletMultipartResolver;
    import org.springframework.web.servlet.config.annotation.EnableWebMvc;
    
    @Configuration
    // 激活注解驱动的控制器请求映射
    @EnableWebMvc
    @ComponentScan(
            basePackages = "com.seliote.webdemo",
            // 忽略默认扫描模式
            useDefaultFilters = false,
            // 仅对标注了 @Controller 的类进行扫描
            includeFilters = @ComponentScan.Filter(Controller.class)
    )
    public class ServletContextConfig {
    
        // 启用文件上传,如果不是 Servlet 3.0+ 就使用第三方工具
        @Bean
        public MultipartResolver multipartResolver() {
            return new StandardServletMultipartResolver();
        }
    }
    
    • 编写启动项,注意其中注册 DispatcherServlet 时所调用的 dynamic.setMultipartConfig(new MultipartConfigElement(...)) 方法用于开启文件上传,WebDemo/src/main/java/com/seliote/webdemo/config/Bootstrap.java
    package com.seliote.webdemo.config;
    
    import org.springframework.web.WebApplicationInitializer;
    import org.springframework.web.context.ContextLoaderListener;
    import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
    import org.springframework.web.servlet.DispatcherServlet;
    
    import javax.servlet.MultipartConfigElement;
    import javax.servlet.ServletContext;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRegistration;
    
    // ServletContainerInitializer 接口的实现将在应用程序启动时(所有监听器启动之前)调用 onStartup() 方法(应用可用的最早时间点),
    // 但是直接实现 ServletContainerInitializer 过于麻烦,所以提供了一个 SpringServletContainerInitializer 桥接口,
    // 它会在应用程序启动时扫描应用中所有 WebApplicationInitializer 接口的实现并调用其 onStartup() 方法
    public class Bootstrap implements WebApplicationInitializer {
        public void onStartup(ServletContext aServletContext) throws ServletException {
            // 允许 Servlet 容器提供静态文件
            aServletContext.getServletRegistration("default").addMapping("/resource/*");
    
            // 配置根应用上下文
            AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
            rootContext.register(RootContextConfig.class);
            // 通过监听器启动根上下文(ContextLoaderListener 将在 Web 应用程序启动时初始化
            aServletContext.addListener(new ContextLoaderListener(rootContext));
    
            // 配置 Servlet 上下文
            AnnotationConfigWebApplicationContext servletContext = new AnnotationConfigWebApplicationContext();
            servletContext.register(ServletContextConfig.class);
            // 动态注册一个 DispatcherServlet,注意是 new DispatcherServlet(ApplicationContext)
            // 并传入上文创建的 AnnotationConfigWebApplicationContext,而非传入 DispatcherServlet.class
            ServletRegistration.Dynamic dynamic = aServletContext.addServlet("dispatcherServlet", new DispatcherServlet(servletContext));
            // 启用文件上传
            dynamic.setMultipartConfig(new MultipartConfigElement("/tmp", 20_971_520L, 41_943_040L, 512_000));
            // 设置 DispatcherServlet 的映射
            dynamic.addMapping("/");
            // 设置应用程序部署后即启动
            dynamic.setLoadOnStartup(1);
        }
    }
    
    • 两个 JSP 用于上传和下载
      WebDemo/web/upload.jsp
    <%@ page contentType="text/html" pageEncoding="UTF-8" language="java" %>
    <html>
    <head>
        <title>Upload</title>
    </head>
    <body>
    <h2>Select a file:</h2><br /><br />
    <form method="post" action="/upload" enctype="multipart/form-data">
        <input type="file" name="userFile" /><br />
        <input type="submit" value="Submit" />
    </form>
    </body>
    </html>
    

    WebDemo/web/download.jsp

    <%@ page contentType="text/html" pageEncoding="UTF-8" language="java" %>
    <html>
    <head>
        <title>Download</title>
    </head>
    <body>
        <a href="/download">
            <button type="button">Download</button>
        </a>
    </body>
    </html>
    
    • 最后编写控制器即可,WebDemo/src/main/java/com/seliote/webdemo/controller/FileController.java
    package com.seliote.webdemo.controller;
    
    import org.springframework.http.HttpRequest;
    import org.springframework.http.HttpStatus;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestPart;
    import org.springframework.web.bind.annotation.ResponseBody;
    import org.springframework.web.bind.annotation.ResponseStatus;
    
    import javax.servlet.ServletOutputStream;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.Part;
    import java.io.ByteArrayOutputStream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    
    @Controller
    public class FileController {
    
        @ResponseBody
        @ResponseStatus(HttpStatus.OK)
        @RequestMapping("/upload")
        public String upload(@RequestPart("userFile") Part aPart) throws IOException {
            if (aPart == null) {
                return "Part is null";
            }
            InputStream inputStream = aPart.getInputStream();
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int readLength = -1;
            while ((readLength = inputStream.read(buffer)) != -1) {
                byteArrayOutputStream.write(buffer, 0, readLength);
            }
            int length = byteArrayOutputStream.size();
            byteArrayOutputStream.close();
            return "Success!" + length;
        }
    
        @ResponseBody
        @ResponseStatus(HttpStatus.OK)
        @RequestMapping("/download")
        public void download(HttpServletRequest aHttpServletRequest, HttpServletResponse aHttpServletResponse) throws IOException {
            File file = new File("/home/seliote/Temp/grub.cfg");
    
            // 设置响应头,说明是文件下载
            aHttpServletResponse.setHeader("Content-Disposition", "attachment; filename=" + file.getName());
            aHttpServletResponse.setContentType("application/octet-stream");
    
            // 为响应手动写入文件
            InputStream inputStream = new FileInputStream(file);
            ServletOutputStream servletOutputStream = aHttpServletResponse.getOutputStream();
            byte[] buffer = new byte[1024];
            int readLength = -1;
            while ((readLength = inputStream.read(buffer)) != -1) {
                servletOutputStream.write(buffer, 0, readLength);
            }
            inputStream.close();
        }
    }
    
  • 相关阅读:
    性能测试培训:性能瓶颈分析思路
    (国内)完美下载Android源码Ubuntu版
    (国内)完美下载android源代码(文章已经丢失)
    【翻译】Ext JS最新技巧——2015-10-21
    ubuntu 中 eclipse 的菜单栏 显示问题
    谷歌代码库已超过 20 亿行代码,他们是如何管理的?
    架构方面的资料集锦
    Android Studio 使用 Gradle 打包 Jar
    【翻译】Ext JS最新技巧——2015-8-11
    【翻译】在Ext JS 6通用应用程序中使用既共享又特定于视图的代码
  • 原文地址:https://www.cnblogs.com/seliote/p/9934646.html
Copyright © 2020-2023  润新知