1. ภาพรวมการอัปโหลดไฟล์
ในการรับรู้ฟังก์ชั่นการอัปโหลดไฟล์ในการพัฒนาเว็บจำเป็นต้องมีสองขั้นตอน:
1. เพิ่มอัปโหลดรายการอินพุตไปยังหน้าเว็บ
<form action = "#" method = "post" enctype = "multipart/form-data"> <input type = "file" name = "filename1"/> <br> <input type = "file" name = "filename2"/> <br> หลังจากตั้งค่าค่านี้เมื่อเบราว์เซอร์อัปโหลดไฟล์มันจะแนบข้อมูลไฟล์กับตัวข้อความคำขอ HTTP และใช้โปรโตคอล MIME เพื่ออธิบายไฟล์ที่อัปโหลดเพื่ออำนวยความสะดวกให้กับตัวรับสัญญาณเพื่อแยกวิเคราะห์และประมวลผลข้อมูลที่อัปโหลด 3. แอตทริบิวต์ชื่อของอินพุตจะต้องตั้งค่ามิฉะนั้นเบราว์เซอร์จะไม่ส่งข้อมูลไฟล์ที่อัปโหลด -
2. อ่านไฟล์อัปโหลดไฟล์ใน servlet และบันทึกลงในฮาร์ดดิสก์เซิร์ฟเวอร์
วัตถุคำขอมีวิธีการ GetInputStream ซึ่งสามารถอ่านข้อมูลที่ส่งข้อมูลโดยไคลเอนต์ อย่างไรก็ตามเนื่องจากผู้ใช้อาจอัปโหลดหลายไฟล์ในเวลาเดียวกันจึงเป็นงานที่ลำบากมากในการโปรแกรมและอ่านข้อมูลที่อัปโหลดโดยตรงทางด้าน servlet และแยกวิเคราะห์ข้อมูลไฟล์ที่เกี่ยวข้องแยกกัน
ตัวอย่างเช่นต่อไปนี้เป็นเนื้อหาบางส่วนของโปรโตคอล HTTP ของคำขอที่ส่งโดยเบราว์เซอร์ที่สกัดกั้นเมื่ออัปโหลดไฟล์:
ยอมรับภาษา: zh-hans-cn, zh-hans; q = 0.5content-type: multipart/form-data; ขอบเขต = --------------------------- 7DFA01D1908A4UA-CPU: AMD64Accept-Encoding: GZIP, deflateUser-Agent: Mozilla/5.0 (Windows NT 6.2; Win64; x64; Trident/7.0; RV: 11.0) Keep-AlivePragma: No-Cachecookie: JSessionId = 11Ceff8E271ab62CE676B5A87B746B5F ----------------------------- 7DFA01D1908A4CONTENT-DISPOSITION: FORM-DATA; NAME = "ชื่อผู้ใช้" Zhangsan ----------------------------- 7DFA01D1908A4CONTENT-DISPOSITION: FORM-DATA; name = "userPass" 1234 ----------------------------- 7DFA01D1908A4CONTENT-DISPOSITION: FORM-DATA; name = "filename1"; filename = "c: /users/asus/desktop/upload.txt" เนื้อหาประเภท: ข้อความ/plainthis เป็นเนื้อหาไฟล์แรก! --------------------------------------------------------------------------------------------- 7DFA01D1908A4CONTENT-DISPOSITION name = "filename1"; filename = "c: /users/asus/desktop/upload2.txt" เนื้อหาประเภท: ข้อความ/plainthis เป็นเนื้อหาไฟล์ที่สอง! สวัสดี --------------------------------------------------------------
นอกจากนี้ยังสามารถเห็นได้จากข้อมูลข้างต้นว่าเป็นการยากที่จะเขียนโปรแกรมที่แข็งแกร่งและมีเสถียรภาพหากคุณแบ่งและอ่านข้อมูลด้วยตนเอง ดังนั้นเพื่ออำนวยความสะดวกให้ผู้ใช้ในการประมวลผลข้อมูลการอัปโหลดองค์กร Apache Open Source จัดเตรียมส่วนประกอบโอเพ่นซอร์ส (Commons-FilePilePload) ที่ใช้ในการประมวลผลการอัปโหลดไฟล์แบบฟอร์ม ส่วนประกอบนี้มีประสิทธิภาพที่ยอดเยี่ยมและ API นั้นใช้งานง่ายมากช่วยให้นักพัฒนาสามารถใช้ฟังก์ชั่นการอัปโหลดเว็บไฟล์ได้อย่างง่ายดาย ดังนั้นในการพัฒนาเว็บฟังก์ชั่นการอัปโหลดไฟล์มักจะใช้งานโดยใช้คอมโพเนนต์คอมมอนส์-ฟิลด์อัปโหลด
ต้องนำเข้าแพ็คเกจสองขวด: Commons-Fileupload, Commons-io
Response.SetContentType ("ข้อความ/html; charset = utf-8"); // ตั้งค่าการร้องขอการเข้ารหัสการตอบสนองการตอบสนอง Setcharacterencoding ("UTF-8"); PrintWriter Writer = Response.getWriter (); // รับการตอบกลับ output stream servletInputStream inputstream = request.getInputStream (); // รับการร้องขอสตรีมอินพุต/** 1. สร้างวัตถุ diskfileitemfactory ตั้งค่าบัฟเฟอร์และไดเรกทอรีไฟล์ชั่วคราว Sizethreshold พารามิเตอร์นี้ตั้งค่าขนาดของบัฟเฟอร์หน่วยความจำค่าเริ่มต้นคือ 10k เมื่อไฟล์อัปโหลดมีขนาดใหญ่กว่าขนาดบัฟเฟอร์ส่วนประกอบ fileupload จะอัปโหลดไฟล์โดยใช้แคชไฟล์ชั่วคราว* @param java.io.file repository พารามิเตอร์นี้ระบุไดเรกทอรีไฟล์ชั่วคราวค่าเริ่มต้นคือ System.getProperty * * หากใช้ตัวสร้างที่ไม่มีพารามิเตอร์ SetSizEthReshold (int sizethreshold), setRepository (java.io.file repository) * วิธีการถูกตั้งค่าด้วยตนเอง */ diskfileitemfactory โรงงาน = ใหม่ diskfileitemfactory (); int sizethreshold = 1024*1024; Factory.SetSizEthreshold (Sizethreshold); ไฟล์ Repository = ไฟล์ใหม่ (request.getSession (). getServletContext (). getRealPath ("temp")); // system.out.println (request.getSession (). getServletContext (). getRealPath ("temp")); // system.out.println Factory.SetRepository (ที่เก็บ); / * * 2. ใช้วัตถุ DiskFileItemFactory เพื่อสร้างวัตถุ ServletFileUpload และตั้งค่าขนาดของไฟล์ที่อัปโหลด * * วัตถุ ServletFilePilePload มีหน้าที่ในการประมวลผลข้อมูลไฟล์ที่อัปโหลด ตรวจสอบว่าแบบฟอร์มที่อัปโหลดนั้นเป็นแบบหลายส่วน/รูปแบบ Data* list parserequest (คำขอ); แยกวิเคราะห์วัตถุคำขอห่อแต่ละรายการอินพุตในแบบฟอร์มลงในวัตถุ FileItem และส่งคืนคอลเลกชันรายการที่บันทึก fileItems ทั้งหมด* เป็นโมฆะ setFilesizeMax (Long filesizemax); ตั้งค่าสูงสุดของไฟล์ที่อัปโหลดเพียงครั้งเดียว* void setSizeMax (Long Sizemax); ตั้งค่าสูงสุดของจำนวนทั้งหมดของ Wenjiang* void setheaderencoding (); ตั้งค่ารูปแบบการเข้ารหัสเพื่อแก้ปัญหาของรหัสการอัพโหลดชื่อไฟล์ที่อ่านไม่ออก*/ servletFileUpload อัปโหลด = ใหม่ servletFileUpload (โรงงาน); Upload.SetheAderencoding ("UTF-8"); // ตั้งค่ารูปแบบการเข้ารหัสเพื่อแก้ปัญหาของรหัสที่อ่านไม่ได้ชื่อไฟล์/** 3. โทรหาวิธี servletFilePilePar.parserequest เพื่อแยกวัตถุคำขอและรับวัตถุรายการที่บันทึกเนื้อหาที่อัปโหลดทั้งหมด*/list <fileitem ลอง {parSerequest = upload.parserequest (คำขอ); } catch (fileuploadexception e) {e.printstacktrace (); } / * * 4. วนซ้ำรายการ แต่ละวัตถุ iterate a fileitem ให้เรียกใช้วิธี isformfield ของมันเพื่อตรวจสอบว่าเป็นไฟล์อัปโหลด* จริงหมายความว่าเป็นฟิลด์ฟอร์มปกติจากนั้นเรียกใช้วิธี getfieldName และ getString เพื่อรับชื่อฟิลด์และค่าฟิลด์ วิธีการของวัตถุนี้คือ: * บูลีน isformfield (); กำหนดว่า FileItem เป็นวัตถุอัพโหลดไฟล์หรือวัตถุแบบฟอร์มปกติ * จริงหมายถึงฟิลด์ฟอร์มปกติ * จากนั้นเรียกใช้วิธี getFieldName และ getString เพื่อรับชื่อฟิลด์และค่าฟิลด์ * เท็จเป็นไฟล์อัปโหลด * จากนั้นเรียก getName () เพื่อรับชื่อไฟล์ของไฟล์อัปโหลด หมายเหตุ: เบราว์เซอร์บางตัวพกพาเส้นทางไคลเอนต์และจำเป็นต้องลบตัวเอง * การเรียกใช้วิธี getInputStream () เพื่อรับกระแสข้อมูลอินพุตข้อมูลเพื่ออ่านข้อมูลการอัปโหลด * ลบ (); หมายความว่าหลังจากปิดสตรีมอินพุต FileItem ลบไฟล์ชั่วคราวจะถูกลบ */สำหรับ (fileitem fileitem: parserequest) {if (fileitem.isformfield ()) {// หมายถึงฟิลด์ปกติถ้า ("ชื่อผู้ใช้" .equals (fileItem.getFieldName ()))) {String username = fileItem.getString (); writer.write ("ชื่อผู้ใช้ของคุณ:"+ชื่อผู้ใช้+"<br>"); } if ("userPass" .equals (fileItem.getFieldName ()))) {string userPass = fileItem.getString (); writer.write ("รหัสผ่านของคุณ:"+userpass+"<br>"); }} else {// หมายถึงไฟล์ที่อัปโหลด // ไฟล์ที่อัปโหลดโดยเบราว์เซอร์ที่แตกต่างกันอาจมีชื่อพา ธ และคุณต้องตัดสตริง clientName = fileItem.getName (); String filename = ""; if (clientName.contains ("//")) {// ถ้า "/" หมายถึงชื่อที่มีพา ธ ชื่อไฟล์สุดท้ายจะถูกสกัดกั้นชื่อไฟล์ = clientName.substring (clientName.lastindexof ("//")) Substring (1); } else {filename = clientName; } uuid randomuuid = uuid.randomuuid (); // สร้างชื่อตัวระบุตัวระบุที่ไม่ซ้ำกันทั่วโลก 128 บิต = apuraluuid.toString ()+ชื่อไฟล์; / * * ออกแบบอัลกอริทึมการสร้างไดเรกทอรี หากจำนวนไฟล์ทั้งหมดที่อัปโหลดโดยผู้ใช้คือคำสั่งซื้อของคำสั่งซื้อหลายล้านครั้งหรือมากกว่าการใส่ไว้ในไดเรกทอรีเดียวกันทำให้ดัชนีไฟล์ช้ามาก * ดังนั้นจึงจำเป็นอย่างยิ่งที่จะต้องออกแบบโครงสร้างไดเรกทอรีเพื่อจัดเก็บไฟล์ในลักษณะที่กระจัดกระจายและการแปลงอัลกอริทึมแฮช UUID เป็นช่วงที่เล็กกว่า * แปลง HashCode ของ UUID เป็น 8 บิต EG OCTAL โครงสร้างไดเรกทอรีที่มีประสิทธิภาพมากสำหรับทั้งเซิร์ฟเวอร์และระบบปฏิบัติการ*/ int hashuuid = randomuuid.hashCode (); สตริง hexuuid = integer.tohexstring (hashuuid); //system.out.println(hexuuid); // รับเส้นทางที่แน่นอนซึ่งโฟลเดอร์ที่จะจัดเก็บไฟล์ที่อัปโหลดในสตริง filePath = request.getSession (). getServletContext (). getRealPath ("อัปโหลด"); สำหรับ (Char C: hexuuid.tochararray ()) {filepath = filepath+"/"+c; } // หากไดเรกทอรีไม่มีอยู่ให้สร้างไฟล์ไดเรกทอรีระดับแปดไฟล์ filePathFile = ไฟล์ใหม่ (filePath); if (! filepathfile.exists ()) {firepathfile.mkdirs (); } // อ่านไฟล์จากสตรีมอินพุตคำขอและเขียนไปยังเซิร์ฟเวอร์ inputStream inputStream2 = fileItem.getInputStream (); // สร้างไฟล์บนไฟล์ Server Side File = ไฟล์ใหม่ (FilePath+"/"+ชื่อไฟล์); bufferedOutputStream bos = ใหม่ bufferedOutputStream (ใหม่ fileOutputStream (ไฟล์)); ไบต์ [] บัฟเฟอร์ = ไบต์ใหม่ [10*1024]; int len = 0; ในขณะที่ ((len = inputstream2.read (บัฟเฟอร์, 0, 10*1024))! =-1) {bos.write (บัฟเฟอร์, 0, len); } writer.write ("คุณอัปโหลดไฟล์"+clientName+"สำเร็จ <br>"); // ปิดทรัพยากร bos.close (); InputStream2.close (); }} // โปรดทราบว่าไฟล์ที่อัปโหลดของ Eclipse ถูกบันทึกไว้ในไดเรกทอรีที่ทำงานของโครงการไม่ใช่ในไดเรกทอรีโครงการในเวิร์กสเปซ2. ปัญหาที่ต้องการความสนใจเป็นพิเศษในการอัปโหลดไฟล์: (ปัญหาเหล่านี้ทั้งหมดมีวิธีแก้ปัญหาง่าย ๆ ในรหัสข้างต้น)
1. สถานที่จัดเก็บไฟล์
เพื่อให้แน่ใจว่าความปลอดภัยของเซิร์ฟเวอร์ไฟล์ที่อัปโหลดควรถูกบันทึกไว้ในไดเรกทอรี Web-Inf ของแอปพลิเคชันหรือไดเรกทอรีที่ไม่ได้จัดการโดยเว็บเซิร์ฟเวอร์ หากผู้ใช้อัปโหลดไฟล์ด้วยรหัสปฏิบัติการเช่นไฟล์ JSP และเข้าถึงได้ตามเส้นทางการเข้าถึงการประกบเขาสามารถทำอะไรก็ได้ทางฝั่งเซิร์ฟเวอร์
2. เพื่อป้องกันไม่ให้ผู้ใช้หลายคนอัพโหลดไฟล์ด้วยชื่อไฟล์เดียวกันส่งผลให้มีการแทนที่ไฟล์ไฟล์อัปโหลด ไฟล์ควรตรวจสอบให้แน่ใจว่าไฟล์ที่อัปโหลดมีชื่อไฟล์ที่ไม่ซ้ำกัน
เปลี่ยนชื่อโดยใช้ชื่อไฟล์ UUID + User Upload
เกี่ยวกับ uuid:
UUID (ตัวระบุที่ไม่ซ้ำกันในระดับสากล) ตัวระบุที่ไม่ซ้ำกันทั่วโลกหมายถึงจำนวนที่สร้างขึ้นบนเครื่องซึ่งทำให้มั่นใจได้ว่ามันเป็นเอกลักษณ์ของเครื่องจักรทั้งหมดในเวลาและพื้นที่เดียวกัน ตามมาตรฐานที่กำหนดโดย Open Software Foundation (OSF), ที่อยู่การ์ดอีเธอร์เน็ต, เวลานาโนวินาที, รหัสรหัสชิปและจำนวนที่เป็นไปได้มากมาย ประกอบด้วยการรวมกันของส่วนต่อไปนี้: วันที่และเวลาปัจจุบัน (ส่วนแรกของ UUID เกี่ยวข้องกับเวลาถ้าคุณสร้าง UUID อีกสองสามวินาทีหลังจากสร้าง UUID ส่วนแรกจะแตกต่างกันส่วนที่เหลือจะเหมือนกัน) คือสตริงผลลัพธ์ที่สร้างขึ้นจะค่อนข้างยาว
มันเป็นจำนวนที่ยาว 128 บิตโดยทั่วไปแสดงในเลขฐานสิบหก แนวคิดหลักของอัลกอริทึมคือการสร้าง GUID ร่วมกับการ์ดเครือข่ายของเครื่องเวลาท้องถิ่นและหมายเลขทันที ในทางทฤษฎีหากเครื่องสร้าง GUID 100,000 ต่อวินาทีสามารถรับประกันได้ (ในแง่ของความน่าจะเป็น) ว่า 3240 ปีจะไม่ถูกทำซ้ำ
เริ่มต้นจาก JDK1.5 การสร้าง UUIDS กลายเป็นเรื่องง่าย ๆ โดยคิดว่า JDK ได้ดำเนินการ UUIDS:
java.util.uuid เพียงแค่เรียกมันโดยตรง
uuid uuid = uuid.randomuuid ();
String s = uuid.randomuuid (). toString (); // รหัสคีย์หลักที่ใช้ในการสร้างฐานข้อมูลนั้นดีมาก -
UUID ประกอบด้วยหมายเลขสิบหกหลักซึ่งแสดงในรูปแบบของ
550E8400-E29B-11D4-A716-446655440000
3. เพื่อป้องกันไฟล์มากเกินไปในไดเรกทอรีเดียวและส่งผลกระทบต่อการอ่านไฟล์และความเร็วในการเขียนโปรแกรมที่จัดการไฟล์อัปโหลดควรเลือกอัลกอริทึมการสร้างโครงสร้างไดเรกทอรีที่เหมาะสมตามปริมาณการอัปโหลดทั้งหมดที่เป็นไปได้และเก็บไฟล์ที่อัปโหลดในลักษณะที่กระจายไป ตัวอย่างเช่นใช้วิธีการ HashCode เพื่อสร้างไดเรกทอรีหลายระดับ
4. หากผู้ใช้ที่แตกต่างกันอัปโหลดไฟล์เดียวกันไม่จำเป็นต้องจัดเก็บสำเนาจำนวนมากของไฟล์เดียวกันในฝั่งเซิร์ฟเวอร์ นี่คือการเสียทรัพยากร อัลกอริทึมควรได้รับการออกแบบมาเพื่อแก้ปัญหาของไฟล์ที่ซ้ำกัน
5. หลักการเทคโนโลยี JSP ใช้การเธรดมัลติเธรดโดยอัตโนมัติ ดังนั้นนักพัฒนาไม่จำเป็นต้องพิจารณาการดำเนินการหลายเธรด
3. ดาวน์โหลดไฟล์
<% arrayList <String> fileenames = new ArrayList <String> (); fileenames.add ("file/aa.txt"); fileenames.add ("file/bb.jpg"); สำหรับ (String filename: ชื่อไฟล์) { %> <form action = "downloadServlet" method = "get"> <อินพุต type = "hidden" name = "filename" value = "< %= filename %>" /> <อินพุต type = "submit" value = "ดาวน์โหลด: < %= filename String filename = request.getParameter ("ชื่อไฟล์"); string urlName = urlencoder.encode (ชื่อไฟล์, "UTF-8"); // ป้องกันการตอบสนองที่อ่านไม่ออกภาษาจีน setheader ("เนื้อหา-การจัดสรร", "สิ่งที่แนบมา; filename ="+urlName); FileInputStream FIS = ใหม่ FileInputStream (ไฟล์ใหม่ (request.getSession (). getServletContext (). getRealPath (ชื่อไฟล์))); bufferedInputStream bis = ใหม่ bufferedInputStream (FIS); ServletOutputStream SOS = Response.getOutputStream (); ไบต์ [] บัฟเฟอร์ = ไบต์ใหม่ [1024]; int len = 0; ในขณะที่ ((len = bis.read (บัฟเฟอร์, 0, 1024))! =-1) {sos.write (บัฟเฟอร์, 0, len); } bis.close (); fis.close ();4. ใช้ส่วนประกอบ SmartUpload ใน SSH เพื่อทำให้ไฟล์อัปโหลดและดาวน์โหลดง่ายขึ้น
ข้างต้นเป็นเนื้อหาทั้งหมดของบทความนี้ ฉันหวังว่ามันจะเป็นประโยชน์ต่อการเรียนรู้ของทุกคนและฉันหวังว่าทุกคนจะสนับสนุน wulin.com มากขึ้น