Servlet realizes file upload and download
For file upload, the browser submits the file to the server in the form of stream during the upload process. It is troublesome to directly use Servlet to obtain the input stream of the uploaded file and then parse the request parameters. Therefore, the file upload component of apache's open source tool common fileUpload is generally selected. The jar package of the common file upload upload component can be downloaded from the apache official website or found under the lib folder of struts. The function of struts upload is based on this implementation. Common file upload depends on the common IO package, so you also need to download this package.
1, Construction of development environment
Create a FileUploadAndDownLoad project and add the Jar package of Apache's Commons fileUpload file upload component, as shown in the following figure:
2, Realize file upload
The file upload function has many small details that need to be paid attention to. The following points need special attention
1. In order to ensure the security of the server, the uploaded files should be placed in a directory that cannot be directly accessed by the outside world, such as the WEB-INF directory.
2. To prevent file overwriting, a unique file name should be generated for the uploaded file.
3. In order to prevent too many files under a directory, hash algorithm should be used to break up the storage.
4. To limit the maximum number of uploaded files.
**5. To * limit * the type of uploaded file, judge whether the suffix is legal when receiving the uploaded file name.
2.1 file upload page and message prompt page
The code of the upload.jsp page is as follows:
<%@ page language="java" pageEncoding="UTF-8"%> <!DOCTYPE HTML> <html> <head> <title>File upload</title> </head> <body> <form action="${pageContext.request.contextPath}/servlet/UploadHandleServlet" enctype="multipart/form-data" method="post"> Upload user:<input type="text" name="username"><br/> Upload file 1:<input type="file" name="file1"><br/> Upload file 2:<input type="file" name="file2"><br/> <input type="submit" value="Submit"> </form> </body> </html>
The code of message.jsp is as follows:
<%@ page language="java" pageEncoding="UTF-8"%> <!DOCTYPE HTML> <html> <head> <title>Message prompt</title> </head> <body> ${message} </body> </html>
2.2. Handle the Servlet of file upload
The code of UploadHandleServlet is as follows:
package com.web.controller; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.List; import java.util.UUID; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.FileUploadBase; import org.apache.commons.fileupload.ProgressListener; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; /** * @ClassName: UploadHandleServlet * @Description: TODO(The function of this class is described in one sentence) * @author: hdb * @date: 2017-11-13 14:35:50 * */ public class UploadHandleServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //Get the storage directory of the uploaded files, store the uploaded files in the WEB-INF directory, and do not allow direct access from the outside world to ensure the safety of the uploaded files String savePath = this.getServletContext().getRealPath("/WEB-INF/upload"); //Save directory of temporary files generated during upload String tempPath = this.getServletContext().getRealPath("/WEB-INF/temp"); File tmpFile = new File(tempPath); if (!tmpFile.exists()) { //Create temporary directory tmpFile.mkdir(); } //Message prompt String message = ""; try{ //Using Apache file upload component to process file upload steps: //1. Create a DiskFileItemFactory factory DiskFileItemFactory factory = new DiskFileItemFactory(); //Set the buffer size of the factory. When the uploaded file size exceeds the buffer size, a temporary file will be generated and stored in the specified temporary directory. factory.setSizeThreshold(1024*100);//Set the size of the buffer to 100KB. If it is not specified, the default size of the buffer is 10KB //Set the saving directory of temporary files generated during uploading factory.setRepository(tmpFile); //2. Create a file upload parser ServletFileUpload upload = new ServletFileUpload(factory); //Monitor file upload progress upload.setProgressListener(new ProgressListener(){ public void update(long pBytesRead, long pContentLength, int arg2) { System.out.println("File size:" + pContentLength + ",Currently processed:" + pBytesRead); /** * File size: 14608, currently processed: 4096 File size: 14608, currently processed: 7367 File size: 14608, currently processed: 11419 File size: 14608, currently processed: 14608 */ } }); //Solve the Chinese garbled code of uploaded file name upload.setHeaderEncoding("UTF-8"); //3. Judge whether the submitted data is the data of the uploaded form if(!ServletFileUpload.isMultipartContent(request)){ //Get data in the traditional way return; } //Set the maximum size of a single file to be uploaded. At present, it is set to 1024 * 1024 bytes, that is, 1MB upload.setFileSizeMax(1024*1024); //Set the maximum value of the total number of uploaded files. The maximum value = the sum of the maximum sizes of multiple files uploaded at the same time. At present, it is set to 10MB upload.setSizeMax(1024*1024*10); //4. The servlet fileUpload parser is used to parse the uploaded data. The parsing result returns a list < FileItem > collection, and each FileItem corresponds to an input item of the Form List<FileItem> list = upload.parseRequest(request); for(FileItem item : list){ //If the fileitem encapsulates the data of ordinary input items if(item.isFormField()){ String name = item.getFieldName(); //Solve the Chinese garbled code problem of data of common input items String value = item.getString("UTF-8"); //value = new String(value.getBytes("iso8859-1"),"UTF-8"); System.out.println(name + "=" + value); }else{//If the uploaded file is encapsulated in fileitem //Get the name of the uploaded file, String filename = item.getName(); System.out.println(filename); if(filename==null || filename.trim().equals("")){ continue; } //Note: the file names submitted by different browsers are different. Some browsers submit file names with paths, such as c:\a\b .txt, while some are just simple file names, such as 1.txt //Process the path part of the file name of the obtained uploaded file, and only keep the file name part filename = filename.substring(filename.lastIndexOf("\\")+1); //Get the extension of the uploaded file String fileExtName = filename.substring(filename.lastIndexOf(".")+1); //If you need to limit the uploaded file type, you can judge whether the uploaded file type is legal through the file extension System.out.println("The extension of the uploaded file is:"+fileExtName); //Get the input stream of the uploaded file in item InputStream in = item.getInputStream(); //Get the name of the file to save String saveFilename = makeFileName(filename); //Get the save directory of the file String realSavePath = makePath(saveFilename, savePath); //Create a file output stream FileOutputStream out = new FileOutputStream(realSavePath + "\\" + saveFilename); //Create a buffer byte buffer[] = new byte[1024]; //Identification to judge whether the data in the input stream has been read int len = 0; //The loop reads the input stream into the buffer, (len = in. Read (buffer)) > 0 indicates that there is data in the in while((len=in.read(buffer))>0){ //Use the FileOutputStream output stream to write the buffer data to the specified directory (savePath + "\" + filename) out.write(buffer, 0, len); } //Close input stream in.close(); //Close output stream out.close(); //Delete temporary files generated when processing file upload //item.delete(); message = "File upload succeeded!"; } } }catch (FileUploadBase.FileSizeLimitExceededException e) { e.printStackTrace(); request.setAttribute("message", "Single file exceeds maximum!!!"); request.getRequestDispatcher("/message.jsp").forward(request, response); return; }catch (FileUploadBase.SizeLimitExceededException e) { e.printStackTrace(); request.setAttribute("message", "The total size of uploaded files exceeds the maximum limit!!!"); request.getRequestDispatcher("/message.jsp").forward(request, response); return; }catch (Exception e) { message= "File upload failed!"; e.printStackTrace(); } request.setAttribute("message",message); request.getRequestDispatcher("/message.jsp").forward(request, response); } /** * @Method: makeFileName * @Description: Generate the file name of the uploaded file. The file name is: uuid + "" + the original name of the file * @Anthor:hdb * @param filename The original name of the file * @return uuid+"_"+The original name of the file */ private String makeFileName(String filename){ //2.jpg //To prevent file overwriting, a unique file name should be generated for the uploaded file return UUID.randomUUID().toString() + "_" + filename; } /** * In order to prevent too many files under a directory, hash algorithm should be used to break up the storage * @Method: makePath * @Description: * @Anthor:hdb * * @param filename File name, the storage directory should be generated according to the file name * @param savePath File storage path * @return New storage directory */ private String makePath(String filename,String savePath){ //Get the hashCode value of the file name, and get the address of the string object filename in memory int hashcode = filename.hashCode(); int dir1 = hashcode&0xf; //0--15 int dir2 = (hashcode&0xf0)>>4; //0-15 //Construct a new save directory String dir = savePath + "\\" + dir1 + "\\" + dir2; //upload\2\3 upload\3\5 //File can represent either a file or a directory File file = new File(dir); //If the directory does not exist if(!file.exists()){ //Create directory file.mkdirs(); } return dir; } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
Register the UploadHandleServlet in the Web.xml file:
<servlet> <servlet-name>UploadHandleServlet</servlet-name> <servlet-class>com.web.controller.UploadHandleServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>UploadHandleServlet</servlet-name> <url-pattern>/servlet/UploadHandleServlet</url-pattern> </servlet-mapping>
The operation effect is as follows:
After the file is uploaded successfully, the uploaded file is saved in the upload directory under the WEB-INF directory, as shown in the following figure:
3, File download
3.1 list the file resources provided for download
We want to provide file resources in the Web application system to users for downloading. First, we need to have a page to list all files in the uploaded file directory. When users click the file download hyperlink, they will download, and write a ListFileServlet to list all downloaded files in the Web application system.
The code of ListFileServlet is as follows:
package com.web.controller; import java.io.File; import java.io.IOException; import java.util.HashMap; import java.util.Map; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * @ClassName: ListFileServlet * @Description: Lists all downloaded files in the Web system * @author: hdb * @date: 2017-11-14 19:54:40 * */ public class ListFileServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //Get the directory of uploaded files String uploadFilePath = this.getServletContext().getRealPath("/WEB-INF/upload"); //Store the file name to download Map<String,String> fileNameMap = new HashMap<String,String>(); //Recursively traverse all files and directories under the filepath directory, and store the file name of the file in the map collection listfile(new File(uploadFilePath),fileNameMap);//File can represent either a file or a directory //Send the Map collection to the listfile.jsp page for display request.setAttribute("fileNameMap", fileNameMap); request.getRequestDispatcher("/listfile.jsp").forward(request, response); } /** * @Method: listfile * @Description: Recursively traverse all files in the specified directory * @Anthor:hdb * @param file It represents both a file and a file directory * @param map A Map collection that stores file names */ public void listfile(File file,Map<String,String> map){ //If file represents not a file, but a directory if(!file.isFile()){ //List all files and directories in this directory File files[] = file.listFiles(); //Traversing the files [] array for(File f : files){ //recursion listfile(f,map); } }else{ /** * Process the file name. The uploaded file is in uuid_ Rename the form of file name, and remove the uuid of the file name_ part file.getName().indexOf("_")Retrieve the position where the "" character first appears in the string. If the file name is similar to: 9349249849-88343-8344_ Ah_ Where_ Da.avi After file. Getname(). Substring (file. Getname(). Indexof ("") + 1) is processed, you can get a_ Where_ Up to. avi part */ String realName = file.getName().substring(file.getName().indexOf("_")+1); //file.getName() gets the original name of the file. This name is unique, so it can be used as a key. realName is the processed name, which may be repeated map.put(file.getName(), realName); } } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
Let's briefly talk about the listfile method in ListFileServlet. The listfile method is used to list all files in the directory. Recursion is used inside the listfile method. In actual development, we will certainly create a table in the database, which will store the uploaded file name and the specific storage directory of the file, We can know the specific storage directory of the file through the query table. Recursive operation is not required. This example is because the database is not used to store the uploaded file name and the specific storage location of the file, and the storage location of the uploaded file is scattered by hash algorithm. Therefore, recursion is required. During recursion, Store the obtained file name in the Map set passed from the outside to the listfile method, so as to ensure that all files are stored in the same Map set.
Configure ListFileServlet in Web.xml file:
<servlet> <servlet-name>ListFileServlet</servlet-name> <servlet-class>com.web.controller.ListFileServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>ListFileServlet</servlet-name> <url-pattern>/servlet/ListFileServlet</url-pattern> </servlet-mapping>
The listfile.jsp page showing the downloaded file is as follows:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <!DOCTYPE HTML> <html> <head> <title>Download file display page</title> </head> <body> <!-- ergodic Map aggregate --> <c:forEach var="me" items="${fileNameMap}"> <c:url value="/servlet/DownLoadServlet" var="downurl"> <c:param name="filename" value="${me.key}"></c:param> </c:url> ${me.value}<a href="${downurl}">download</a> <br/> </c:forEach> </body> </html>
Access ListFileServlet to display the file resources provided for users to download in listfile.jsp page, as shown in the following figure:
3.2. Realize file download
Write a Servlet for file download. The code of DownLoadServlet is as follows:
package com.web.controller; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.OutputStream; import java.net.URLEncoder; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class DownLoadServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //Get the file name to download String fileName = request.getParameter("filename"); //239283-92489 avatar.avi fileName = new String(fileName.getBytes("iso8859-1"),"UTF-8"); //All uploaded files are saved in subdirectories under the / WEB-INF/upload directory String fileSaveRootPath=this.getServletContext().getRealPath("/WEB-INF/upload"); //Find the directory where the file is located by the file name String path = findFileSavePathByFileName(fileName,fileSaveRootPath); //Get the file to download File file = new File(path + "\\" + fileName); //If the file does not exist if(!file.exists()){ request.setAttribute("message", "The resource you want to download has been deleted!!"); request.getRequestDispatcher("/message.jsp").forward(request, response); return; } //Processing file name String realname = fileName.substring(fileName.indexOf("_")+1); //Set the response header to control the browser to download the file response.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(realname, "UTF-8")); //Read the file to be downloaded and save it to the file input stream FileInputStream in = new FileInputStream(path + "\\" + fileName); //Create output stream OutputStream out = response.getOutputStream(); //Create buffer byte buffer[] = new byte[1024]; int len = 0; //Loop reads the contents of the input stream into the buffer while((len=in.read(buffer))>0){ //Output the contents of the buffer to the browser to realize file download out.write(buffer, 0, len); } //Close file input stream in.close(); //Close output stream out.close(); } /** * @Method: findFileSavePathByFileName * @Description: Find the path of the file to be downloaded through the file name and the root directory where the uploaded file is stored * @Anthor:hdb * @param filename File name to download * @param saveRootPath The root directory where the uploaded file is saved, that is, the / WEB-INF/upload directory * @return The storage directory of the file to download */ public String findFileSavePathByFileName(String filename,String saveRootPath){ int hashcode = filename.hashCode(); int dir1 = hashcode&0xf; //0--15 int dir2 = (hashcode&0xf0)>>4; //0-15 String dir = saveRootPath + "\\" + dir1 + "\\" + dir2; //upload\2\3 upload\3\5 File file = new File(dir); if(!file.exists()){ //Create directory file.mkdirs(); } return dir; } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
Configure DownLoadServlet in the Web.xml file:
<servlet> <servlet-name>DownLoadServlet</servlet-name> <servlet-class>com.web.controller.DownLoadServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>DownLoadServlet</servlet-name> <url-pattern>/servlet/DownLoadServlet</url-pattern> </servlet-mapping>
Click the [Download] hyperlink and submit the request to the DownLoadServlet for processing. The file download can be realized. The operation effect is shown in the following figure:
From the running results, we can see that our file download function can download files normally.