SpringMVC is used based on annotations: upload & download

Get into the habit of writing together! This is the 8th day of my participation in the "Nuggets Daily New Plan · April Update Challenge", click to view the details of the event .

1. File download

1-1, servlet native way to download

/**
 * 基于servlet api的文件下载
 */
@RequestMapping("/download")
public String download(HttpServletRequest request,HttpServletResponse response) throws IOException {
    // 获得当前项目路径下的下载文件(真实开发中文件名肯定是从数据中读取的)
    String realPath =request.getServletContext().getRealPath("/file/20181129204254948.png");
    // 根据文件路径封装成了File对象
    File tmpFile=new File(realPath);
    // 可以直接根据File对象获得文件名
    String fileName = tmpFile.getName();
    // 设置响应头 content-disposition: 就是设置文件下载的打开方式,默认会在网页上打开,
    // 设置attachment;filename= 就是为了以下载方式来打开文件
    // "UTF-8"设置如果文件名有中文就不会乱码
    response.setHeader("content-disposition", "attachment;filename="+ URLEncoder.encode(fileName, "UTF-8"));
    // 根据文件路径 封装成文件输入流
    InputStream in = new FileInputStream(realPath);
    int len = 0;
    // 声明了一个1KB的字节 的缓冲区
    byte[] buffer = new byte[1024];
    // 获取输出流
    OutputStream out = response.getOutputStream();
    // 循环读取文件,每次读1KB,避免内存溢出
    while ((len = in.read(buffer)) > 0) {
        // 往客户端写入
        out.write(buffer,0,len);//将缓冲区的数据输出到客户端浏览器
    }
    in.close();

    return null;
}
复制代码

In the above code, we set the response header response.setHeader("content-disposition", "attachment;filename="+ URLEncoder.encode(fileName, "UTF-8"));

The content-disposition allows the front end to be downloaded in the form of a file, otherwise it will be opened directly in the browser

1-2. Use ResponseEntity to download

You can customize the content of the response data, the response headers, and the response status code at the same time

1-2-1. Use ResponseEntity to customize the response content.

Generally, in a scenario where the front-end and back-end are separated, the front-end requests the interface of the back-end, and the back-end generally returns three values: request status, request data, and request information. Using ResponseEntity can help us customize such content.

image.pngFrom the above figure, we can see that relevant data can be returned through ResponseEntity, and response headers and status codes can also be set.

Another thing to note is that you can see that the return type of the method is Response<String> When we return ResponseEntity, the first parameter must be of type String. This is the value that returns the generic type.

2-2-2. Use ResponseEntity to download files

/**
 * 基于servlet api的文件下载
 */
@RequestMapping("/download02")
public ResponseEntity<byte[]>  download02(HttpServletRequest request) throws IOException {
    // 获得当前项目路径下的下载文件(真实开发中文件名肯定是从数据中读取的)
    String realPath =request.getServletContext().getRealPath("/file/20181129204254948.png");
    // 根据文件路径封装成了File对象
    File tmpFile=new File(realPath);
    // 可以直接根据File对象获得文件名
    String fileName = tmpFile.getName();
    HttpHeaders headers=new HttpHeaders();
    headers.set("content-disposition", "attachment;filename="+ URLEncoder.encode(fileName, "UTF-8"));
    // 根据文件路径 封装成文件输入流
    InputStream in = new FileInputStream(realPath);

    return new ResponseEntity<>(new byte[in.available()],headers,HttpStatus.OK);
}
复制代码

image.pngIt can be seen that the data can also be downloaded using ResponseEntity, but the buffer cannot be set, and it can only be read all at once.

1-2-3, the difference between servlet download and ResponseEntity download

两者区别,使用原生servlet下载,我们可以设置缓冲区,但是使用ResponseEntity就无法进行设置,只能将文件的全部数据以字节数组的方式一次性读取。为了避免内存溢出,建议使用servlet原生的方式下载

二、文件上传

Spring MVC 为文件上传提供了直接的支持,这种支持是通过即插即用的 MultipartResolver 实现的。Spring 用 Jakarta Commons FileUpload 技术实现了一个 MultipartResolver 实现类:CommonsMultipartResovler

Spring MVC 上下文中默认没有装配 MultipartResovler,因此默认情况下不能处理文件的上传工作,如果想使用 Spring 的文件上传功能,需现在上下文中配置 MultipartResolver。

2-1、添加commons-fileupload依赖

下载基于Jakarta Commons FileUpload的上传支持jar包

<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.4</version>
</dependency>
复制代码

如果使用idea一定要手动再导入一下包(导入方式可以看之前的文章)

image.png

2-2、配置spring.xml注入CommonsMultipartResolver文件上传解析器

<!--注入基于CommonsMultipartResolver文件上传解析器-->
<bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver" id="multipartResolver">
    <!--设置编码集,防止出现中文乱码-->
    <property name="defaultEncoding" value="UTF-8"></property>
    <!--设置最大上传字节  配置10MB-->
    <property name="maxUploadSize" value="#{1024*1024*10}"></property>
</bean>
复制代码

2-3、文件上传

2-3-1、单个文件上传

2-3-1-1、编写控制器方法

/**
 * 基于springmvc MultiPartResolver文件上传
 * @param desc
 * @param multipartFile
 * @return
 * @throws IOException
 */
@PostMapping("/upload01")
public String upload01(String desc, @RequestParam("myfile") MultipartFile multipartFile) throws  IOException {

    System.out.println(desc);
    System.out.println(multipartFile.getOriginalFilename());
    String path = "d:\\img\\" + multipartFile.getOriginalFilename();
    File file = new File(path);
    multipartFile.transferTo(file);
    return "success";
}
复制代码

2-3-1-2、视图层

<form enctype="multipart/form-data" action="${pageContext.request.contextPath}/upload01" method="post">
  <p>文件描述:<input type="text" name="desc" /></p>
  <p>文件:<input type="file" name="myfile" accept="image/*"/></p>
  <p><input type="submit" value="上传单个文件"></p>
</form>
复制代码

2-3-2、多文件上传

2-3-2-1、编写控制器方法

/**
 * 基于springmvc MultiPartResolver多文件文件上传
 * @param desc
 * @param myfile
 * @return
 * @throws IOException
 */
@PostMapping("/upload02")
public String upload02(String desc,MultipartFile[] myfile) throws  IOException {

    for (MultipartFile multipartFile : myfile) {
        System.out.println(desc);
        System.out.println(multipartFile.getOriginalFilename());
        String path = "d:\img\" + multipartFile.getOriginalFilename();
        File file = new File(path);
        multipartFile.transferTo(file);
    }
    return "success";
}
复制代码

2-3-2-2、视图层

视图层我们可以控制file上传的文件是否多选可以使用mutiple="mutiple" 在h5中如果属性和值相等,可以将值省略,然后设置了accept属性,可以在用户选择的时候自动过滤,如下面代码只显示图片类型的文件

<form enctype="multipart/form-data" action="${pageContext.request.contextPath}/upload03" method="post">
  <p>文件描述:<input type="text" name="desc" /></p>
  <p>文件:<input type="file" name="myfile" multiple accept="image/*"/></p>
  <p><input type="submit" value="上传多个文件"></p>
</form>
复制代码

2-3-3、通过多线程的方式批量上传文件

In the above example, multi-file upload is used. Although the for method can be used to read and upload files one by one, in some scenarios, the efficiency is greatly reduced. In order to improve the efficiency of our upload, we can use multi-threaded way to upload.

2-3-3-4, write controller method

/**
 * 基于springmvc MultiPartResolver多文件文件上传--多线程
 * @param desc
 * @param myfile
 * @return
 * @throws IOException
 */
@PostMapping("/upload03")
public String upload03(String desc,MultipartFile[] myfile) throws IOException, InterruptedException {

    System.out.println(desc);
    for (MultipartFile multipartFile : myfile) {
        // 声明线程
        Thread thread = new Thread(() -> {
            System.out.println(multipartFile.getOriginalFilename());
            String path = "d:\img\" + multipartFile.getOriginalFilename();
            File file = new File(path);
            try {
                multipartFile.transferTo(file);
            } catch (IOException e) {
                e.printStackTrace();
            }
        });
        thread.start();   //启动线程
        thread.join();   // 让子线程执行完再执行主线程
    }
    return "success";
}
复制代码

Guess you like

Origin juejin.im/post/7084036356132831245