JavaWeb, Spring, SpringBoot realize file upload and download

File upload and download

1. Front-end file.html:

Front-end form requirements: In order to upload files, the method of the form must be set to POST, and the enctype must be set to multipart/form-data. Only in this case, the browser will send the file selected by the user to the server as binary data;

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>上传</title>
</head>
<body>

<form action="/fileUpload" enctype="multipart/form-data" method="post">
       <input type="file" name="file"/>
       <input type="submit" value=”上传文件”>
</form>

<div>
    <a href="/download">点击下载</a>
</div>
</body>
</html>

note:

  • multipart/form-data : This encoding method will process form data in a binary stream. This encoding method will also encapsulate the content of the specified file in the file domain into the request parameters, and will not encode characters.
  • multipart/form-data uploads the form data in the form of multiple form items.

2. JavaWeb file upload and download

(1) File upload
needs to import two jar packages:

  • commons-fileupload-1.2.1.jar
  • commons-io-1.4.jar

Common methods:

  • The ServletFileUpload class is used to parse the uploaded data.
  • ServletFileUpload.isMultipartContent(HttpServletRequest request): Determine whether the current data is in a multipart format
  • List<FileItem> parseRequest(HttpServletRequest request): Parse the uploaded data and return multiple form items
  • FileItem.isFormField(): Determine whether the form item is a file
  • FileItem.getFieldName(): Get the name attribute value of the form item
  • FileItem.getString(): get the value of the form item
  • FileItem.getName(): Get the uploaded file name
  • FileItem.write(file): write the file in the form item to the disk directory pointed to by file
//判断上传的数据是否为多段数据
if(ServletFileUpload.isMultipartContent(req)){
    
    

	//创建FileItemFactory工厂实现类
	FileItemFactory fileItemFactory = new DiskFileItemFactory();
	
	//创建用于解析上传数据的工具类ServletFileUpload
	ServletFileUpload servletFileUpload = new ServletFileUpload(fileItemFactory);
	
    //解析上传数据,得到表单项FileItem
	List<FileItem> list = servletFileUpload.parseRequest(req);
	
	//循环判断每一个表单项,是普通类型还是上传的文件
	for(FileItem fileItem : list){
    
    
		if(fileItem.isFormField()){
    
    
			//普通表单项
			System.out.pritln(fileItem.getFiledName());
			System.out.pritln(fileItem.getString("UTF-8"));
		}else{
    
    
			//上传的文件
			System.out.pritln(fileItem.getFiledName());
			System.out.pritln(fileItem.getName());
			fileItem.write(new File("e:\\"+fileItem.getName()));
		}
	}
}

(2) File download

//需要下载的文件名
String downloadFileName = "1.jpg";

//读取要下载的文件内容
ServletContext servletContext = getServletContext();

//获取要下载的文件类型
String mimeType = servletContext,getMimeType("/file"+downloadFileName)

//告诉客户端返回的数据类型
resp.setContentType(mimeType);

//告诉客户端收到的数据是用于下载使用还是使用响应头
if(req.getHeader("User-Agent").content("Firefox")){
    
    
  resp.setHeader("Content-Disposition","attachment;
  fiename==?UTF-8?B?"+new BASE64Encoder().encode("中国.jpg","UTF-8")));

}else{
    
    
  resp.setHeader("Content-Disposition","attachment;
  fiename="+URLEncoder.encode("中国.jpg","UTF-8"));
}

InputStream resourceAsStream = servletContext.getResourceAsStream("/file"+downloadFileName);

//获取响应输出流
OutputStream outputStream = resp.getOutputStream();

//将下载的文件内容回传给客户端
IOUtils.copy(resourceAsStream,outputStream);

note:

  • Content-Disposition response header: how to deal with the received data
  • attachment: means attachment, used when downloading
  • req.getHeader("User-Agent"): Use different encodings according to different browsers. Firefox uses BASE64Encoder, and Google uses URLencoder encoding, which is mainly used to solve the Chinese garbled problem.

3. Spring file upload and download:

(1)MultipartResolver

  • springMVC can support file uploading well, but the MultipartResolver is not installed by default in the SpringMVC context, so it cannot handle file uploading by default. If you want to use Spring's file upload function, you need to configure MultipartResolver in the context.
  • Spring MVC provides direct support for file upload. This support is implemented with the plug-and-play MultipartResolver.
  • Spring MVC uses Apache Commons FileUpload technology to implement a MultipartResolver implementation class: CommonsMultipartResolver. Therefore, SpringMVC file upload also needs to rely on the component of ApacheCommonsFileUpload.
  • In SpringMVC, the need to import the file upload process dependencies commons-iopackage:
<dependency>
   <groupId>commons-fileupload</groupId>
   <artifactId>commons-fileupload</artifactId>
   <version>1.3.3</version>
</dependency>

commons-ioSituation of using dependent packages :

public String fileUpload(@RequestParam("file") CommonsMultipartFile
file) 

(2) Configure MultipartResolver

<!--文件上传配置-->
<bean id="multipartResolver"
 class="org.springframework.web.multipart.commons.CommonsMultipartResolve
r">
   <!-- 请求的编码格式,必须和jSP的pageEncoding属性一致,以便正确读取表单的内容,
默认为ISO-8859-1 -->
   <property name="defaultEncoding" value="utf-8"/>
   <!-- 上传文件大小上限,单位为字节(10485760=10M)-->
   <property name="maxUploadSize" value="10485760"/>
   <property name="maxInMemorySize" value="40960"/>
</bean>

note:

  • The id of bena must be: multipartResolver, otherwise the upload file will report a 400 error.

CommonsMultipartFile common methods:

  • String getOriginalFilename(): Get the original name of the uploaded file, such as test.html
  • InputStream getInputStream(): Get the file stream
  • void transferTo(File dest)Save the uploaded file to a catalog file

(3) File upload in the form of I/O stream

@Controller
public class FileController {
    
    
  
   @RequestMapping("/upload")
   public String fileUpload(@RequestParam("file") CommonsMultipartFile
file , HttpServletRequest request) throws IOException {
    
    

       //获取文件名
       String uploadFileName = file.getOriginalFilename();
       
       //如果文件名为空,直接回到首页!
       if ("".equals(uploadFileName)){
    
    
           return "redirect:/index.jsp";
      }
       System.out.println("上传文件名: "+uploadFileName);
       
       //上传路径保存设置
       String path =
request.getServletContext().getRealPath("/upload");

       //如果路径不存在,创建一个
       File realPath = new File(path);
       if (!realPath.exists()){
    
    
           realPath.mkdir();
      }
       System.out.println("上传文件保存地址:"+realPath);
       
       InputStream is = file.getInputStream(); //文件输入流
       OutputStream os = new FileOutputStream(new
File(realPath,uploadFileName)); //文件输出流

       //读取写出
       int len=0;
       byte[] buffer = new byte[1024];
       while ((len=is.read(buffer))!=-1){
    
    
           os.write(buffer,0,len);
           os.flush();
      }
       os.close();
is.close();
       return "redirect:/index.jsp";
  }
}

note:

  • @RequestParam("file") encapsulates the file obtained by the name=file control into a CommonsMultipartFile object
  • Bulk upload CommonsMultipartFile is an array

(4) Upload files using transferTo

@RequestMapping("/upload2")
public String  fileUpload2(@RequestParam("file") CommonsMultipartFile
file, HttpServletRequest request) throws IOException {
    
    

   //上传路径保存设置
   String path = request.getServletContext().getRealPath("/upload");
   File realPath = new File(path);
   if (!realPath.exists()){
    
    
       realPath.mkdir();
  }
   //上传文件地址
   System.out.println("上传文件保存地址:"+realPath);

   file.transferTo(new File(realPath +"/"+
file.getOriginalFilename()));

   return "redirect:/index.jsp";
}

(5) File download

  • Set the response header

  • Read file - InputStream

  • Write out the file - OutputStream

  • Close the stream (open first and then close)

@RequestMapping(value="/download")
public String downloads(HttpServletResponse response ,HttpServletRequest
request) throws Exception{
    
    

   //要下载的图片地址
   String  path = request.getServletContext().getRealPath("/upload");
   String  fileName = "基础语法.jpg";
   
//1、设置response 响应头
   response.reset(); //设置页面不缓存,清空buffer
   response.setCharacterEncoding("UTF-8"); //字符编码
   response.setContentType("multipart/form-data"); //二进制传输数据
   
   //设置响应头
   response.setHeader("Content-Disposition",
           "attachment;fileName="+URLEncoder.encode(fileName, "UTF-8"));
           
   File file = new File(path,fileName);
   //2、读取文件--输入流
   InputStream input=new FileInputStream(file);
   
   //3、写出文件--输出流
   OutputStream out = response.getOutputStream();
   byte[] buff =new byte[1024];
   int index=0;
   
   //4、执行写出操作
   while((index= input.read(buff))!= -1){
    
    
       out.write(buff, 0, index);
       out.flush();
  }
   out.close();
   input.close();
   return null;
}

front end:

<a href="/download">点击下载</a>

4. File upload and download in springboot:

(1) SpringBoot uses the default file upload process StandardServletMultipartResolver, and the related automatic configuration is in it MultipartAutoConfiguration. We can use spring.servlet.multipartto configure, of course, we can also use commons-iopackages, but we need to exclude the default method:

spring:
  autoconfigure:
    exclude: org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration

(2) File upload and download

  • Springboot upload files can be used directly org.springframework.web.multipart.MultipartFile.
  • When uploading a file, you need to define the address and file name of the uploaded file, get the byte stream from the file, and output it to the specified file path.
  • When downloading a file, get the full path of the downloaded file, and it is recommended to download the file using Buffer.
@RestController
public class TestController {
    
    

    @PostMapping("/fileUpload")
    public String fileUpload(HttpServletRequest req, HttpServletResponse resp,@RequestParam("file") MultipartFile file) {
    
    
        if(file.isEmpty()){
    
    
            return "未选择上传文件";
        }
        String originalFilename = file.getOriginalFilename();
        String path = "G:/glp/"+originalFilename;
        File dest = new File(path);
        if(!dest.getParentFile().exists()){
    
    
            dest.getParentFile().mkdir();
        }
        try{
    
    
            file.transferTo(dest);
            return "上传成功";
        }catch (IOException e){
    
    
            e.printStackTrace();
        }
        return "上传失败";
    }

    @GetMapping("/download")
    public String fileDownLoad(HttpServletRequest req,HttpServletResponse resp){
    
    
        File file = new File("G:/glp/Java研发工程师.pdf");
        if(!file.exists()){
    
    
            return "下载文件不存在";
        }
        try(BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));){
    
    
            byte[] buff = new byte[1024];
            OutputStream outputStream = resp.getOutputStream();
            int len =0;
            while ((len=bis.read(buff))!=-1){
    
    
                outputStream.write(buff,0,len);
                outputStream.flush();
            }
        }catch (IOException e){
    
    
            e.printStackTrace();
            return "下载失败";
        }
        return "下载成功";
    }
}

Note:
used heretransferToTo upload files.

五、BufferedInputStream

BufferedInputStream is an input stream with a buffer, usually using it can improve our reading efficiency, now we look at the implementation principle of BufferedInputStream:

  • There is a buffer inside the BufferedInputStream, the default size is 8M, each time the read method is called, it first tries to read data from the buffer, if the read fails (the buffer has no readable data), it selects from the physical data source (For example, a file) read new data (here we will try to read as many bytes as possible) into the buffer, and finally return part or all of the content in the buffer to the user. Because of reading from the buffer Data is much faster than reading directly from physical data sources (such as files), so BufferedInputStream is very efficient!
  • For operations without buffering, one byte is written every time a byte is read. Since disk-related IO operations are much slower than memory operations, the efficiency of streams without buffering is very low. With a buffered stream, you can read many bytes at a time, but don't write to the disk, just put it in the memory first. When the buffer size is enough, write to the disk at one time. This method can reduce the number of disk operations and increase the speed a lot! This is the difference between inputstream and bufferedinputstream.
  • BufferedInputStream and BufferedOutputStream are subclasses of FilterInputStream and FilterOutputStream respectively, which implement the decorative design pattern.

Guess you like

Origin blog.csdn.net/glpghz/article/details/108893963