Java Web file download guide

background

Today, I adjusted the report download function of an old project. The original file was stored locally on the server. The download can be obtained directly from the local machine. Now we have to change it to obtain the file from the FTP server and return it to the front desk.

In theory, the code can be adjusted slightly, but in fact it is a small pit. This article will sort out the process and points of attention for downloading Java Web application files.

File download process

File download is an old-fashioned feature. The basic principle is to write data directly to the response stream and set the response type to binary stream format:

  1. Set the response code;
  2. Set the response file type octet-stream;
  3. Set the attachment name of the response header field;
  4. I want to write data to the OutputStream stream of ServletResponse.

The corresponding codes for the second, third and fourth steps are:

Insert picture description here

Download operation source code

The common file download codes are:

	@ResponseBody
	@RequestMapping(value = "/download")
	public void download(HttpServletRequest request, HttpServletResponse response,String reportId) {
		// TODO 根据 reportId 查询报表对应的文件名称
		String fileName = "xxx日报表文件.xlsx";

		//设置响应类型和附件头域
		response.setCharacterEncoding("utf-8");
		response.setContentType("application/octet-stream");
		response.setHeader("content-disposition", "attachment;filename="+ fileName);

		//读取报表内容写入响应流对象
		InputStream inputStream = null;
		try {
			OutputStream output = response.getOutputStream();

			//检查文件是否存在
			if(!isFileExist(fileName)){
				logger.warn("文件/目录 {} 不存在", pathName);
				response.getWriter().println("报表文件不存在!");
				return;
			}

			inputStream = new FileInputStream(new File(pathName));
			int len = -1;
			byte[] bytes = new byte[2048];
           // 向 Response 的响应流写入二进制数据
			while ((len = inputStream.read(bytes)) != -1) {
				output .write(bytes, 0, len);
			}
			output.flush();
		} catch (Exception e) {
			logger.error("下载文件异常",e);
			try {
				response.getWriter().println("下载文件异常!");
			} catch (IOException ex) {
				ex.printStackTrace();
			}
		}finally{
			if(output != null){
				try {
					output.close();
				} catch (IOException e) {
					logger.error("下载文件关闭输出流异常",e);
				}
			}
			if(inputStream != null){
				try {
					inputStream.close();
				} catch (IOException e) {
					logger.error("下载文件关闭输入流异常",e);
				}
			}
		}
	}
复制代码

敲重点After running the download operation, the report file of type xlsx is now in the download bar. The response header for viewing the network request is:

Insert picture description here

Response header field setting location

Set response header field and type information must be in writebefore writing , otherwise it is unreadable attachment. Adjust the code sequence, write and set the response header:

Insert picture description here
After performing the download operation, it was found that the xlsx report was downloaded in the .zip compressed package format, and the content was unreadable.

Looking at the header of the network response, it can be seen that the header field set afterwards has not taken effect:

Insert picture description here

Programming Apocalypse

Why is the display order of download attachments different when the setting order is different?

Verify repeated a dozen times, found response.setHeaderin writethe time after the operation, header set is invalid. It is speculated that this is determined by the assembly order of http communication protocol packets 因为 http 响应头域信息是在 body 之前组装的.

Finally, summarize the main points of the file download:

  1. Download path must be set in the background, you can not receive the download path of the front desk directly, otherwise there is ../..any risk of downloading a file path; if the path to be received with fileNameparameters, you must check fileNamenot contain ../other special path;
  2. You must pay attention to the order of the response header field setting and the stream writing operation 写设头域后写, otherwise the attachment is not available;
  3. The same FTP download from the ServletResponsethe OutputStreamobject passed FTPClientis retrieveFile(filename, outputStream)downloaded directly to the output stream.

Guess you like

Origin juejin.im/post/5e9a3393e51d4546b84780c7