Java Web implementation of file download and messy code handling methods

  • 2020-05-10 18:17:56
  • OfStack

File upload and download is a common problem in the development of web. In the past few days, I used to download files in a project. I also made some scattered notes before. File upload has yet to be tested in step 1, here is the first file download.

1. File download process

The file download process is actually very clear, that is:

1. Locate files according to file names or file paths. Specific policies are mainly based on your own needs.

2. Get the input stream, and get the input stream from the target file.

3. Get the output stream from response.

4. Read the file from the input stream and output the file through the output stream. This is the actual download execution.

5. Turn off IO stream.

This is the main process, and there are some necessary property Settings, such as the more important contentType type of Settings file.

2. Stop wordy, go to the code

I did it with Springmvc, but it's the same with the other ones, mainly HttpServletResponse objects and valid target files.

1. Foreground code


/*
*  Download the uploaded file 
*/
function downloadFromUpload(fileName){
window.location.href = path + "/download?dir=upload&fileName="+encodeURI(encodeURI(fileName));
}
/*
*  Ordinary download 
*/
function download(fileName){
window.location.href = path + "/download?dir=download&fileName="+encodeURI(encodeURI(fileName));
}

2. controller code


/**
*  File download ( Download from the upload path )
* 
* @param request
* @param response
* @throws IOException
*/
@ResponseBody
@RequestMapping(value = "/download")
public void downloadFile(HttpServletRequest request,
HttpServletResponse response, FileModel model) throws Exception {
String fileName = URLDecoder.decode(model.getFileName(), "UTF-8");
/*
*  Limit only upload and download The files in the folder can be downloaded 
*/
String folderName = "download";
if (!StringUtils.isEmpty(model.getDir())
&& model.getDir().equals("upload")) {
folderName = "upload";
} else {
folderName = "download";
}
String fileAbsolutePath = request.getSession().getServletContext()
.getRealPath("/")
+ "/WEB-INF/" + folderName + "/" + fileName;
FileTools.downloadFile(request, response, fileAbsolutePath);
log.warn(" The user Id : "
+ (Integer) (request.getSession().getAttribute("userId"))
+ ", User name: "
+ (String) (request.getSession().getAttribute("username"))
+ ", I downloaded the file :" + fileAbsolutePath);
}

The download logic here is that the foreground only needs to request /download and give the filename parameter. To avoid confusion in Chinese, the name of the foreground file is changed to Unicode code using encodeURI () of js as the parameter, and then the background code is decoded and converted to Chinese. In addition, due to the particularity of the project, the files I want to download here may be in the upload and download folders, so there is an extra part of judgment logic here. In addition, I've wrapped the file name and requested folder name in FileModel.

3. Download the logical implementation.

Instead of service, we're going to do it in a static way.


/**
*  Specify the download name when downloading the file 
* 
* @param request
* HttpServletRequest
* @param response
* HttpServletResponse
* @param filePath
*  File full path 
* @param fileName
*  Specifies the file name to display when the client downloads 
* @throws IOException
*/
public static void downloadFile(HttpServletRequest request,
HttpServletResponse response, String filePath, String fileName)
throws IOException {
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
bis = new BufferedInputStream(new FileInputStream(filePath));
bos = new BufferedOutputStream(response.getOutputStream());
long fileLength = new File(filePath).length();
response.setCharacterEncoding("UTF-8");
response.setContentType("multipart/form-data");
/*
*  Solve the problem of the browser's Chinese garbled code 
*/
String userAgent = request.getHeader("User-Agent");
byte[] bytes = userAgent.contains("MSIE") ? fileName.getBytes()
: fileName.getBytes("UTF-8"); // fileName.getBytes("UTF-8") To deal with safari The garbled code problem 
fileName = new String(bytes, "ISO-8859-1"); //  All browsers support it ISO coding 
response.setHeader("Content-disposition",
String.format("attachment; filename=\"%s\"", fileName));
response.setHeader("Content-Length", String.valueOf(fileLength));
byte[] buff = new byte[2048];
int bytesRead;
while (-1 != (bytesRead = bis.read(buff, 0, buff.length))) {
bos.write(buff, 0, bytesRead);
}
bis.close();
bos.close();
}
/**
*  The download file name is not specified when the file is downloaded 
* 
* @param request
* HttpServletRequest
* @param response
* HttpServletResponse
* @param filePath
*  File full path 
* @throws IOException
*/
public static void downloadFile(HttpServletRequest request,
HttpServletResponse response, String filePath) throws IOException {
File file = new File(filePath);
downloadFile(request, response, filePath, file.getName());
}

An overloaded download method is provided to address the need sometimes to specify the file name that the client will download.

3. Precautions

1. Selection of MIME type

Before the MIME type is not very understanding, found that there are a lot of downloaded source code MIME type Settings not 1. Is this sentence


response.setContentType("multipart/form-data");

One of the functions of setting the MIME type here is to tell the client browser what format to use for the file to be downloaded. There are a lot of explanations on the corresponding website. The I class is set to this format, and 1 will automatically match the format.

2, specify the client download file name

Sometimes we may need to specify the file name for the client to download the file, which is this code

response.setHeader("Content-disposition", String.format("attachment; filename=\"%s\"", fileName));
The fileName can be customized. Don't move the front part like 1.

3. Solve the problem of Chinese garbled codes

Chinese file chaos is so common that when the project system architecture is built, all Chinese codes should be unified, including the editor, the page and the database. UTF-8 codes are recommended. If you use Spring, you can also configure Spring's character set filter to step 1 to avoid Chinese scrambled codes.

(1) the client downloads the file name of the request process

Sometimes we will encounter that when the front page displays the list of Chinese file names to download, it is normal, but when we go to the background, we find that the file names in the request are scrambled. At this time, encodeURI mentioned above can be used to solve the problem.

(2) the client downloaded the execution of the file name chaos

In actual tests, it was found that the Chinese file name under ie might be garbled when all other browsers could execute it. On the Internet saw such a piece of code, after testing, the perfect solution to the problem of different browser Chinese garbled code


/*
*  Solve the problem of the browser's Chinese garbled code 
*/
String userAgent = request.getHeader("User-Agent");
byte[] bytes = userAgent.contains("MSIE") ? fileName.getBytes()
: fileName.getBytes("UTF-8"); // fileName.getBytes("UTF-8") To deal with safari The garbled code problem 
fileName = new String(bytes, "ISO-8859-1"); //  All browsers support it ISO coding 
response.setHeader("Content-disposition",
String.format("attachment; filename=\"%s\"", fileName));

(3) garbled files on the server

Different servers may be coded differently depending on the platform, but it is also important to note here. For the specific solution, please refer to the previous article: Chinese garbled code handling in the file downloading process


Related articles: