Concept and principle of file upload
Local file copy of file upload
File copy for different devices
concept
The essence is to transfer the files in one computer to another computer (server) through io stream according to the network protocol
principle
- Network communication protocol
- ip
- The corresponding device can be found in the network
- port
- The corresponding software can be found in the device
- agreement
- tcp/udp
- tcp is recommended
- Rules for interaction between devices
- ip
- socket
- Socket: includes ip and port
File upload implementation
Three elements of file upload
- The request method must be post, because there is no limit on the amount of data transmitted
- method="post"
- enctype = "multipart / form data", hybrid component submits data
- File upload item
- <input type="file" name="file"/>
- page
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>File upload</title> </head> <body> <!-- Three elements of file upload: 1,method=post 2,enctype="multipart/form-data" 3,File upload item --> <form action="${pageContext.request.contextPath}/upload" method="post" enctype="multipart/form-data"> describe:<input type="text" name="desc"><br> <!-- File upload item --> <input type="file" name="file"/><br> <button type="submit">upload</button> </form> </body> </html>
File upload background code
- rely on
- concept
- Is to upload the files in the local computer to the disk in the server
- Development steps
- Create disk file item factory object DiskFileItemFactory
- Create core resolution object ServletFileUpload
- Parse upload request
- If it is description text, print it directly
- If the file is uploaded, read and write it
@WebServlet(name = "UploadServlet", urlPatterns = "/upload") public class UploadServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 1. Create disk file item factory object DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory(); // 2. Create core resolution object ServletFileUpload servletFileUpload = new ServletFileUpload(diskFileItemFactory); try { // 3. Analyze the upload request and obtain the file item (including the uploaded file and description text) List<FileItem> fileItems = servletFileUpload.parseRequest(request); String fileName = null; String desc = null; for (FileItem fileItem : fileItems) { // Return to true, normal field; If it returns false, it is the file if (fileItem.isFormField()) { desc = fileItem.getString(); System.out.println(desc);// Chinese garbled code is solved later } else { InputStream inputStream = fileItem.getInputStream(); BufferedInputStream bis = new BufferedInputStream(inputStream); // Get the real path of the upload folder // It can also be written like this: request getServletContext(). getRealPath() String dirPath = request.getRealPath("upload"); File dirFile = new File(dirPath); if (!dirFile.exists()) { // Does not exist, create folder manually dirFile.mkdir(); } // fileItem.getName(): the name of the uploaded file String path = dirPath + File.separator + fileItem.getName(); FileOutputStream fos = new FileOutputStream(path); BufferedOutputStream bos = new BufferedOutputStream(fos); // Arrays are used to carry data byte[] bys = new byte[8192]; int len = -1; // bis. Read (bytes): read the data from the input stream and put it into the byte array while ((len = bis.read(bys)) != -1) { // Write the data of byte stream to the output stream, that is, the target file bos.write(bys, 0, len); } bos.close(); bis.close(); // Server path (Tomcat image): C: \ users \ min \ IntelliJIdea2019. 3\system\tomcat\Tomcat_ 8_ 5_ 39_ day66 // Project deployment path: D:\Users\IdeaProjects\NZ2002\laoqiu\day66\out\artifacts\day66_war_exploded/upload/a.txt } } } catch (Exception e) { e.printStackTrace(); } } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } }
After uploading, the browser can directly access: http://localhost:8080/day66/upload/a.txt
Common API for file upload
- ServletFileUpload class
- parseRequest
- Parse the request and get the file item
- setHeaderEncoding
- Solve Chinese garbled file names
- parseRequest
- FileItem class
- isFormField
- Judge whether it is an ordinary upload item. If the return value is true, it is an ordinary upload item, otherwise it is a file upload item
- getFieldName
- Get field name (name attribute in label)
- getString(String encoding)
- Gets the description text and specifies the encoding format
- getName
- Get the name of the uploaded file
- getInputStream
- Get the input stream corresponding to the uploaded file
- isFormField
- Problem solving
- Upload file name Chinese garbled code
- Chinese garbled description text
- duplication file name
@WebServlet(name = "UploadServlet", urlPatterns = "/upload") public class UploadServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory(); ServletFileUpload servletFileUpload = new ServletFileUpload(diskFileItemFactory); // Solve the problem of Chinese garbled file names servletFileUpload.setHeaderEncoding("utf-8"); try { List<FileItem> fileItems = servletFileUpload.parseRequest(request); String fileName = null; String desc = null; for (FileItem fileItem : fileItems) { if (fileItem.isFormField()) { // getString("utf-8"): solve the problem of garbled description text desc = fileItem.getString("utf-8"); } else { InputStream inputStream = fileItem.getInputStream(); BufferedInputStream bis = new BufferedInputStream(inputStream); // Take the real path: day66 in the tomcat image docBase + "upload" of XML file String dirPath = request.getRealPath("upload"); File dirFile = new File(dirPath); if (!dirFile.exists()) { dirFile.mkdir(); } // File name = current time in milliseconds + "-" + file name fileName = System.currentTimeMillis() + "-" + fileItem.getName(); String path = dirPath + File.separator + fileName; FileOutputStream fos = new FileOutputStream(path); BufferedOutputStream bos = new BufferedOutputStream(fos); byte[] bys = new byte[8192]; int len = -1; while ((len = bis.read(bys)) != -1) { bos.write(bys, 0, len); } bos.close(); bis.close(); } } } catch (Exception e) { e.printStackTrace(); } } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } }
Description of the real path of the server of idea
File upload combined with database
Background code
Bean
@Data @AllArgsConstructor @NoArgsConstructor public class MyFile { private Integer id; private String fileName; private String filePath; private String description; }
Controller
- UploadServlet
@WebServlet(name = "UploadServlet", urlPatterns = "/upload") public class UploadServlet extends HttpServlet { private FileService fileService = new FileServiceImpl(); protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory(); ServletFileUpload servletFileUpload = new ServletFileUpload(diskFileItemFactory); servletFileUpload.setHeaderEncoding("utf-8"); try { List<FileItem> fileItems = servletFileUpload.parseRequest(request); // Put it outside the loop String fileName = null; String desc = null; for (FileItem fileItem : fileItems) { if (fileItem.isFormField()) { desc = fileItem.getString("utf-8"); } else { InputStream inputStream = fileItem.getInputStream(); BufferedInputStream bis = new BufferedInputStream(inputStream); String dirPath = request.getRealPath("upload"); File dirFile = new File(dirPath); if (!dirFile.exists()) { dirFile.mkdir(); } fileName = System.currentTimeMillis() + "-" + fileItem.getName(); String path = dirPath + File.separator + fileName; FileOutputStream fos = new FileOutputStream(path); BufferedOutputStream bos = new BufferedOutputStream(fos); byte[] bys = new byte[8192]; int len = -1; while ((len = bis.read(bys)) != -1) { bos.write(bys, 0, len); } bos.close(); bis.close(); } } // After uploading successfully, save the file information (id, file name, file path, description) to the database MyFile myFile = new MyFile(); myFile.setFileName(fileName); // “ http://localhost:8080/day66/upload/ Beauty 1 Jpg "absolute path with protocol // "/ day66/upload / beauty 1.jpg" absolute path without protocol myFile.setFilePath(request.getContextPath() + File.separator + "upload" + File.separator + fileName);// /day66\upload\1618223633722-girl01.jpg myFile.setDescription(desc); fileService.addFile(myFile); response.sendRedirect("/day66/fileList"); } catch (Exception e) { e.printStackTrace(); } } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } }
- FileListServlet
@WebServlet(name = "FileListServlet", urlPatterns = "/fileList") public class FileListServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // Get the list of uploaded files FileService fileService = new FileServiceImpl(); try { List<MyFile> fileList = fileService.selectFileList(); request.setAttribute("fileList", fileList); // Jump to filelist jsp request.getRequestDispatcher("/fileList.jsp").forward(request, response); } catch (Exception e) { e.printStackTrace(); } } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } }
Service
public class FileServiceImpl implements FileService { private FileDao fileDao = new FileDaoImpl(); @Override public void addFile(MyFile myFile) throws Exception { fileDao.addFile(myFile); } @Override public List<MyFile> selectFileList() throws Exception { return fileDao.selectFileList(); } }
Dao
public class FileDaoImpl implements FileDao { @Override public void addFile(MyFile file) throws Exception { new QueryRunner(JDBCUtils.getDataSource()) .update("insert into tb_document (fileName, filePath, description) values(? ,? ,?)", file.getFileName(), file.getFilePath(), file.getDescription()); } @Override public List<MyFile> selectFileList() throws Exception { return new QueryRunner(JDBCUtils.getDataSource()) .query("select * from tb_document", new BeanListHandler<MyFile>(MyFile.class)); } }
Foreground code
Development process:
- When the file is uploaded successfully, redirect to FileListServlet
- In FileListServlet, obtain the uploaded file list, store it in request, and forward the request to filelist jsp
- upload.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>File upload</title> </head> <body> <!-- Three elements of file upload: 1,method=post 2,enctype="multipart/form-data" 3,File upload item --> <form action="${pageContext.request.contextPath}/upload" method="post" enctype="multipart/form-data"> describe:<input type="text" name="desc"><br> <!-- File upload item --> <input type="file" name="file"/><br> <button type="submit">upload</button> </form> </body> </html>
- fileList.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <html> <head> <title>File list</title> <style> a{ /* Underline */ text-decoration: none; } </style> </head> <body> <table border="1px" cellpadding="10px" cellspacing="0px"> <tr> <td>number</td> <td>File name</td> <td>Document description</td> <td>operation</td> </tr> <c:forEach items="${fileList}" var="file"> <tr> <td>${file.id}</td> <td><a href="${file.filePath}">${file.fileName}</a></td> <td>${file.description}</td> <td><a href="${pageContext.request.contextPath}/download?fileName=${file.fileName}">download</a></td> </tr> </c:forEach> </table> </body> </html>
File download
- concept
- Transfer the files in the server to the local computer through the network communication protocol
- There are two i forms of file download
- Hyperlinks
- If the browser supports this format, you can open it in the browser. If the browser does not support this format, you will be prompted to download it
- Download by writing code manually
- Hyperlinks
- step
- Set media type
- Tell the browser the type of file to download
- Operation response header "content type"
- Set download window
- Operation response header "content disposition"
- IO stream read / write
- Local input stream
- response.getOutputStream()
- Set media type
- Comparison between file upload and file download
- File download process
The page is filelist jsp
/** * File download (download is successful) * 1,Set media type (success) * 2,Set the download window (error: Chinese garbled code), and you only need to solve the garbled code * 3,IO Reading and writing (success) */ @WebServlet(name = "DownLoadServlet", urlPatterns = "/download") public class DownLoadServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // Get download file name String fileName = request.getParameter("fileName"); // 1. Set media type: tells the browser the type of file to download // Gets the media type of the downloaded file String mimeType = request.getServletContext().getMimeType(fileName); response.setContentType(mimeType); // Different browsers encode file names in different ways. Google browser, represented by utf-8, encodes file names // Some other browsers encode the file name with base64 to determine the type of browser used user agent String userAgent = request.getHeader("User-Agent"); String newFileName = null; if (userAgent.contains("Chrome")) { // Encoded in utf-8 newFileName = URLEncoder.encode(fileName, "utf-8"); } else { // base64 encoding newFileName = base64EncodeFileName(fileName); } // 2. Set the download window by operating "content disposition" response.setHeader("Content-Disposition", "attachement;filename=" + newFileName); // 3. Start IO read / write String path = request.getRealPath("upload") + File.separator + fileName; BufferedInputStream bis = new BufferedInputStream(new FileInputStream(path)); // Get the output stream corresponding to the response ServletOutputStream outputStream = response.getOutputStream(); BufferedOutputStream bos = new BufferedOutputStream(outputStream); byte[] bys = new byte[8192]; int len = -1; while ((len = bis.read(bys)) != -1) { bos.write(bys, 0, len); } bos.close(); bis.close(); } // base64 encoding public String base64EncodeFileName(String fileName) { BASE64Encoder base64Encoder = new BASE64Encoder(); try { return "=?UTF‐8?B?" + new String(base64Encoder.encode(fileName .getBytes("utf-8"))) + "?="; } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); } } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } }
User defined file upload
- concept
- Transfer the files in the local computer to the server through the network communication protocol
- File upload principle
- Sender
- Use the local input stream to read files from the local computer
- Use the output stream of network communication to transfer the content in the local input stream to the server computer
- receiving end
- Use the input stream of network communication to read the data of the uploaded file
- Use the local output stream to write out the data of the uploaded file to the file of the server
- Sender
- User defined file upload process
- User defined file upload optimization
- Question one
- The receiving end accepts the file once, and the receiving program will end
- If users need to upload files later, they will fail
- Introduce infinite loop
- Question two
- When a user uploads a large file, which takes 10 minutes, other users cannot upload files within 10 minutes
- Introducing multithreading
Receiver [server]
// When uploading files to the receiving end, run the receiving end first and then the sending end public class Receiver { // Existing problems: // 1. Files can only be uploaded once // 2. If someone uses the file upload function to upload a large file, then others can't use it // 3. Duplicate file name public static void main(String[] args) { try { // 1. Create server socket object ServerSocket serverSocket = new ServerSocket(10241); // Receive multiple while (true) { // 2. The socket object received from the sender is blocking (the program that has not been sent will wait all the time) Socket socket = serverSocket.accept();// It needs to be put in the loop new Thread() {// Anonymous object inheriting Thread @Override public void run() { // 3. Get the TCP input stream [network input stream] InputStream inputStream = null; try { inputStream = socket.getInputStream(); BufferedInputStream bis = new BufferedInputStream(inputStream); String destPath = "D:\\Users\\IdeaPro\\javacode\\javaweb03\\day66-upload-download-demo01\\out\\artifacts\\day66_upload_download_demo01_war_exploded\\upload\\" + System.currentTimeMillis() + "-copy.txt"; // 4. Use [local output stream] BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destPath)); byte[] bys = new byte[8192]; int len = -1; while ((len = bis.read(bys)) != -1) { bos.write(bys, 0, len); } bos.close(); bis.close(); } catch (Exception e) { e.printStackTrace(); } } }.start(); } } catch (Exception e) { e.printStackTrace(); } } }
Sender [Client]
// File upload sender public class Sender { public static void main(String[] args) { String path = "C:\\Users\\min\\Desktop\\a.txt"; try { // Get the input stream corresponding to the local file [local input stream] BufferedInputStream bis = new BufferedInputStream(new FileInputStream(path)); // Socket object at sender Socket socket = new Socket(InetAddress.getByName("127.0.0.1"), 10241); // [network output stream] BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream()); // Read and write, and send the file from the local computer to the server byte[] bys = new byte[8192]; int len = -1; while ((len = bis.read(bys)) != -1) { bos.write(bys, 0, len); } bos.close(); bis.close(); } catch (Exception e) { e.printStackTrace(); } } }
Start the receiver first and then the sender
Servlet single instance multithreading
- concept
- tomcat server Initialization of XML Connector in thread pool
- When a request is initiated for the first time, the thread pool will be scheduled to allocate threads to handle the request, and a servlet object will be instantiated
- When the second request is initiated, the thread pool will be dispatched again to allocate a new thread to process the request, and the previous Servlet object will be used
- Advantages: save memory expenses
- Thread safety issues
- The value of member variable will change, which has thread safety problems
- The value of member variable will not change, and there is no thread safety problem
- Local variables. Different threads hold different local variables. Therefore, there is no thread safety problem
public interface UserService { void login(); }
public class UserServiceImpl implements UserService { @Override public void login() { } }
/** * Thread safety: multiple threads can operate the same module at the same time * Static variables belong to class, also known as class variables * Member variables, which belong to objects, are also called object variables * Local variables belong to methods, also known as method variables */ @WebServlet(name = "Demo01Servlet", urlPatterns = "/demo01") public class Demo01Servlet extends HttpServlet { // Define a member variable num1 in the Servlet. If it belongs to Demo01Servlet object, it means that multiple threads hold this num1 variable at the same time // Thread 1: change num1 to 2. The doPost method enters the stack and holds a local variable num1 // Thread 2: change the num1 value to 3. The doPost method enters the stack and holds a local variable num1 // Thread 3: change the num1 value to 4. The doPost method enters the stack and holds a local variable num1 // The three num1 belong to different variables // Conclusion: it is best not to define a member variable in a Servlet // private int num1 = 1; private UserService userService = new UserServiceImpl(); protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // Local variable, belonging to method int num1 = 1; // Only userService is used without modification. It is thread safe userService.login(); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } }
advantage:
- Servlet is a single instance, which reduces the overhead of generating servlets
- The thread pool is used to respond to multiple requests, which improves the response time
Disadvantages:
- Avoid using member variables in servlets as much as possible. Because member variables belong to objects and servlets are single instances, it is equivalent that this member variable is shared by multiple threads, which has thread safety problems
Custom tomcat server
Environment is a Java se project
- Implementation principle of tomcat server
- Operation request line, request header, request body
- Operation response line, response header, response body
- Custom server
- Imitate tomcat server
- Operation request line
- Operation response line, response header, response body
- Development process
- Use the Socket input stream to read the request information sent by the browser (the request path in the request line)
- Processing request path
- Relative path processed into resources
- Use the local input stream to read the resources in the custom server
- Use the output stream of Socket to respond the data of resources to the browser
Basic Edition
/** * javase route: * Absolute path: starting from the drive letter * Relative path: starting from the current project, use relative path * index.html It's under the project */ public class MyTomcatServer { public static void main(String[] args) { try { ServerSocket serverSocket = new ServerSocket(8181); Socket socket = serverSocket.accept(); // Process the request line and obtain the path to access the resource InputStream inputStream = socket.getInputStream(); // A path is a string that converts a byte stream into a character stream InputStreamReader reader = new InputStreamReader(inputStream); // Encapsulate into an efficient character stream BufferedReader bufferedReader = new BufferedReader(reader); String line = bufferedReader.readLine(); // GET /day67/index.html HTTP/1.1 // Request mode, request path and protocol; Only the request path is useful // Take the request path from line String[] requestInfos = line.split(" "); String requestURL = requestInfos[1]; // /day67/index.html // Get resources according to the path int length = "/day67/".length(); // Gets the relative path of the requested resource requestURL = requestURL.substring(length); // Index HTML read out BufferedInputStream bis = new BufferedInputStream(new FileInputStream(requestURL)); // Index. Through the server HTML response to browser // Body action response OutputStream outputStream = socket.getOutputStream(); // Efficient BufferedOutputStream bos = new BufferedOutputStream(outputStream); // The action response line must be preceded by the action response body // Operation response line (protocol, response status code) bos.write("HTTP/1.1 200 OK\r\n".getBytes()); // Operation response header (content type) bos.write("Content-Type:text/html\r\n".getBytes()); bos.write("\r\n".getBytes()); // Reading and writing int len = -1; byte[] bys = new byte[8192]; while ((len = bis.read(bys)) != -1) { bos.write(bys, 0, len); } bos.close(); bis.close(); } catch (Exception e) { e.printStackTrace(); } } }
index. Under the path of HTML project (JavaSE project), click http://localhost:8181/day67/index.html visit
Existing problems:
- The server can only receive requests once
- The server is a single thread. If a single operation takes too long, subsequent operations will be blocked
Solution:
- Join infinite loop
- Join multithreading
Optimized version
So index The resources under HTML can be accessed
public class MyTomcatServer { public static void main(String[] args) { try { ServerSocket serverSocket = new ServerSocket(8181); while (true) { // Blocking thread // When there is no request, block this code and no thread will be created // If you put it into a thread, it will create a thread crazily, even if there is no request Socket socket = serverSocket.accept(); new Thread() { @Override public void run() { try { // Conversion flow - > efficient flow BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream())); String line = bufferedReader.readLine(); String[] requestInfos = line.split(" "); String requestURL = requestInfos[1]; int length = "/day67/".length(); requestURL = requestURL.substring(length); // Think of this project as a tomcat container // Index HTML [use local IO stream relative to the server] BufferedInputStream bis = new BufferedInputStream(new FileInputStream(requestURL)); // Index. Through the server HTML response to browser [use network IO stream relative to browser] BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream()); // Writes the specified byte to the buffered output stream bos.write("HTTP/1.1 200 OK\r\n".getBytes()); bos.write("Content-Type:text/html\r\n".getBytes()); bos.write("\r\n".getBytes()); int len = -1; byte[] bys = new byte[8192]; while ((len = bis.read(bys)) != -1) { bos.write(bys, 0, len); } bos.close(); bis.close(); } catch (Exception e) { e.printStackTrace(); } } }.start(); } } catch (Exception e) { e.printStackTrace(); } } }
- index.html page
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>home page</title> <link rel="shortcut icon" href="/day67/favicon.ico" /> <link rel="bookmark" href="/day67/favicon.ico" type="image/x-icon" /> </head> <body> Home page <img src="girl01.jpg"> <img src="girl02.jpg"> </body> </html>