ในการพัฒนาระบบเว็บแอปพลิเคชันฟังก์ชั่นการอัปโหลดและดาวน์โหลดไฟล์เป็นฟังก์ชั่นที่ใช้กันทั่วไป วันนี้มาพูดคุยเกี่ยวกับการใช้งานฟังก์ชั่นการอัปโหลดและดาวน์โหลดไฟล์ใน Javaweb
ภาพรวมการอัปโหลดไฟล์
1. ฟังก์ชั่นของการอัปโหลดไฟล์
ตัวอย่างเช่นฮาร์ดไดรฟ์เครือข่าย! มันถูกใช้เพื่ออัปโหลดและดาวน์โหลดไฟล์
ในการกรอกข้อมูลประวัติย่อที่สมบูรณ์เกี่ยวกับการสรรหาบุคลากร Zhilian คุณต้องอัปโหลดรูปภาพด้วย
2. ข้อกำหนดสำหรับการอัปโหลดหน้าเว็บ
มีข้อกำหนดมากมายสำหรับการอัปโหลดไฟล์โปรดจำไว้ว่า:
ต้องใช้แบบฟอร์มไม่ใช่วิธีการเชื่อมโยงหลายมิติจะต้องโพสต์ไม่ใช่การรับ
Enctype ของแบบฟอร์มจะต้องเป็นแบบหลายส่วน/ฟอร์มข้อมูล
เพิ่มฟิลด์ฟิลด์ฟอร์มไฟล์ในแบบฟอร์มเช่น <อินพุต type = "file" name = "xxx"/>>> >>
<form action = "$ {pageContext.request.contextpath}/fileuploadservlet" method = "post" enctype = "multipart/form-data"> ชื่อผู้ใช้: <input type = "text" name = "username"/> <br/> ไฟล์ 1: < name = "file2"/> <br/> <input type = "submit" value = "ส่ง"/> </form>3. เปรียบเทียบความแตกต่างระหว่างแบบฟอร์มการอัปโหลดไฟล์และแบบฟอร์มข้อความปกติ
ดูความแตกต่างระหว่าง "ฟอร์มการอัปโหลดไฟล์" และ "แบบฟอร์มข้อความปกติ" ผ่าน HTTPWATCH
Enctype ของฟอร์มอัปโหลดไฟล์ = "multipart/form-data" ซึ่งแสดงถึงข้อมูลแบบฟอร์มหลายส่วน;
สามารถตั้งค่าแบบฟอร์มข้อความปกติได้โดยไม่ต้องตั้งค่าแอตทริบิวต์ Enctype:
เมื่อวิธีการ =” โพสต์” ค่าเริ่มต้นของ Enctype คือแอปพลิเคชัน/x-www-form-urlencoded ซึ่งหมายความว่าเมื่อใช้วิธี =” get” ค่าเริ่มต้นของ Enctype เป็นโมฆะและไม่มีข้อความดังนั้นจึงไม่จำเป็นต้องทดสอบแบบฟอร์มข้อความปกติ:
<form action = "$ {pageContext.Request.ContextPath}/fileUploadServlet" method = "post"> ชื่อผู้ใช้: <อินพุต type = "text" name = "ผู้ใช้ชื่อ"/> <br/> ไฟล์ 1: <อินพุตประเภท = "ไฟล์" file1 "/> <br/> ไฟล์ 2: <อินพุต value = "ส่ง"/> </form>จากการทดสอบ HTTPWATCH โดยดูที่ข้อมูลการร้องขอของแบบฟอร์มเราพบว่ามีเพียงชื่อไฟล์ในคำขอ แต่ไม่มีเนื้อหาไฟล์ กล่าวคือเมื่อ Enctype ของแบบฟอร์มไม่ได้เป็นแบบหลายส่วน/ฟอร์มข้อมูลคำขอไม่มีเนื้อหาไฟล์ แต่เฉพาะชื่อไฟล์ซึ่งหมายความว่าไม่มีความแตกต่างระหว่างอินพุต: ไฟล์และอินพุต: ข้อความในรูปแบบข้อความปกติ
แบบฟอร์มการทดสอบไฟล์อัพโหลด:
<form action = "$ {pageContext.request.contextpath}/fileuploadservlet" method = "post" enctype = "multipart/form-data"> ชื่อผู้ใช้: <input type = "text" name = "username"/> <br/> ไฟล์ 1: < name = "file2"/> <br/> <input type = "submit" value = "ส่ง"/> </form>จากการทดสอบ HTTPWATCH เราจะดูส่วนต่างๆของร่างกายของข้อมูลคำขอของแบบฟอร์มและพบว่าส่วนของร่างกายประกอบด้วยส่วนประกอบหลายองค์ประกอบแต่ละองค์ประกอบสอดคล้องกับฟิลด์ฟอร์มและแต่ละองค์ประกอบมีข้อมูลส่วนหัวของตัวเอง ด้านล่างข้อมูลส่วนหัวเป็นบรรทัดที่ว่างเปล่าและด้านล่างเส้นเปล่าเป็นส่วนของร่างกายของสนาม หลายส่วนถูกคั่นด้วยตัวแบ่งแบบสุ่มที่สร้างขึ้น
ข้อมูลส่วนหัวของฟิลด์ข้อความมีข้อมูลส่วนหัวเพียงข้อมูลเดียวคือการแยกเนื้อหา มูลค่าของข้อมูลส่วนหัวนี้มีสองส่วน ส่วนแรกได้รับการแก้ไขคือรูปแบบข้อมูลและส่วนที่สองคือชื่อของฟิลด์ ด้านหลังเส้นเปล่าเป็นส่วนหลักและส่วนหลักคือเนื้อหาที่กรอกไว้ในกล่องข้อความ
ข้อมูลส่วนหัวของฟิลด์ไฟล์มีสองส่วนหัวคือการแยกเนื้อหาและประเภทเนื้อหา มีชื่อไฟล์เพิ่มเติมในการกระจายเนื้อหาซึ่งระบุชื่อไฟล์ที่อัปโหลด ประเภทเนื้อหาระบุประเภทของไฟล์ที่อัปโหลด ส่วนหลักของฟิลด์ไฟล์คือเนื้อหาของไฟล์
โปรดทราบว่าเนื่องจากไฟล์ที่เราอัปโหลดเป็นไฟล์ข้อความปกติทั้งหมดเช่นไฟล์ txt พวกเขาสามารถแสดงได้ตามปกติใน httpwatch หากไฟล์ที่อัปโหลดเป็น exe, mp3 ฯลฯ แล้วสิ่งที่คุณเห็นใน httpwatch นั้นอ่านไม่ออก
4. ข้อกำหนดสำหรับ servlets เมื่ออัปโหลดไฟล์
เมื่อแบบฟอร์มที่ส่งเป็นแบบฟอร์มการอัปโหลดไฟล์นอกจากนี้ยังมีข้อกำหนดสำหรับ servlet
ก่อนอื่นเราต้องตรวจสอบให้แน่ใจว่าข้อมูลของแบบฟอร์มการอัปโหลดไฟล์จะถูกห่อหุ้มไว้ในวัตถุคำขอ
เมธอด request.getParameter (string) ได้รับเนื้อหาอักขระฟิลด์ฟอร์มที่ระบุ แต่แบบฟอร์มการอัปโหลดไฟล์ไม่ได้เป็นเนื้อหาอักขระอีกต่อไป แต่เป็นเนื้อหาไบต์ดังนั้นจึงไม่ถูกต้อง
ในเวลานี้คุณสามารถใช้วิธีการขอ getInputStream () เพื่อขอรับวัตถุ ServletInputStream มันเป็นคลาสย่อยของอินพุตสตรีม วัตถุ ServletInputStream นี้สอดคล้องกับส่วนของร่างกายของแบบฟอร์มทั้งหมด (เริ่มต้นจากตัวหารแรกจนถึงจุดสิ้นสุด) ซึ่งแสดงข้อมูลในสตรีมการแยกวิเคราะห์ที่เราต้องการ แน่นอนว่าการแยกวิเคราะห์มันเป็นสิ่งที่ลำบากมากและ Apache ได้จัดเตรียมเครื่องมือในการแยกวิเคราะห์: Commons-Fileupload
คุณสามารถลองพิมพ์เนื้อหาของ request.getInputStream () และเปรียบเทียบข้อมูลคำขอใน httpwatch
โมฆะสาธารณะ dopost (คำขอ httpservletrequest, การตอบสนอง httpservletResponse) พ่น servletexception, ioexception {inputstream ใน = request.getInputStream (); สตริง s = ioutils.toString (ใน); System.out.println (s);}------------------------- 7DDD3370AB2CONTENT-DISPOSITION: FORM-DATA; NAME = "ชื่อผู้ใช้" สวัสดี ------------------------- 7DDD3370AB2CONTENT-DISPOSITION: FORM-DATA; name = "file1"; filename = "a.txt" ประเภทเนื้อหา: ข้อความ/plainaaa ----------------------------- 7DDD3370AB2CONTENT-DISPOSITION: FORM-DATA; name = "file2"; filename = "b.txt" ประเภทเนื้อหา: text/plainbbb ------------------------- 7ddd3370ab2-----------------------
Commons-Fileupload
ทำไมต้องใช้ fileupload:
มีข้อกำหนดมากมายสำหรับการอัปโหลดไฟล์โปรดจำไว้ว่า:
ต้องเป็นแบบฟอร์มโพสต์
Enctype ของแบบฟอร์มจะต้องเป็นแบบหลายส่วน/ฟอร์ม
เพิ่มฟิลด์ฟิลด์ฟอร์มไฟล์ลงในแบบฟอร์มเช่น
ข้อกำหนด Servlet:
คุณไม่สามารถใช้คำขอได้อีกต่อไป GetParameter () เพื่อรับข้อมูลแบบฟอร์ม คุณสามารถใช้ request.getInputStream () เพื่อรับข้อมูลแบบฟอร์มทั้งหมดแทนที่จะเป็นข้อมูลของรายการแบบฟอร์ม ซึ่งหมายความว่าคุณไม่ได้ใช้ FilePload เราจำเป็นต้องแยกวิเคราะห์เนื้อหาของ request.getInputStream () ตัวเราเอง
1. ภาพรวม FilePload
FileUpload เป็นส่วนประกอบการอัปโหลดที่จัดทำโดยส่วนประกอบของ Apache งานหลักคือช่วยเราแยกวิเคราะห์คำขอ GetInputStream ()
แพ็คเกจ JAR ที่ต้องการโดยส่วนประกอบ FileUpload คือ:
Commons-fileupload.jar, Core Package
Commons-io.jar แพ็คเกจการพึ่งพา
2. แอปพลิเคชันง่าย ๆ ของ fileupload
คลาสหลักของ fileupload คือ: diskfileitemfactory, servletfileupload, fileitem
ขั้นตอนในการใช้ส่วนประกอบ fileupload มีดังนี้:
// 1. สร้างคลาสโรงงาน DiskFileItemFactory Object DiskFileItemFactory โรงงาน = ใหม่ DiskFileItemFactory (); // 2 สร้างวัตถุ Parser โดยใช้ Fartory ServletFileUpload fileUpload = ใหม่ servletFileUpload (โรงงาน); // 3 ใช้ตัวแยกวิเคราะห์เพื่อแยกวิเคราะห์รายการออบเจ็กต์คำขอ <fileItem> list = fileupload.parserequest (คำขอ);
DiskFileItemFactory File File File คลาสโรงงาน
สาธารณะ diskfileitemfactory (int sizethreshold, ที่เก็บไฟล์)
เมื่อสร้างโรงงานให้ระบุขนาดบัฟเฟอร์หน่วยความจำและตำแหน่งที่เก็บไฟล์ชั่วคราว
โมฆะสาธารณะ setsizethreshold (int sizethreshold)
ตั้งค่าขนาดบัฟเฟอร์หน่วยความจำเริ่มต้น 10K
โมฆะสาธารณะ setRepository (ที่เก็บไฟล์)
ตั้งค่าตำแหน่งการจัดเก็บไฟล์ชั่วคราวระบบเริ่มต้น GetProperty ("java.io.tmpdir")
บัฟเฟอร์หน่วยความจำ: เมื่ออัปโหลดไฟล์เนื้อหาของไฟล์ที่อัปโหลดจะถูกบันทึกไว้ในบัฟเฟอร์หน่วยความจำก่อน เมื่อขนาดไฟล์ที่อัปโหลดเกินขนาดบัฟเฟอร์ไฟล์ชั่วคราวจะถูกสร้างขึ้นทางฝั่งเซิร์ฟเวอร์
ตำแหน่งที่เก็บไฟล์ชั่วคราว: อัปโหลดไฟล์เกินขนาดบัฟเฟอร์หน่วยความจำเพื่อสร้างไฟล์ชั่วคราว ไฟล์ชั่วคราวสามารถลบได้ผ่านวิธีการ DELETE () ของ FileItem
FileItem แสดงแต่ละส่วนของข้อมูลในแบบฟอร์มอัปโหลดไฟล์
เราจะแนะนำคลาส FileItem อย่างเคร่งขรึมซึ่งเป็นผลลัพธ์สุดท้ายที่เราต้องการ วัตถุ FileItem สอดคล้องกับรายการแบบฟอร์ม (ฟิลด์ฟอร์ม) ฟิลด์ไฟล์และฟิลด์ปกติมีอยู่ในรูปแบบ คุณสามารถใช้เมธอด iSformfield () ของคลาส FileItem เพื่อพิจารณาว่าฟิลด์ฟอร์มเป็นฟิลด์ปกติหรือไม่ หากไม่ใช่ฟิลด์ปกติแสดงว่าเป็นฟิลด์ไฟล์
หมายเหตุ: เนื่องจากรูปแบบการอัปโหลดไฟล์ถูกเข้ารหัสโดยใช้ multipart/form-data ซึ่งแตกต่างจากการเข้ารหัส URL แบบดั้งเดิมวิธีการ getParameter ทั้งหมด () ทั้งหมดไม่สามารถใช้ setCharacterencoding () ไม่สามารถแก้ปัญหาที่อ่านไม่ออกของรายการอินพุต
ServletFileUpload File File Class Core Core
3. ตัวอย่างการอัปโหลดอย่างง่าย
เขียนตัวอย่างการอัปโหลดอย่างง่าย:
แบบฟอร์มมีฟิลด์ชื่อผู้ใช้และฟิลด์ไฟล์
Servlet บันทึกไฟล์ที่อัปโหลดไปยังไดเรกทอรีอัปโหลดโดยแสดงชื่อผู้ใช้ชื่อไฟล์ขนาดไฟล์ประเภทไฟล์
ขั้นตอนแรก:
ในการทำ index.jsp ให้สมบูรณ์จำเป็นต้องใช้แบบฟอร์มเดียวเท่านั้น โปรดทราบว่าแบบฟอร์มจะต้องโพสต์และ Enctype จะต้องเป็น mulitpart/form-data
<form action = "$ {pageContext.request.contextpath}/fileuploadservlet" method = "post" enctype = "multipart/form-data"> ชื่อผู้ใช้: <input type = "text" name = "username"/> <br/> ไฟล์ 1: <อินพุต type = "ไฟล์"ขั้นตอนที่ 2: FilePloadServlet เสร็จสมบูรณ์
โมฆะสาธารณะ dopost (คำขอ httpservletrequest, การตอบสนอง httpservletResponse) โยน servletexception, ioexception {// เพราะคุณต้องการพิมพ์ด้วยการตอบกลับตั้งค่าการตอบสนองการเข้ารหัส SetContentType ("ข้อความ/html; charset = utf-8"); // สร้างโรงงาน diskfileitemfactory dfif = ใหม่ diskfileitemfactory (); // สร้างวัตถุตัวแยกวิเคราะห์โดยใช้โรงงาน servletFileUpload fileUpload = ใหม่ servletFileUpload (DFIF); ลอง {// ใช้วัตถุ parser เพื่อแยกวิเคราะห์คำขอและรับรายการ FileItem List <fileItem> list = fileupload.parserequest (คำขอ); // traverse รายการฟอร์มทั้งหมดสำหรับ (fileItem fileItem: list) {// ถ้ารายการฟอร์มปัจจุบันเป็นรายการฟอร์มปกติถ้า (fileItem.isformfield ()) {// รับชื่อฟิลด์ของฟอร์มรายการปัจจุบันสตริงฟิลด์ชื่อ fieldName = fileItem.getFieldName (); // ถ้าชื่อฟิลด์ของรายการแบบฟอร์มปัจจุบันคือชื่อผู้ใช้ถ้า (fieldName.equals ("ชื่อผู้ใช้")) {// พิมพ์เนื้อหาของรายการฟอร์มปัจจุบันนั่นคือเนื้อหาที่ป้อนโดยรายการแบบฟอร์มผู้ใช้ชื่อตอบกลับ () พิมพ์ ("ชื่อผู้ใช้:" }} else {// ถ้ารายการแบบฟอร์มปัจจุบันไม่ใช่รายการแบบฟอร์มปกติหมายความว่าชื่อสตริงฟิลด์ไฟล์ = fileItem.getName (); // รับชื่อของไฟล์ที่อัปโหลด // หากชื่อไฟล์ที่อัปโหลดว่างเปล่า } // รับเส้นทางจริงซึ่งสอดคล้องกับ $ {Project Directory}/อัปโหลด แน่นอนไดเรกทอรีนี้จะต้องมีสตริง savepath = this.getServletContext (). getRealPath ("/อัปโหลด"); // สร้างวัตถุไฟล์ผ่านไดเรกทอรีอัปโหลดและไฟล์ชื่อไฟล์ = ไฟล์ใหม่ (บันทึกชื่อ); // บันทึกไฟล์อัปโหลดไปยังตำแหน่งที่ระบุ FileItem.Write (ไฟล์); // พิมพ์ชื่อของการอัปโหลดไฟล์ response.getWriter () พิมพ์ ("อัปโหลดชื่อไฟล์:" + ชื่อ + "<br/>"); // พิมพ์ขนาดของการอัพโหลดไฟล์ response.getWriter () พิมพ์ ("อัพโหลดขนาดไฟล์:" + fileItem.getSize () + "<br/>"); // พิมพ์ประเภทของการตอบสนองไฟล์ที่อัปโหลด getWriter () พิมพ์ ("อัปโหลดประเภทไฟล์:" + fileItem.getContentType () + "<br/>"); }}} catch (Exception e) {โยน servletexception ใหม่ (e); -รายละเอียดการอัปโหลดไฟล์
1. ใส่ไฟล์ที่อัปโหลดในไดเรกทอรี Web-Inf
หากไฟล์ที่อัปโหลดโดยผู้ใช้ไม่ได้ถูกเก็บไว้ในไดเรกทอรี Web-Inf ผู้ใช้สามารถเข้าถึงไฟล์ที่อัปโหลดโดยตรงผ่านเบราว์เซอร์ซึ่งเป็นอันตรายมาก
หากผู้ใช้อัปโหลดไฟล์ A.JSP จากนั้นผู้ใช้จะเข้าถึงไฟล์ A.JSP ผ่านเบราว์เซอร์เนื้อหาใน A.JSP จะถูกเรียกใช้งาน หากมีคำสั่งต่อไปนี้ใน A.JSP: runtime.getRuntime (). exec ("shutdown st 1"); แล้วคุณจะ ...
โดยปกติแล้วเราจะสร้างไดเรกทอรีอัปโหลดในไดเรกทอรี Web-Inf เพื่อจัดเก็บไฟล์ที่อัปโหลด ในการค้นหาไดเรกทอรีนี้ใน servlet เราจำเป็นต้องใช้วิธีการ getRealPath (สตริง) ของ servletContext ตัวอย่างเช่นมีคำสั่งต่อไปนี้ในโครงการ Upload1 ของฉัน:
servletContext servletContext = this.getServletContext (); string savepath = servletContext.getRealPath ("/web-inf/uploads");SavePath คือ: f:/tomcat6_1/webapps/upload1/web-inf/uploads
2. ชื่อไฟล์ (เส้นทางเต็มชื่อไฟล์)
ชื่อไฟล์ที่อัปโหลดอาจเป็นเส้นทางเต็ม:
ชื่อไฟล์อัปโหลดที่ได้รับจาก IE6 เป็นพา ธ แบบเต็มในขณะที่ชื่อไฟล์อัปโหลดที่ได้รับจากเบราว์เซอร์อื่นเป็นเพียงชื่อไฟล์ เรายังต้องจัดการกับปัญหาความแตกต่างของเบราว์เซอร์
ชื่อสตริง = file1fileitem.getName (); responce.getWriter (). พิมพ์ (ชื่อ);
การใช้เบราว์เซอร์ที่แตกต่างกันเพื่อทดสอบ IE6 จะส่งคืนเส้นทางเต็มเพื่ออัปโหลดไฟล์ ฉันไม่รู้ว่า IE6 กำลังทำอะไรซึ่งทำให้เรามีปัญหามากมายซึ่งก็คือการจัดการกับปัญหานี้
นอกจากนี้ยังง่ายมากที่จะจัดการกับปัญหานี้ ไม่ว่าจะเป็นเส้นทางที่สมบูรณ์หรือไม่เราเพียงแค่สกัดกั้นเนื้อหาหลังจาก "/" สุดท้ายล่าสุด
ชื่อสตริง = file1fileitem.getName (); int lastIndex = name.lastIndexof ("//"); // รับตำแหน่งของ "/" ถ้า (LastIndex! = -1) {// โปรดทราบว่าถ้าไม่ใช่เส้นทางเต็มแล้วจะไม่มี "/" name = name.substring (LastIndex + 1); // รับชื่อไฟล์} response.getWriter (). พิมพ์ (ชื่อ);3. ปัญหาที่อ่านไม่ออกภาษาจีน
ชื่อไฟล์ที่อัปโหลดมีภาษาจีน:
เมื่อชื่อที่อัปโหลดมีภาษาจีนคุณจะต้องตั้งค่าการเข้ารหัส คอมโพเนนต์คอมมอนส์-ฟิลด์อัปโหลดให้เรามีสองวิธีในการตั้งค่าการเข้ารหัส:
request.Setcharacterencoding (String): วิธีนี้เป็นวิธีที่คุ้นเคยที่สุดที่เราเป็น
fileupload.setheaderencdoing (String): วิธีนี้มีลำดับความสำคัญสูงกว่าก่อนหน้า
เนื้อหาไฟล์ของไฟล์ที่อัปโหลดมีภาษาจีน:
โดยปกติแล้วเราไม่จำเป็นต้องใส่ใจเกี่ยวกับเนื้อหาของการอัปโหลดไฟล์เพราะเราจะบันทึกไฟล์ที่อัปโหลดไปยังฮาร์ดไดรฟ์! กล่าวอีกนัยหนึ่งไฟล์มีลักษณะอย่างไรและดูเหมือนว่าบนเซิร์ฟเวอร์!
แต่ถ้าคุณมีข้อกำหนดดังกล่าวและต้องแสดงเนื้อหาไฟล์ที่อัปโหลดบนคอนโซลคุณสามารถใช้ fileitem.getString ("UTF-8") เพื่อจัดการการเข้ารหัส
เนื้อหาไฟล์ข้อความและรายการไอเท็มปกติการใช้ GetString ("UTF-8") ของคลาส FileItem เพื่อจัดการการเข้ารหัส
4. ปัญหาการอัปโหลดไฟล์ด้วยชื่อเดียวกัน (การเปลี่ยนชื่อไฟล์)
โดยปกติแล้วเราจะบันทึกไฟล์ที่ผู้ใช้อัปโหลดไปยังไดเรกทอรีอัปโหลด แต่ถ้าผู้ใช้อัปโหลดไฟล์ด้วยชื่อเดียวกัน สิ่งนี้จะทำให้เกิดความคุ้มครอง วิธีการจัดการกับปัญหานี้คือการใช้ UUID เพื่อสร้างชื่อที่ไม่ซ้ำกันจากนั้นใช้ "_" เพื่อเชื่อมต่อชื่อเดิมที่อัปโหลดโดยไฟล์
ตัวอย่างเช่นไฟล์ที่อัปโหลดโดยผู้ใช้คือ "My One Inch Photo.jpg" หลังจากการประมวลผลชื่อไฟล์คือ: "891B3881395F4175B969256A3F7B6E10_MY หนึ่งนิ้ว photo.jpg" วิธีนี้จะไม่ทำให้ไฟล์สูญเสียส่วนขยาย เนื่องจากความเป็นเอกลักษณ์ของ UUID ไฟล์ที่อัปโหลดมีชื่อเดียวกัน แต่จะไม่มีปัญหากับชื่อเดียวกันในฝั่งเซิร์ฟเวอร์
โมฆะสาธารณะ dopost (คำขอ httpservletrequest, การตอบสนอง httpservletResponse) พ่น servletexception, ioexception {request.setcharacterencoding ("UTF-8"); diskfileitemfactory dfif = ใหม่ diskfileitemfactory (); servletFileUpload fileupload = ใหม่ servletFileUpload (dfif); ลอง {list <fileItem> list = fileupload.parserequest (คำขอ); // รับไอเท็มฟอร์มที่สองเนื่องจากรายการแบบฟอร์มแรกคือชื่อผู้ใช้ชื่อที่สองคือรายการไฟล์ไฟล์ fileItem fileItem = list.get (1); ชื่อสตริง = fileItem.getName (); // รับชื่อไฟล์ // หากไคลเอนต์ใช้ IE6 จากนั้นคุณจะต้องได้รับชื่อไฟล์จากเส้นทางเต็ม path int LastIndex = name.AlastIndexof ("//"); if (lastIndex! = -1) {name = name.SubString (LastIndex + 1); } // รับไฟล์ที่อัปโหลด savepath = this.getServletContext (). getRealPath ("/web-inf/uploads"); string uuid = commonutils.uuid (); // สร้าง uuid string filename = uuid + "_" + name; // ชื่อไฟล์ใหม่คือ UUID + Underscore + ชื่อดั้งเดิม // สร้างวัตถุไฟล์และไฟล์ที่อัปโหลดจะถูกบันทึกไว้ // บันทึก file item.write (ไฟล์); } catch (exception e) {โยน servletexception ใหม่ (e); -5. ไดเรกทอรีไม่สามารถจัดเก็บไฟล์ได้มากเกินไป (ไดเรกทอรีร้านค้าที่จะเลิกกัน)
ไม่ควรมีไฟล์มากเกินไปที่เก็บไว้ในไดเรกทอรี โดยทั่วไปแล้ว 1,000 ไฟล์จะถูกเก็บไว้ในไดเรกทอรีและหากมีจำนวนมากมันจะ "แคร็ก" มากเมื่อเปิดไดเรกทอรี คุณสามารถลองพิมพ์ไดเรกทอรี c:/windows/system32 คุณจะรู้สึกได้
นั่นคือเราต้องใส่ไฟล์ที่อัปโหลดลงในไดเรกทอรีที่แตกต่างกัน อย่างไรก็ตามไดเรกทอรีหนึ่งไม่สามารถใช้สำหรับแต่ละไฟล์ที่อัปโหลดได้เนื่องจากวิธีนี้จะนำไปสู่ไดเรกทอรีมากเกินไป ดังนั้นเราควรใช้อัลกอริทึมบางอย่างเพื่อ "เลิก"!
มีหลายวิธีในการทำลายมันเช่นการใช้วันที่เพื่อทำลายมันสร้างไดเรกทอรีทุกวัน นอกจากนี้คุณยังสามารถใช้ตัวอักษรตัวแรกของชื่อไฟล์เพื่อสร้างไดเรกทอรีและไฟล์ที่มีตัวอักษรเริ่มต้นเดียวกันจะถูกวางไว้ในไดเรกทอรีเดียวกัน
อัลกอริทึมการทำลายวันที่: หากมีการอัปโหลดไฟล์มากเกินไปในวันหนึ่งจะมีไฟล์ไดเรกทอรีมากเกินไป
อัลกอริทึมสำหรับการทำลายตัวอักษรแรก: หากชื่อไฟล์เป็นภาษาจีนเพราะมีภาษาจีนมากเกินไปมันจะนำไปสู่ไดเรกทอรีมากเกินไป
เราใช้อัลกอริทึมแฮชที่นี่เพื่อทำลายมัน:
รับ hashcode ของชื่อไฟล์: int hcode = name.hashCode ()
รับ HCODE 4 บิตที่ต่ำกว่าจากนั้นแปลงเป็นอักขระเลขฐานสิบหกเพื่อให้ได้ HCODE 5 ~ 8 บิตจากนั้นแปลงเป็นอักขระเลขฐานสิบหกเพื่อสร้างห่วงโซ่ไดเรกทอรีโดยใช้ตัวละครหกสิบสองตัวนี้ ตัวอย่างเช่นอักขระ 4 บิตที่ต่ำกว่าคือ "5"
ข้อได้เปรียบของอัลกอริทึมนี้คือมีการสร้างไดเรกทอรีสูงสุด 16 ไดเรกทอรีในไดเรกทอรีการอัปโหลดและมีการสร้างไดเรกทอรีสูงสุด 16 ไดเรกทอรีในแต่ละไดเรกทอรีนั่นคือ 256 ไดเรกทอรีและไฟล์ที่อัปโหลดทั้งหมดจะถูกวางไว้ในไดเรกทอรี 256 ไดเรกทอรีเหล่านี้ หากจำนวนสูงสุดของแต่ละไดเรกทอรีคือ 1,000 ไฟล์สามารถบันทึกไฟล์ทั้งหมด 256,000 ไฟล์
ตัวอย่างเช่นชื่อไฟล์อัปโหลดคือ: text document.txt ใหม่จากนั้นรับรหัสแฮชของ "text document.txt" ใหม่จากนั้นรับตัวเลข 4 หลักของรหัสแฮชและ 5 ถึง 8 หลัก หาก 4 บิตต่ำกว่าคือ: 9 และ 5 ~ 8 บิตคือ 1 ดังนั้นเส้นทางบันทึกไฟล์คือการอัปโหลด/9/1/
int hcode = name.hashCode (); // รับ hashcode ของชื่อไฟล์ // รับ hcode ต่ำ 4 บิตและแปลงเป็นสตริงสตริง hexadecimal สตริง dir1 = integer.tohexstring (hcode & 0xf); >>> 4 & 0xf); // เชื่อมต่อไฟล์บันทึกไฟล์ไปยังเส้นทางเต็มพา ธ savepath = savepath + "/" + dir1 + "/" + dir2; // เนื่องจากเส้นทางนี้อาจไม่มีอยู่ให้สร้างเป็นวัตถุไฟล์แล้วสร้างเชนไดเรกทอรีเพื่อให้แน่ใจว่าไดเรกทอรีมีอยู่ใหม่ก่อนที่จะบันทึกไฟล์ไฟล์ (บันทึก)
6. ขีด จำกัด ขนาดสำหรับไฟล์ที่อัปโหลดแต่ละไฟล์
มันง่ายมากที่จะ จำกัด ขนาดของไฟล์ที่อัปโหลดเพียงแค่ setFilesizeMax (ยาว) ของคลาส servletfileupload พารามิเตอร์คือจำนวนขีด จำกัด บนของไบต์ของไฟล์ที่อัปโหลด ตัวอย่างเช่น ServletFileUpload.SetFilesizEmax (1024*10) หมายความว่าขีด จำกัด บนคือ 10KB
เมื่อไฟล์ที่อัพโหลดเกินขีด จำกัด บนแล้ว fileuploadbase.filesizeLimitexceedexception จะถูกโยนทิ้ง เราสามารถรับข้อยกเว้นนี้ได้ใน servlet และเอาต์พุต "ไฟล์ที่อัปโหลดเกินขีด จำกัด " ไปยังหน้า
โมฆะสาธารณะ dopost (คำขอ httpservletrequest, การตอบสนอง httpservletResponse) พ่น servletexception, ioexception {request.setcharacterencoding ("UTF-8"); diskfileitemfactory dfif = ใหม่ diskfileitemfactory (); servletFileUpload fileupload = ใหม่ servletFileUpload (dfif); // ตั้งค่าขีด จำกัด บนของไฟล์เดียวที่อัปโหลดเป็น 10kb fileupload.setFilesizeMax (1024 * 10); ลอง {list <fileItem> list = fileupload.parserequest (คำขอ); // รับไอเท็มฟอร์มที่สองเนื่องจากรายการแบบฟอร์มแรกคือชื่อผู้ใช้ชื่อที่สองคือรายการฟอร์มไฟล์ fileItem = list.get (1); ชื่อสตริง = fileItem.getName (); // รับชื่อไฟล์ // หากไคลเอนต์ใช้ IE6 จากนั้นคุณจะต้องได้รับชื่อไฟล์จากเส้นทางเต็ม path int LastIndex = name.AlastIndexof ("//"); if (lastIndex! = -1) {name = name.SubString (LastIndex + 1); } // รับไฟล์ที่อัปโหลด savepath = this.getServletContext (). getRealPath ("/web-inf/uploads"); string uuid = commonutils.uuid (); // สร้าง uuid string filename = uuid + "_" + name; // ชื่อไฟล์ใหม่คือ uuid + underscore + ชื่อดั้งเดิม int hcode = name.hashCode (); Integer.toHexstring (Hcode & 0xf); // รับ hcode 5 ~ 8 บิตต่ำกว่าและแปลงเป็นสตริงสตริง hexadecimal สตริง dir2 = integer.tohexstring (hcode >>> 4 & 0xf); // เชื่อมต่อไฟล์บันทึกไฟล์เข้ากับพา ธ เต็มรูปแบบ savepath = savepath + "/" + dir1 + "/" + dir2; // เนื่องจากเส้นทางนี้อาจไม่มีอยู่ให้สร้างวัตถุไฟล์จากนั้นสร้างห่วงโซ่ไดเรกทอรีเพื่อให้แน่ใจว่าไดเรกทอรีมีอยู่แล้วก่อนที่จะบันทึกไฟล์ใหม่ไฟล์ (บันทึก) .MkDirs (); // สร้างวัตถุไฟล์และไฟล์ที่อัปโหลดจะถูกบันทึกลงในพา ธ ที่ระบุโดยไฟล์นี้ // savepath นั่นคือไฟล์ที่อัปโหลดไดเรกทอรีบันทึก // ชื่อไฟล์ชื่อไฟล์ชื่อไฟล์ชื่อไฟล์; // บันทึก fileitem.write (ไฟล์); } catch (Exception e) {// ตรวจสอบว่าประเภทของข้อยกเว้นที่ถูกโยนคือ fileuploadbase.filesizeLimitexceedeDexception // ถ้าเป็นเช่นนั้นหมายความว่าเกินขีด จำกัด เมื่ออัปโหลดไฟล์ if (e instanceof fileuploadbase.filesizeLimitexceedEdException) {// บันทึกข้อความแสดงข้อผิดพลาดในคำขอคำขอ SetAttribute ("msg", "อัปโหลดล้มเหลว! ไฟล์ที่อัปโหลดเกิน 10kb!"); // ส่งต่อไปยังหน้า index.jsp! ในหน้า index.jsp คุณต้องใช้ $ {msg} เพื่อแสดงข้อความแสดงข้อผิดพลาด getRequestDispatcher ("/index.jsp") ส่งต่อ (คำขอ, ตอบกลับ); กลับ; } โยน servletexception ใหม่ (e); -7. ขีด จำกัด ขนาดรวมสำหรับการอัปโหลดไฟล์
แบบฟอร์มเพื่ออัปโหลดไฟล์อาจอนุญาตให้อัปโหลดไฟล์หลายไฟล์ตัวอย่างเช่น:
บางครั้งเราจำเป็นต้อง จำกัด ขนาดของคำขอ กล่าวคือจำนวนไบต์สูงสุดสำหรับคำขอนี้ (ผลรวมของรายการแบบฟอร์มทั้งหมด)! การใช้ฟังก์ชั่นนี้ก็ง่ายมาก คุณจะต้องเรียกวิธี SetSizeMax (ยาว) ของคลาส servletFileUpload
ตัวอย่างเช่น fileUpload.setSizeMax (1024 * 10); ขีด จำกัด บนสำหรับคำขอทั้งหมดคือ 10KB เมื่อขนาดคำขอเกิน 10KB วิธีการ parSeRequest () ของคลาส servletFileUpload จะส่ง fileuploadbase.sizeLimitexceedexception ยกเว้น
8. ขนาดแคชและไดเรกทอรีชั่วคราว
ลองคิดดูถ้าฉันอัปโหลดภาพยนตร์ Blu-ray ให้บันทึกภาพยนตร์ลงในหน่วยความจำก่อนแล้วคัดลอกไปยังฮาร์ดดิสก์เซิร์ฟเวอร์ผ่านหน่วยความจำแล้วหน่วยความจำของคุณจะถูกกินได้หรือไม่?
ดังนั้นส่วนประกอบ fileupload ไม่สามารถบันทึกไฟล์ทั้งหมดในหน่วยความจำได้ FilePload จะพิจารณาว่าขนาดไฟล์เกิน 10KB หรือไม่ ถ้าเป็นเช่นนั้นให้บันทึกไฟล์ไปยังฮาร์ดดิสก์ หากไม่เกินมันให้บันทึกในหน่วยความจำ
10kb เป็นค่าเริ่มต้นของ fileupload เราสามารถตั้งค่าได้
เมื่อไฟล์ถูกบันทึกลงในฮาร์ดดิสก์ FilePload จะบันทึกไฟล์ไปยังไดเรกทอรีชั่วคราวของระบบ แน่นอนคุณสามารถตั้งค่าไดเรกทอรีชั่วคราว
โมฆะสาธารณะ dopost (คำขอ httpservletrequest, การตอบสนอง httpservletResponse) พ่น servletexception, ioexception {request.setcharacterencoding ("UTF-8"); diskfileitemfactory dfif = ใหม่ diskfileitemfactory (1024*20, ไฟล์ใหม่ ("f: // temp")); servletFileUpload fileupload = ใหม่ servletFileUpload (dfif); ลอง {list <fileItem> list = fileupload.parserequest (คำขอ); fileItem fileItem = list.get (1); ชื่อสตริง = fileItem.getName (); String savepath = this.getServletContext (). getRealPath ("/web-inf/uploads"); // บันทึก fileitem.write (พา ธ (พา ธ (บันทึก, ชื่อ));} catch (ข้อยกเว้น e) {โยน servletexception ใหม่ (e);}} พา ธ ไฟล์ส่วนตัว (สตริงบันทึก, สตริง filename) {// รับชื่อไฟล์ int จากเส้นทางเต็ม lastindex = filename.lastindexof ("//"); FileName.SubString (LastIndex + 1); DIR2;ดาวน์โหลดไฟล์
1. ดาวน์โหลด 1 ถึง servlet
ทรัพยากรที่ดาวน์โหลดจะต้องอยู่ในไดเรกทอรี Web-Inf (ก็โอเคตราบใดที่ผู้ใช้ไม่สามารถเข้าถึงได้โดยตรงผ่านเบราว์เซอร์) จากนั้นดาวน์โหลดผ่าน Servlet
ให้ไฮเปอร์ลิงก์ในหน้า JSP ลิงก์ไปยัง DownloadServlet และระบุชื่อไฟล์เพื่อดาวน์โหลด จากนั้น DownloadServlet จะได้รับเส้นทางจริงของไฟล์และเขียนไฟล์ไปยังสตรีม Response.getOutputStream ()
download.jsp
<body> นี่คือหน้า JSP ของฉัน <br> <a href = "<c: url value = '/downloadservlet? path = a.avi' //>"> a.avi </a> <br/> <a href = "<c: url value = '/downloadservlet? value = '/downloadservlet? path = a.txt' /////> "> a.txt </a> <br/> </body>
downloadservlet.java
โมฆะสาธารณะ DOGET (คำขอ httpservletRequest, การตอบสนอง httpservletResponse) พ่น servletexception, ioexception {string filename = request.getParameter ("path"); String filePath = this.getServletContext (). getRealPath ("/web-inf/uploads/" + ชื่อไฟล์); ไฟล์ไฟล์ = ไฟล์ใหม่ (filePath); if (! file.exists ()) {response.getWriter (). พิมพ์ ("ไฟล์ที่คุณต้องการดาวน์โหลดไม่มีอยู่!"); กลับ; } ioutils.copy (ใหม่ FileInputStream (ไฟล์), response.getOutputStream ());}รหัสข้างต้นมีปัญหาต่อไปนี้:
1. คุณสามารถดาวน์โหลด A.AVI ได้ แต่ชื่อไฟล์ในกล่องดาวน์โหลดคือ DownloadServlet;
2. คุณไม่สามารถดาวน์โหลด a.jpg และ a.txt ได้ แต่แสดงในหน้า
2. ดาวน์โหลด 2 ถึง servlet
มาจัดการกับปัญหาในตัวอย่างก่อนหน้าเพื่อให้กล่องดาวน์โหลดสามารถแสดงชื่อไฟล์ที่ถูกต้องและคุณสามารถดาวน์โหลดไฟล์ A.JPG และ A.TXT
จัดการกับปัญหาข้างต้นโดยการเพิ่มส่วนหัวการแยกเนื้อหา เมื่อมีการตั้งค่าส่วนหัวของเนื้อหา-การแยกส่วนเบราว์เซอร์จะปรากฏขึ้นในช่องดาวน์โหลด
และคุณยังสามารถระบุชื่อของไฟล์ที่ดาวน์โหลดผ่านส่วนหัวของเนื้อหา-การกระจาย!
string filename = request.getParameter ("path"); String filePath = this.getServletContext (). getRealPath ("/web-inf/uploads/" + ชื่อไฟล์); ไฟล์ไฟล์ = ไฟล์ใหม่ (filePath); if (! file.exists ()) {response.getWriter (). พิมพ์ ("ไฟล์ที่คุณต้องการดาวน์โหลดไม่มีอยู่!"); กลับ; } response.addheader ("เนื้อหา-การจัดสรร", "สิ่งที่แนบมา; ชื่อไฟล์ =" + ชื่อไฟล์); ioutils.copy (ใหม่ FileInputStream (ไฟล์), response.getOutputStream ());แม้ว่ารหัสด้านบนสามารถจัดการการดาวน์โหลดไฟล์เช่น TXT และ JPG ได้แล้วและยังจัดการกับปัญหาในการแสดงชื่อไฟล์ในกล่องดาวน์โหลดหากชื่อไฟล์ที่ดาวน์โหลดเป็นภาษาจีน
3. ดาวน์โหลด 3 ผ่าน servlet
ด้านล่างนี้เป็นปัญหาของการจัดการการแสดงผลภาษาจีนในกล่องดาวน์โหลด!
ในความเป็นจริงคำถามนี้ง่ายมาก คุณจะต้องเข้ารหัสภาษาจีนผ่าน URL!
download.jsp
<a href = "<c: url value = '/downloadservlet? path = นักฆ่าคนนี้ไม่เย็นเกินไป avi' //>"> นักฆ่าคนนี้ไม่เย็นเกินไป avi </a> <br/> <a href = "<c: c: url = '/downloadservlet? path = baibing.jpg'/> href = "<c: url value = '/downloadservlet? path = description.txt'/>"> description.txt </a> <br/>
downloadservlet.java
String filename = request.getParameter ("path"); // ในการร้องขอรับพารามิเตอร์จีนมีภาษาจีนและจำเป็นต้องแปลงด้วยตัวเอง // แน่นอนถ้าคุณใช้ "ตัวกรองการเข้ารหัสทั่วโลก" คุณไม่จำเป็นต้องจัดการกับมันที่นี่ชื่อไฟล์ = สตริงใหม่ (ชื่อไฟล์. getBytes ("iso-8859-1"), "utf-8"); string filepath = this.getServletContext () ไฟล์ (filePath); ถ้า (! file.exists ()) {response.getWriter (). พิมพ์ ("ไฟล์ที่คุณต้องการดาวน์โหลดไม่มีอยู่!"); return;} // เบราว์เซอร์ทั้งหมดจะใช้การเข้ารหัสในท้องถิ่นนั่นคือระบบปฏิบัติการจีนใช้ GBK // หลังจากเบราว์เซอร์ได้รับชื่อไฟล์นี้มันจะใช้ ISO-8859-1 เพื่อถอดรหัสชื่อไฟล์ = สตริงใหม่ ชื่อไฟล์); ioutils.copy (ใหม่ FileInputStream (ไฟล์), response.getOutputStream ());ข้างต้นเป็นเนื้อหาทั้งหมดของบทความนี้ ฉันหวังว่ามันจะเป็นประโยชน์ต่อการเรียนรู้ของทุกคนและฉันหวังว่าทุกคนจะสนับสนุน wulin.com มากขึ้น