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();
    }
}

猜你喜欢

转载自www.cnblogs.com/seliote/p/9934646.html