Cách cấu hình và khắc phục sự cố <p:fileUpload>
phụ thuộc vào phiên bản PrimeFaces.
Tất cả các phiên bản PrimeFaces
Các yêu cầu dưới đây áp dụng cho tất cả các phiên bản PrimeFaces:
Các enctype
thuộc tính của <h:form>
cần phải được thiết lập để multipart/form-data
. Khi điều này không có, tải lên ajax có thể hoạt động, nhưng hoạt động chung của trình duyệt là không xác định và phụ thuộc vào thành phần biểu mẫu và phiên bản / chế tạo trình duyệt web. Chỉ cần luôn chỉ định nó ở bên an toàn.
Khi sử dụng mode="advanced"
(tức là tải lên ajax, đây là mặc định), hãy đảm bảo rằng bạn đã có <h:head>
trong mẫu (chính). Điều này sẽ đảm bảo rằng các tệp JavaScript cần thiết được đưa vào đúng cách. Điều này không bắt buộc đối với mode="simple"
(tải lên không ajax), nhưng điều này sẽ phá vỡ giao diện và chức năng của tất cả các thành phần PrimeFaces khác, vì vậy bạn không muốn bỏ lỡ điều đó.
Khi sử dụng mode="simple"
(tức là tải lên không phải ajax), thì ajax phải được tắt trên bất kỳ nút / liên kết lệnh PrimeFaces nào bằng ajax="false"
và bạn phải sử dụng <p:fileUpload value>
với <p:commandButton action>
thay vì <p:fileUpload fileUploadListener>
(đối với PrimeFaces <= 7.x) hoặc <p:fileUpload listener>
(đối với PrimeFaces> = 8.x)
Vì vậy, nếu bạn muốn tải lên tệp (tự động) với hỗ trợ ajax (hãy lưu ý <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!
}
Hoặc nếu bạn muốn tải lên tệp không phải 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!
}
Do lưu ý rằng thuộc tính ajax-liên quan như auto
, allowTypes
, update
, onstart
, oncomplete
, vv được bỏ qua trong mode="simple"
. Vì vậy, không cần thiết phải chỉ định chúng trong trường hợp như vậy.
Cũng lưu ý rằng bạn nên đọc nội dung tệp ngay bên trong các phương thức được đề cập ở trên chứ không phải trong một phương thức bean khác được gọi bởi một yêu cầu HTTP sau này. Điều này là do nội dung tệp được tải lên nằm trong phạm vi yêu cầu và do đó không khả dụng trong một yêu cầu HTTP sau / khác. Bất kỳ nỗ lực nào để đọc nó trong một yêu cầu sau đó rất có thể sẽ kết thúc với java.io.FileNotFoundException
tệp tạm thời.
PrimeFaces 8.x
Cấu hình giống với thông tin phiên bản 5.x bên dưới, nhưng nếu trình nghe của bạn không được gọi, hãy kiểm tra xem tập tin đính kèm có được gọi listener
hay không (giống như với các phiên bản 8.x trước)fileUploadListener
PrimeFaces 5.x
Điều này không yêu cầu bất kỳ cấu hình bổ sung nào nếu bạn đang sử dụng JSF 2.2 và faces-config.xml
phiên bản JSF 2.2 của bạn cũng được khai báo là phù hợp. Bạn hoàn toàn không cần bộ lọc tải lên tệp PrimeFaces. Trong trường hợp bạn chưa rõ cách cài đặt và định cấu hình JSF đúng cách tùy thuộc vào máy chủ đích được sử dụng, hãy xem Cách cài đặt và cấu hình thư viện JSF đúng cách qua Maven? và phần "Cài đặt JSF" trên trang wiki JSF của chúng tôi .
Tuy nhiên, nếu bạn vẫn chưa sử dụng JSF 2.2 và bạn không thể nâng cấp nó (sẽ dễ dàng khi đã ở trên vùng chứa tương thích Servlet 3.0), thì bạn cần đăng ký thủ công bộ lọc tải lên tệp PrimeFaces bên dưới web.xml
(nó sẽ phân tích cú pháp đa một phần yêu cầu và điền vào bản đồ tham số yêu cầu thông thường để FacesServlet
có thể tiếp tục hoạt động như bình thường):
<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>
Các <servlet-name>
giá trị facesServlet
phải phù hợp chính xác giá trị trong <servlet>
entry của javax.faces.webapp.FacesServlet
trong cùng web.xml
. Vì vậy, nếu nó là ví dụ Faces Servlet
, thì bạn cần phải chỉnh sửa nó cho phù hợp.
PrimeFaces 4.x
Câu chuyện tương tự như PrimeFaces 5.x cũng áp dụng trên 4.x.
Chỉ có một vấn đề tiềm ẩn trong việc tải lên nội dung tệp UploadedFile#getContents()
. Điều này sẽ trở lại null
khi API gốc được sử dụng thay vì Apache Commons FileUpload. Bạn cần sử dụng UploadedFile#getInputStream()
thay thế. Xem thêm Cách chèn hình ảnh đã tải lên từ p: fileUpload dưới dạng BLOB trong MySQL?
Một vấn đề tiềm ẩn khác với API gốc sẽ hiển thị là khi thành phần tải lên có trong biểu mẫu mà trên đó kích hoạt một yêu cầu ajax "thông thường" khác, không xử lý thành phần tải lên. Xem thêm Tải lên tệp không hoạt động với AJAX trong PrimeFaces 4.0 / JSF 2.2.x - javax.servlet.ServletException: Loại nội dung yêu cầu không phải là đa phần / biểu mẫu-dữ liệu .
Cả hai vấn đề cũng có thể được giải quyết bằng cách chuyển sang Apache Commons FileUpload. Xem phần PrimeFaces 3.x để biết thêm chi tiết.
PrimeFaces 3.x
Phiên bản này không hỗ trợ tải lên tệp gốc JSF 2.2 / Servlet 3.0. Bạn cần cài đặt Apache Commons FileUpload theo cách thủ công và đăng ký rõ ràng bộ lọc tải lên tệp trong đó web.xml
.
Bạn cần các thư viện sau:
Chúng phải có trong classpath thời gian chạy của ứng dụng web. Khi sử dụng Maven, hãy đảm bảo rằng chúng có ít nhất phạm vi thời gian chạy (phạm vi biên dịch mặc định cũng tốt). Khi mang theo các JAR theo cách thủ công, hãy đảm bảo chúng nằm trong /WEB-INF/lib
thư mục.
Bạn có thể tìm thấy chi tiết đăng ký bộ lọc tải lên tệp trong phần PrimeFaces 5.x ở trên. Trong trường hợp bạn đang sử dụng PrimeFaces 4+ và bạn muốn sử dụng Apache Commons FileUpload một cách rõ ràng thay vì tải lên tệp gốc JSF 2.2 / Servlet 3.0, thì bạn cần bên cạnh các thư viện được đề cập và lọc cả thông số ngữ cảnh bên dưới trong web.xml
:
<context-param>
<param-name>primefaces.UPLOADER</param-name>
<param-value>commons</param-value><!-- Allowed values: auto, native and commons. -->
</context-param>
Xử lý sự cố
Trong trường hợp nó vẫn không hoạt động, đây là một nguyên nhân có thể khác không liên quan đến cấu hình PrimeFaces:
Chỉ khi bạn đang sử dụng bộ lọc upload PrimeFaces file: Có một Filter
trong webapp của bạn chạy trước khi bộ lọc upload PrimeFaces tập tin và đã tiêu thụ cơ thể theo yêu cầu của ví dụ gọi điện thoại getParameter()
, getParameterMap()
, getReader()
, Etcetera. Nội dung yêu cầu chỉ có thể được phân tích cú pháp một lần. Khi bạn gọi một trong những phương thức đó trước khi bộ lọc tải lên tệp thực hiện công việc của nó, thì bộ lọc tải tệp lên sẽ nhận được một nội dung yêu cầu trống.
Để khắc phục điều này, bạn cần đặt <filter-mapping>
bộ lọc tải tệp lên trước bộ lọc khác web.xml
. Nếu yêu cầu không phải là multipart/form-data
yêu cầu, thì bộ lọc tải lên tệp sẽ tiếp tục như thể không có gì xảy ra. Nếu bạn sử dụng các bộ lọc được thêm tự động vì chúng sử dụng chú thích (ví dụ: PrettyFaces), bạn có thể cần thêm thứ tự rõ ràng qua web.xml. Xem Cách xác định thứ tự thực thi bộ lọc servlet bằng cách sử dụng chú thích trong WAR
Chỉ khi bạn đang sử dụng bộ lọc tải lên tệp PrimeFaces: Có một bộ lọc khác Filter
trong ứng dụng web của bạn chạy trước bộ lọc tải lên tệp PrimeFaces và đã thực hiện RequestDispatcher#forward()
lệnh gọi. Thông thường, các bộ lọc ghi lại URL như PrettyFaces thực hiện việc này. Điều này kích hoạt FORWARD
điều phối viên, nhưng các bộ lọc chỉ lắng nghe theo mặc định trên REQUEST
điều phối viên.
Để khắc phục điều này, bạn cần đặt bộ lọc tải lên tệp PrimeFaces trước bộ lọc chuyển tiếp hoặc định cấu hình lại bộ lọc tải lên tệp PrimeFaces để lắng nghe FORWARD
điều phối viên:
<filter-mapping>
<filter-name>primeFacesFileUploadFilter</filter-name>
<servlet-name>facesServlet</servlet-name>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
Có một lồng nhau <h:form>
. Điều này là bất hợp pháp trong HTML và hành vi của trình duyệt là không xác định. Thông thường, trình duyệt sẽ không gửi dữ liệu mong đợi khi gửi. Đảm bảo rằng bạn không làm tổ <h:form>
. Điều này hoàn toàn không phụ thuộc vào hình thức enctype
. Chỉ cần không tổ chức các hình thức ở tất cả.
Nếu bạn vẫn gặp sự cố, hãy gỡ lỗi lưu lượng HTTP. Mở bộ công cụ dành cho nhà phát triển của trình duyệt web (nhấn F12 trong Chrome / Firebug23 + / IE9 +) và kiểm tra phần Mạng / Mạng. Nếu phần HTTP trông ổn, thì hãy gỡ lỗi mã JSF. Đặt một điểm dừng FileUploadRenderer#decode()
và tiến lên từ đó.
Lưu tệp đã tải lên
Sau khi bạn cuối cùng đã làm cho nó hoạt động, câu hỏi tiếp theo của bạn có thể sẽ là "Làm thế nào / ở đâu để lưu tệp đã tải lên?". Vâng, tiếp tục ở đây: Cách lưu tệp đã tải lên trong JSF .
web.xml
PrimeFaces theo Hướng dẫn người dùng PrimeFaces. Bạn đã đọc nó anyway? Tuy nhiên, điều đó sẽ không giải thích tại sao lại hiệumode="simple"
quả với bạn.