javaweb-39:文件上传及拓展鸡汤
文件上傳核心代碼:
FileServlet.java
package com.gongyi.servlet;import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload;import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.List; import java.util.UUID;public class FileServlet extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {try {//判斷上傳的文件是普通表單還是帶文件的表單if (!ServletFileUpload.isMultipartContent(request)) {return;//終止方法運(yùn)行,說(shuō)明這是一個(gè)普通的表單,直接返回}//創(chuàng)建上傳文件的保存路徑,建議放在WEB-INF路徑下,安全,用戶無(wú)法直接訪問(wèn)上傳的文件String uploadPath = this.getServletContext().getRealPath("/WEB-INF/upload");File uploadFile = new File(uploadPath);if (!uploadFile.exists()) {uploadFile.mkdir();//創(chuàng)建這個(gè)目錄}//緩存,臨時(shí)文件//臨時(shí)路徑,假如文件超過(guò)了預(yù)期的大小,我們就把他放到一個(gè)臨時(shí)文件中,過(guò)幾天自動(dòng)刪除,或者提醒用戶轉(zhuǎn)存為永久String tmpPath = this.getServletContext().getRealPath("/WEB-INF/tmp");File file = new File(tmpPath);if (!file.exists()) {file.mkdir();//創(chuàng)建這個(gè)臨時(shí)目錄}//處理上傳的文件,一般都需要通過(guò)流來(lái)獲取,我們可以使用request.getInputStream(),原生態(tài)的文件上傳流獲取,十分麻煩//但是我們都建議使用Apache的文件上傳組件來(lái)實(shí)現(xiàn),commons-fileupload,它需要依賴于commons-io組件/*** ServletFileUpload負(fù)責(zé)上傳的文件數(shù)據(jù),并將表單中每個(gè)輸入項(xiàng)封裝成一個(gè)FileItem對(duì)象* 在使用ServletFileUpload對(duì)象解析請(qǐng)求時(shí),需要DiskFileItemFactory對(duì)象* 所以,我們需要在進(jìn)行解析工作前,構(gòu)造好DiskFileItemFactory對(duì)象* 通過(guò)ServletFileUpload對(duì)象的構(gòu)造方法或setFileItemFactory()方法設(shè)置ServletFileUpload對(duì)象的fileItemFactory屬性*///1.創(chuàng)建DiskFileItemFactory對(duì)象,處理文件上傳路徑或者大小限制的DiskFileItemFactory factory = new DiskFileItemFactory();/*//通過(guò)這個(gè)工廠設(shè)置一個(gè)緩沖區(qū),當(dāng)上傳的文件大于這個(gè)緩沖區(qū)的時(shí)候,將它放到臨時(shí)文件中factory.setSizeThreshold(1024 * 1024);//緩沖區(qū)大小為1Mfactory.setRepository(file);//臨時(shí)文件的保存目錄,需要一個(gè)File*///2.獲取ServletFileUploadServletFileUpload upload = new ServletFileUpload(factory);/*//監(jiān)聽文件上傳進(jìn)度upload.setProgressListener(new ProgressListener() {@Override//pBytesRead:已經(jīng)讀取到的文件大小//pContentLength:文件大小public void update(long pBytesRead, long pContentLength, int pItems) {System.out.println("總大小:"+pContentLength+",已上傳:"+pBytesRead);}});//處理亂碼問(wèn)題upload.setHeaderEncoding("UTF-8");//設(shè)置單個(gè)文件的最大值upload.setFileSizeMax(1024*1024*10);//設(shè)置總共能夠上傳文件的大小//1024 = 1kb * 1024 = 1M * 10 = 10Mupload.setSizeMax(1024*1024*10);*///3.處理上傳的文件//把前端請(qǐng)求解析,封裝成一個(gè)FileItem對(duì)象,需要從ServletFileUpload對(duì)象中獲取List<FileItem> fileItems = upload.parseRequest(request);//fileItem每一個(gè)表單對(duì)象for (FileItem fileItem : fileItems) {//判斷上傳的文件是普通的表單還是帶文件的表單if (fileItem.isFormField()) {//getFieldName指的是前端表單控件的nameString name = fileItem.getFieldName();String value = fileItem.getString("UTF-8");//處理亂碼System.out.println(name + ":" + value);} else {//文件//============================處理文件==================================String uploadFileName = fileItem.getName();//可能存在文件名不合法的情況if (uploadFileName.trim().equals("") || uploadFileName == null) {continue;}//獲得上傳的文件名 /images/girl/beauty.pngString fileName = uploadFileName.substring(uploadFileName.lastIndexOf("/") + 1);//獲得文件的后綴名String fileExtName = uploadFileName.substring(uploadFileName.lastIndexOf(".") + 1);/*** 如果文件后綴名fileExtName 不是我們所需要的* 就直接return,不處理,告訴用戶文件類型不對(duì)*///可以使用UUID(唯一識(shí)別的通用碼),保證文件名唯一//UUID.randomUUID();隨機(jī)生成一個(gè)唯一識(shí)別的通用碼//網(wǎng)絡(luò)傳輸中的東西,都需要序列化//POJO,實(shí)體類,如果想要在多個(gè)電腦上運(yùn)行,傳輸===>需要把對(duì)象序都列化了//JNI = Java Native Interface//implements Serializable:標(biāo)記接口,JVM--> Java棧 本地方法棧 native --> C++String uuidPath = UUID.randomUUID().toString();//============================存放地址==================================//存到哪?uploadPath//文件真實(shí)存在的路徑 realPathString realPath = uploadPath + "/" + uuidPath;//給每一個(gè)文件創(chuàng)建一個(gè)對(duì)應(yīng)的文件夾File realPathFile = new File(realPath);if (!realPathFile.exists()) {realPathFile.mkdir();}//============================文件傳輸==================================//獲得文件上傳的流InputStream inputStream = fileItem.getInputStream();//創(chuàng)建一個(gè)文件輸出流//realPath = 真實(shí)的文件夾//差了一個(gè)文件,加上輸出文件的名字+"/"+uuidFileNameFileOutputStream fos = new FileOutputStream(realPath + "/" + fileName);//創(chuàng)建一個(gè)緩沖區(qū)byte[] buffer = new byte[1024 * 1024];//判斷是否讀取完畢int len = 0;//如果大于0,說(shuō)明還存在數(shù)據(jù)while ((len = inputStream.read(buffer)) > 0) {fos.write(buffer, 0, len);}//關(guān)閉流fos.close();inputStream.close();String msg = "文件上傳成功";fileItem.delete();//上傳成功,清除臨時(shí)文件//servlet請(qǐng)求轉(zhuǎn)發(fā)消息request.setAttribute("msg", msg);request.getRequestDispatcher("info.jsp").forward(request, response);}}} catch (Exception e) {e.printStackTrace();}}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws javax.servlet.ServletException, IOException {} }web.xml:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"version="4.0"><servlet><servlet-name>FileServlet</servlet-name><servlet-class>com.gongyi.servlet.FileServlet</servlet-class></servlet><servlet-mapping><servlet-name>FileServlet</servlet-name><url-pattern>/upload.do</url-pattern></servlet-mapping> </web-app>index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html><head><title>$Title$</title></head><body><%--通過(guò)表單上傳文件get:上傳文件大小有限制post:上傳文件大小無(wú)限制--%><%--${pageContext.request.contextPath} 獲取服務(wù)器路徑--%><form action="${pageContext.request.contextPath}/upload.do" method="post" enctype="multipart/form-data">上傳用戶:<input type="text" name="username"><br/><p><input type="file" name="file1"></p><p><input type="file" name="file1"></p><p><input type="submit">|<input type="reset"></p></form></body> </html>info.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html><head><title>Title</title></head><body>${msg}</body> </html>FileServlet.java【優(yōu)化后,提取了方法】
package com.gongyi.servlet;import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.FileUploadException; import org.apache.commons.fileupload.ProgressListener; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload;import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.List; import java.util.UUID;public class FileServlet extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {try {//判斷上傳的文件是普通表單還是帶文件的表單if (!ServletFileUpload.isMultipartContent(request)) {return;//終止方法運(yùn)行,說(shuō)明這是一個(gè)普通的表單,直接返回}//創(chuàng)建上傳文件的保存路徑,建議放在WEB-INF路徑下,安全,用戶無(wú)法直接訪問(wèn)上傳的文件String uploadPath = this.getServletContext().getRealPath("/WEB-INF/upload");File uploadFile = new File(uploadPath);if (!uploadFile.exists()) {uploadFile.mkdir();//創(chuàng)建這個(gè)目錄}//緩存,臨時(shí)文件//臨時(shí)路徑,假如文件超過(guò)了預(yù)期的大小,我們就把他放到一個(gè)臨時(shí)文件中,過(guò)幾天自動(dòng)刪除,或者提醒用戶轉(zhuǎn)存為永久String tmpPath = this.getServletContext().getRealPath("/WEB-INF/tmp");File file = new File(tmpPath);if (!file.exists()) {file.mkdir();//創(chuàng)建這個(gè)臨時(shí)目錄}//處理上傳的文件,一般都需要通過(guò)流來(lái)獲取,我們可以使用request.getInputStream(),原生態(tài)的文件上傳流獲取,十分麻煩//但是我們都建議使用Apache的文件上傳組件來(lái)實(shí)現(xiàn),commons-fileupload,它需要依賴于commons-io組件/*** ServletFileUpload負(fù)責(zé)上傳的文件數(shù)據(jù),并將表單中每個(gè)輸入項(xiàng)封裝成一個(gè)FileItem對(duì)象* 在使用ServletFileUpload對(duì)象解析請(qǐng)求時(shí),需要DiskFileItemFactory對(duì)象* 所以,我們需要在進(jìn)行解析工作前,構(gòu)造好DiskFileItemFactory對(duì)象* 通過(guò)ServletFileUpload對(duì)象的構(gòu)造方法或setFileItemFactory()方法設(shè)置ServletFileUpload對(duì)象的fileItemFactory屬性*///1.創(chuàng)建DiskFileItemFactory對(duì)象,處理文件上傳路徑或者大小限制的DiskFileItemFactory factory = getDiskFileItemFactory(file);//2.獲取ServletFileUploadServletFileUpload upload = getServletFileUpload(factory);//3.處理上傳的文件String msg = uploadParseRequest(upload, request, uploadPath);//servlet請(qǐng)求轉(zhuǎn)發(fā)消息request.setAttribute("msg", msg);request.getRequestDispatcher("info.jsp").forward(request, response);} catch (Exception e) {e.printStackTrace();}}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws javax.servlet.ServletException, IOException {}public static DiskFileItemFactory getDiskFileItemFactory(File file) {DiskFileItemFactory factory = new DiskFileItemFactory();//通過(guò)這個(gè)工廠設(shè)置一個(gè)緩沖區(qū),當(dāng)上傳的文件大于這個(gè)緩沖區(qū)的時(shí)候,將它放到臨時(shí)文件中factory.setSizeThreshold(1024 * 1024);//緩沖區(qū)大小為1Mfactory.setRepository(file);//臨時(shí)文件的保存目錄,需要一個(gè)Filereturn factory;}public static ServletFileUpload getServletFileUpload(DiskFileItemFactory factory) {ServletFileUpload upload = new ServletFileUpload(factory);//設(shè)置編碼upload.setHeaderEncoding("UTF-8");//監(jiān)聽文件上傳進(jìn)度upload.setProgressListener(new ProgressListener() {@Override//pBytesRead:已經(jīng)讀取到的文件大小//pContentLength:文件大小public void update(long pBytesRead, long pContentLength, int pItems) {System.out.println("總大小:" + pContentLength + ",已上傳:" + pBytesRead);}});//處理亂碼問(wèn)題upload.setHeaderEncoding("UTF-8");//設(shè)置單個(gè)文件的最大值upload.setFileSizeMax(1024 * 1024 * 10);//設(shè)置總共能夠上傳文件的大小//1024 = 1kb * 1024 = 1M * 10 = 10Mupload.setSizeMax(1024 * 1024 * 10);return upload;}public static String uploadParseRequest(ServletFileUpload upload, HttpServletRequest request, String uploadPath) throws IOException, FileUploadException {//把前端請(qǐng)求解析,封裝成一個(gè)FileItem對(duì)象,需要從ServletFileUpload對(duì)象中獲取List<FileItem> fileItems = upload.parseRequest(request);//fileItem每一個(gè)表單對(duì)象String msg = "上傳失敗";for (FileItem fileItem : fileItems) {//判斷上傳的文件是普通的表單還是帶文件的表單if (fileItem.isFormField()) {//getFieldName指的是前端表單控件的nameString name = fileItem.getFieldName();String value = fileItem.getString("UTF-8");//處理亂碼System.out.println(name + ":" + value);} else {//文件//============================處理文件==================================String uploadFileName = fileItem.getName();//可能存在文件名不合法的情況if (uploadFileName.trim().equals("") || uploadFileName == null) {continue;}//獲得上傳的文件名 /images/girl/beauty.pngString fileName = uploadFileName.substring(uploadFileName.lastIndexOf("/") + 1);//獲得文件的后綴名String fileExtName = uploadFileName.substring(uploadFileName.lastIndexOf(".") + 1);/*** 如果文件后綴名fileExtName 不是我們所需要的* 就直接return,不處理,告訴用戶文件類型不對(duì)*///可以使用UUID(唯一識(shí)別的通用碼),保證文件名唯一//UUID.randomUUID();隨機(jī)生成一個(gè)唯一識(shí)別的通用碼//網(wǎng)絡(luò)傳輸中的東西,都需要序列化//POJO,實(shí)體類,如果想要在多個(gè)電腦上運(yùn)行,傳輸===>需要把對(duì)象序都列化了//JNI = Java Native Interface//implements Serializable:標(biāo)記接口,JVM--> Java棧 本地方法棧 native --> C++String uuidPath = UUID.randomUUID().toString();//============================存放地址==================================//存到哪?uploadPath//文件真實(shí)存在的路徑 realPathString realPath = uploadPath + "/" + uuidPath;//給每一個(gè)文件創(chuàng)建一個(gè)對(duì)應(yīng)的文件夾File realPathFile = new File(realPath);if (!realPathFile.exists()) {realPathFile.mkdir();}//============================文件傳輸==================================//獲得文件上傳的流InputStream inputStream = fileItem.getInputStream();//創(chuàng)建一個(gè)文件輸出流//realPath = 真實(shí)的文件夾//差了一個(gè)文件,加上輸出文件的名字+"/"+uuidFileNameFileOutputStream fos = new FileOutputStream(realPath + "/" + fileName);//創(chuàng)建一個(gè)緩沖區(qū)byte[] buffer = new byte[1024 * 1024];//判斷是否讀取完畢int len = 0;//如果大于0,說(shuō)明還存在數(shù)據(jù)while ((len = inputStream.read(buffer)) > 0) {fos.write(buffer, 0, len);}//關(guān)閉流fos.close();inputStream.close();msg = "文件上傳成功";fileItem.delete();//上傳成功,清除臨時(shí)文件}}return msg;} }彩蛋
1.*.do的前世今生
與structs命名有關(guān)系
2.普通web工程,右鍵可以直接新建servlet
導(dǎo)入依賴
3.常見(jiàn)面試題大類
1)字符串操作
2)算法
4.代碼如果大于50行,一個(gè)屏幕放不下,就考慮抽象提取出方法了
5.java中的float,double不精確【離散,大約數(shù),可以從操作系統(tǒng)原理的底層存儲(chǔ)解釋:010101010】,
一般用BigDecimal替代
常見(jiàn)問(wèn)題:
float f = 0.1; double d = 1.0/10; System.out.println(f==d);//false6.UUID Demo
package com.gongyi.servlet;import java.util.UUID;public class TestUUID {public static void main(String[] args) {String uuidPath = UUID.randomUUID().toString();String uuidPath1 = UUID.randomUUID().toString();String uuidPath2 = UUID.randomUUID().toString();String uuidPath3 = UUID.randomUUID().toString();System.out.println(uuidPath);System.out.println(uuidPath1);System.out.println(uuidPath2);System.out.println(uuidPath3);} }7.多線程Demo(用lamda表達(dá)式實(shí)現(xiàn))
package com.gongyi.servlet;public class TestThread {public static void main(String[] args) {new Thread(() -> {System.out.println("Hello,World");}).start();} }8.回顧Java關(guān)鍵字
JNI:
9.idea的普通web工程部署后,在左側(cè)的project視圖下看不到輸出文件夾out,在show explorer下可以看到
應(yīng)該是于empty project有關(guān)系,它在empty project根目錄下
10.運(yùn)行過(guò)程中遇到問(wèn)題:
1)java.lang.NullPointerException: No FileItemFactory has been set.
// Create a new file upload handler ServletFileUpload upload = new ServletFileUpload(factory);在構(gòu)建 ServletFileUpload時(shí),應(yīng)該把factory作為參數(shù)傳遞過(guò)去
2)java.io.FileNotFoundException: org.apache.commons.fileupload.servlet.ServletFileUpload@5207bdd5\883a38d0-bcff-4a99-8172-f65d6ebef2d9\Java面試題�?�結(jié):基�?及語(yǔ)法篇169�?.pdf (??�?���?����·����)
懷疑是中文導(dǎo)致,上傳英文文件名文件
java.io.FileNotFoundException: org.apache.commons.fileupload.servlet.ServletFileUpload@6e80778f\c4ec939e-55aa-4f22-905d-ccd59e92ffe6\SpringMVC.md (??�?���?����·����)
發(fā)現(xiàn)代碼寫錯(cuò)了
原來(lái):
現(xiàn)在:
String uploadPath = this.getServletContext().getRealPath("/WEB-INF/upload"); String realPath = uploadPath + "/" + uuidPath;3)上傳時(shí),console和目標(biāo)文件夾中文文件名亂碼
debug代碼,發(fā)現(xiàn)文件名取值就亂碼了:
針對(duì)文件加下編碼處理應(yīng)該就行了:
原來(lái)代碼:
String uploadFileName = fileItem.getName();現(xiàn)在代碼,加上如下代碼:
//設(shè)置編碼 upload.setHeaderEncoding("UTF-8");參考教程
4)console中文亂碼
在tomcat的vm options添加如下:
-Dfile.encoding=UTF-8總結(jié)
以上是生活随笔為你收集整理的javaweb-39:文件上传及拓展鸡汤的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Ubuntu查看USB串口号【简单、好记
- 下一篇: C++调用JSON-CPP库实现JSON