วิธีกำหนดค่าและแก้ไขปัญหา<p:fileUpload>
ขึ้นอยู่กับเวอร์ชัน PrimeFaces
PrimeFaces ทุกรุ่น
ข้อกำหนดด้านล่างนี้ใช้กับ PrimeFaces ทุกเวอร์ชัน:
enctype
แอตทริบิวต์ของความต้องการที่จะได้รับการตั้งค่าให้<h:form>
multipart/form-data
เมื่อไม่มีสิ่งนี้การอัปโหลด ajax อาจใช้งานได้ แต่พฤติกรรมทั่วไปของเบราว์เซอร์ไม่ได้ระบุไว้และขึ้นอยู่กับองค์ประกอบของแบบฟอร์มและยี่ห้อ / เวอร์ชันของเว็บเบราว์เซอร์ เพียงแค่ระบุให้อยู่ในด้านที่ปลอดภัยเสมอ
เมื่อใช้mode="advanced"
(เช่นการอัปโหลด ajax นี่เป็นค่าเริ่มต้น) จากนั้นตรวจสอบให้แน่ใจว่าคุณได้<h:head>
อยู่ในเทมเพลต (ต้นแบบ) เพื่อให้แน่ใจว่ามีการรวมไฟล์ JavaScript ที่จำเป็นอย่างเหมาะสม สิ่งนี้ไม่จำเป็นสำหรับmode="simple"
(การอัปโหลดที่ไม่ใช่ ajax) แต่จะทำให้รูปลักษณ์และฟังก์ชันการทำงานของส่วนประกอบ PrimeFaces อื่น ๆ เสียหายดังนั้นคุณจึงไม่ควรพลาดสิ่งนั้น
เมื่อใช้mode="simple"
(เช่นการอัพโหลดแบบไม่ใช้ ajax) จะต้องปิดการใช้งาน ajax บนปุ่ม / ลิงก์คำสั่ง PrimeFaces โดยajax="false"
และคุณจะต้องใช้<p:fileUpload value>
กับ<p:commandButton action>
แทน<p:fileUpload fileUploadListener>
(สำหรับ PrimeFaces <= 7.x) หรือ<p:fileUpload listener>
(สำหรับ PrimeFaces> = 8.x)
ดังนั้นหากคุณต้องการอัปโหลดไฟล์ (อัตโนมัติ) ด้วยการสนับสนุน ajax (คำนึงถึง<h:head>
!):
<h:form enctype="multipart/form-data">
<p:fileUpload fileUploadListener="#{bean.upload}" auto="true" /> // for PrimeFaces >= 8.x this should be listener instead of fileUploadListener
</h:form>
public void upload(FileUploadEvent event) {
UploadedFile uploadedFile = event.getFile();
String fileName = uploadedFile.getFileName();
String contentType = uploadedFile.getContentType();
byte[] contents = uploadedFile.getContents(); // Or getInputStream()
// ... Save it, now!
}
หรือหากคุณต้องการอัพโหลดไฟล์ที่ไม่ใช่ ajax:
<h:form enctype="multipart/form-data">
<p:fileUpload mode="simple" value="#{bean.uploadedFile}" />
<p:commandButton value="Upload" action="#{bean.upload}" ajax="false" />
</h:form>
private UploadedFile uploadedFile; // +getter+setter
public void upload() {
String fileName = uploadedFile.getFileName();
String contentType = uploadedFile.getContentType();
byte[] contents = uploadedFile.getContents(); // Or getInputStream()
// ... Save it, now!
}
ทำทราบว่าแอตทริบิวต์ของอาแจ็กซ์ที่เกี่ยวข้องเช่นauto
, allowTypes
, update
,onstart
, oncomplete
, ฯลฯ จะไม่สนใจmode="simple"
ใน ดังนั้นจึงไม่จำเป็นต้องระบุในกรณีเช่นนี้
โปรดทราบว่าคุณควร อ่านเนื้อหาไฟล์ทันทีภายในวิธีการที่กล่าวถึงข้างต้นและไม่ใช้วิธี bean อื่นที่เรียกใช้โดยการร้องขอ HTTP ในภายหลัง เนื่องจากเนื้อหาไฟล์ที่อัปโหลดถูกกำหนดขอบเขตคำขอจึงไม่สามารถใช้งานได้ในคำขอ HTTP ภายหลัง / อื่น ความพยายามใด ๆ ที่จะอ่านในคำขอในภายหลังส่วนใหญ่มักจะจบลงด้วยjava.io.FileNotFoundException
ไฟล์ชั่วคราว
PrimeFaces 8.x
การกำหนดค่าจะเหมือนกับข้อมูลเวอร์ชัน 5.x ด้านล่าง แต่ถ้าผู้ฟังของคุณไม่ได้ถูกเรียกให้ตรวจสอบว่ามีการเรียกใช้ระบบเสียงหรือไม่ listener
หรือไม่ (เช่นเดียวกับรุ่นก่อน 8.x)fileUploadListener
PrimeFaces 5.x
สิ่งนี้ไม่ต้องการการกำหนดค่าเพิ่มเติมใด ๆ หากคุณใช้ JSF 2.2 และของคุณfaces-config.xml
ได้รับการประกาศว่าเป็นไปตามเวอร์ชัน JSF 2.2 คุณไม่จำเป็นต้องมีตัวกรองการอัปโหลดไฟล์ PrimeFaces เลย ในกรณีที่คุณไม่ชัดเจนว่าจะติดตั้งและกำหนดค่า JSF อย่างไรให้ถูกต้องโดยขึ้นอยู่กับเซิร์ฟเวอร์เป้าหมายที่ใช้ให้ไปที่วิธีการติดตั้งและกำหนดค่าไลบรารี JSF อย่างถูกต้องผ่าน Maven? และ "การติดตั้ง JSF" ของหน้าเว็บวิกิพีเดีย
หากคุณยังไม่ได้ใช้ JSF 2.2 และคุณไม่สามารถอัปเกรดได้ (ควรทำได้อย่างง่ายดายเมื่ออยู่ในคอนเทนเนอร์ที่เข้ากันได้กับ Servlet 3.0) คุณต้องลงทะเบียนตัวกรองการอัปโหลดไฟล์ PrimeFaces ด้านล่างด้วยตนเองweb.xml
(มันจะแยกวิเคราะห์ไฟล์ คำขอส่วนหนึ่งและกรอกแผนที่พารามิเตอร์คำขอปกติเพื่อให้FacesServlet
สามารถทำงานต่อได้ตามปกติ):
<filter>
<filter-name>primeFacesFileUploadFilter</filter-name>
<filter-class>org.primefaces.webapp.filter.FileUploadFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>primeFacesFileUploadFilter</filter-name>
<servlet-name>facesServlet</servlet-name>
</filter-mapping>
<servlet-name>
ค่าของfacesServlet
ต้องตรงกับค่าใน<servlet>
รายการของในที่เดียวกันjavax.faces.webapp.FacesServlet
web.xml
ดังนั้นถ้าเป็นเช่นFaces Servlet
นั้นคุณต้องแก้ไขเพื่อให้เข้ากัน
PrimeFaces 4.x
เรื่องเดียวกับ PrimeFaces 5.x ใช้กับ 4.x เช่นกัน
มีเพียงปัญหาที่อาจเกิดขึ้นในการรับเนื้อหาไฟล์ที่อัปโหลดโดยUploadedFile#getContents()
. สิ่งนี้จะกลับมาnull
เมื่อใช้ API ดั้งเดิมแทน Apache Commons FileUpload คุณจำเป็นต้องใช้UploadedFile#getInputStream()
แทน ดูวิธีแทรกรูปภาพที่อัปโหลดจาก p: fileUpload เป็น BLOB ใน MySQL
ปัญหาที่อาจเกิดขึ้นกับ API เนทีฟอีกประการหนึ่งจะปรากฏขึ้นคือเมื่อส่วนประกอบการอัปโหลดอยู่ในรูปแบบที่มีการเรียกใช้คำขอ ajax "ปกติ" ที่แตกต่างออกไปซึ่งไม่ได้ประมวลผลองค์ประกอบการอัปโหลด ดูเพิ่มเติมการอัปโหลดไฟล์ไม่ทำงานกับ AJAX ใน PrimeFaces 4.0 / JSF 2.2.x - javax.servlet.ServletException: ชนิดเนื้อหาคำขอไม่ใช่ข้อมูลหลายส่วน / แบบฟอร์มmultipart
ปัญหาทั้งสองสามารถแก้ไขได้โดยเปลี่ยนเป็น Apache Commons FileUpload ดูรายละเอียดในส่วน PrimeFaces 3.x
PrimeFaces 3.x
เวอร์ชันนี้ไม่รองรับการอัปโหลดไฟล์เนทีฟ JSF 2.2 / Servlet 3.0 คุณต้องติดตั้ง Apache Commons FileUpload ด้วยตนเองและลงทะเบียนตัวกรองการอัปโหลดไฟล์อย่างชัดเจนในรูปแบบweb.xml
.
คุณต้องการไลบรารีต่อไปนี้:
สิ่งเหล่านี้ต้องมีอยู่ในคลาสพา ธ รันไทม์ของ webapp เมื่อใช้ Maven ตรวจสอบให้แน่ใจว่ามีขอบเขตรันไทม์เป็นอย่างน้อย (ขอบเขตเริ่มต้นของการคอมไพล์ก็ดีเช่นกัน) เมื่อพกพาไปรอบ ๆ JAR ด้วยตนเองตรวจสอบให้แน่ใจว่าพวกเขาอยู่ใน/WEB-INF/lib
โฟลเดอร์
รายละเอียดการลงทะเบียนตัวกรองการอัปโหลดไฟล์สามารถพบได้ในส่วน PrimeFaces 5.x ที่นี่ด้านบน ในกรณีที่คุณใช้ PrimeFaces 4+ และคุณต้องการใช้ Apache Commons FileUpload อย่างชัดเจนแทนการอัปโหลดไฟล์เนทีฟ JSF 2.2 / Servlet 3.0 คุณต้องอยู่ติดกับไลบรารีที่กล่าวถึงและกรองพารามิเตอร์บริบทด้านล่างด้วยweb.xml
:
<context-param>
<param-name>primefaces.UPLOADER</param-name>
<param-value>commons</param-value><!-- Allowed values: auto, native and commons. -->
</context-param>
การแก้ไขปัญหา
ในกรณีที่ยังใช้งานไม่ได้นี่เป็นอีกสาเหตุหนึ่งที่เป็นไปได้ที่ไม่เกี่ยวข้องกับการกำหนดค่า PrimeFaces:
เฉพาะในกรณีที่คุณกำลังใช้การอัปโหลดไฟล์กรอง PrimeFaces: มีผู้อื่นFilter
ใน webapp ของคุณซึ่งจะทำงานก่อนที่จะอัปโหลดไฟล์กรอง PrimeFaces และได้บริโภคแล้วร่างกายคำขอโดยเช่นโทรgetParameter()
, getParameterMap()
,getReader()
, เป็นต้น สามารถแยกวิเคราะห์เนื้อหาคำขอได้เพียงครั้งเดียว เมื่อคุณเรียกใช้วิธีใดวิธีหนึ่งก่อนที่ตัวกรองการอัปโหลดไฟล์จะทำงานตัวกรองการอัปโหลดไฟล์จะได้รับเนื้อหาคำขอว่างเปล่า
เพื่อแก้ไขปัญหานี้คุณจะต้องใส่<filter-mapping>
ของตัวกรองการอัปโหลดไฟล์ก่อนที่จะกรองอื่น web.xml
ๆ หากคำขอไม่ใช่multipart/form-data
คำขอตัวกรองการอัปโหลดไฟล์จะดำเนินต่อไปราวกับว่าไม่มีอะไรเกิดขึ้น หากคุณใช้ตัวกรองที่เพิ่มโดยอัตโนมัติเนื่องจากใช้คำอธิบายประกอบ (เช่น PrettyFaces) คุณอาจต้องเพิ่มการสั่งซื้ออย่างชัดเจนผ่าน web.xml ดูวิธีกำหนดลำดับการเรียกใช้ตัวกรอง servlet โดยใช้คำอธิบายประกอบใน WAR
เฉพาะในกรณีที่คุณใช้ตัวกรองการอัปโหลดไฟล์ PrimeFaces: มีอีกตัวหนึ่งFilter
ในเว็บแอปของคุณซึ่งทำงานก่อนตัวกรองการอัปโหลดไฟล์ PrimeFaces และทำการRequestDispatcher#forward()
โทร โดยปกติแล้วตัวกรองการเขียน URL ใหม่เช่นPrettyFacesจะทำสิ่งนี้ สิ่งนี้จะทริกเกอร์ผู้FORWARD
มอบหมายงาน แต่ตัวกรองจะรับฟังโดยค่าเริ่มต้นในREQUEST
ผู้มอบหมายงานเท่านั้น
ในการแก้ไขปัญหานี้คุณต้องใส่ตัวกรองการอัปโหลดไฟล์ PrimeFaces ก่อนตัวกรองการส่งต่อหรือกำหนดค่าตัวกรองการอัปโหลดไฟล์ PrimeFaces ใหม่เพื่อฟังFORWARD
ผู้มอบหมายงานด้วย:
<filter-mapping>
<filter-name>primeFacesFileUploadFilter</filter-name>
<servlet-name>facesServlet</servlet-name>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
<h:form>
มีที่ซ้อนกันเป็น สิ่งนี้ผิดกฎหมายใน HTML และพฤติกรรมของเบราว์เซอร์ไม่ได้ระบุไว้ บ่อยครั้งที่เบราว์เซอร์จะไม่ส่งข้อมูลที่คาดไว้เมื่อส่ง <h:form>
ตรวจสอบให้แน่ใจว่าคุณไม่ได้ทำรัง enctype
นี้จะสมบูรณ์โดยไม่คำนึงถึงรูปแบบของ เพียงแค่อย่ารังแบบฟอร์มเลย
หากคุณยังคงประสบปัญหาอยู่ให้ดีบักการรับส่งข้อมูล HTTP เปิดชุดเครื่องมือสำหรับนักพัฒนาเว็บเบราว์เซอร์ (กด F12 ใน Chrome / Firebug23 + / IE9 +) และตรวจสอบส่วน Net / Network หากส่วน HTTP ดูดีให้ดีบักโค้ด JSF วางจุดพักFileUploadRenderer#decode()
และเดินหน้าจากที่นั่น
กำลังบันทึกไฟล์ที่อัปโหลด
หลังจากที่คุณใช้งานได้ในที่สุดคำถามถัดไปของคุณอาจเป็นเช่น "ฉันจะบันทึกไฟล์ที่อัปโหลดได้อย่างไร / ที่ไหน" ดียังคงที่นี่: วิธีการบันทึกไฟล์ที่อัปโหลดใน JSF
web.xml
ตามคู่มือผู้ใช้ PrimeFaces คุณอ่านมันหรือไม่? อย่างไรก็ตามนั่นไม่สามารถอธิบายได้ว่าทำไมถึงmode="simple"
เหมาะกับคุณ