Установщик прикладного bean-компонента не может установить значение
Я создаю страницу, используя Primefaces с формой с возможностью ajax-загрузки изображения и предварительного просмотра перед отправкой всей формы.
Чтобы добиться этого, я сделал диалог вне основной формы:
<p:dialog id="imageDlg" header="Load Image" modal="true"
widgetVar="imageUploadWidget">
<h:form id="imageForm" enctype="multipart/form-data">
<p:fileUpload mode="advanced" auto="true" sizeLimit="9999999"
allowTypes="/(\.|\/)(gif|jpe?g|png)$/"
fileUploadListener="#{pageBean.imageUploadHandler}">
</p:fileUpload>
</h:form>
</p:dialog>
Внутри основной формы есть p:graphicImage
компонент для отображения только что загруженного изображения и кнопка для отображения диалога. Страница опирается на область видимости bean (PageBean
), но пройти StreamedContent
в p:graphicImage
Значение bean-компонента должно иметь сессию или область приложения (потому что метод вызывается многократно). Таким образом, я сделал второй бин приложения (ImageBean
) только для этого.
<p:graphicImage value="#{imageBean.imageStreamedContent()}"/>
<p:commandButton value="Choose image" type="button"
onclick="imageUploadWidget.show();"/>
Кодекс ImageBean
:
@ApplicationScoped
@ManagedBean
public class ImagesBean implements Serializable {
private byte[] image;
//getter & setter
public StreamedContent imageStreamedContent() {
FacesContext context = FacesContext.getCurrentInstance();
if (context.getCurrentPhaseId() == PhaseId.RENDER_RESPONSE) {
return new DefaultStreamedContent();
} else {
return new DefaultStreamedContent(new ByteArrayInputStream(getImage()));
}
}
}
Следующая часть fileUploadListener
, Идея проста - установить соответствующие поля PageBean
(чтобы сохранить его позже при отправке формы) ImageBean
(показать его после частичного обновления) и обновить часть основной формы:
@ManagedBean
@ViewScoped
public class PageBean implements Serializable {
@ManagedProperty(value="#{imageBean}")
ImagesBean imagesBean;
...
public void imageUploadHandler(FileUploadEvent event) {
getImagesBean().setImage(event.getFile().getContents());
RequestContext.getCurrentInstance().update("form:tabPanel1");
}
Здесь появляется странная вещь. внутри setImage()
метод все окей - поле установлено, геттер работает нормально. Но тогда страница обновляется, imageBean.getImage()
внутри imageBean.imageStreamedContent()
возвращает ноль.
Точнее - возвращает старое значение, как будто setter никогда не вызывался или вызывался для другого экземпляра bean-компонента. Я проверил это по другому String
поле: инициализировано в ImageBean
конструктор, в обработчике вызвал сеттер с другим значением и обновил часть основной формы. То же самое: старое значение из конструктора.
Я думаю, что мне чего-то не хватает в жизненном цикле бина или конкретной области. Или, может быть, есть менее сложный способ реализации этой задачи?
1 ответ
Существует проблема с использованием StreamedContent в Primefaces для p:graphicImage
а также p:media
,
Вы можете увидеть комментарии Cagatay Civici на эту тему на форуме Primefaces здесь.
По моему опыту, когда у меня была более тонкая (более или менее) проблема, мне помогли эта и эта ответы BalusC.
Я использовал отдельный сервлет вместо Managedbean для потоковой передачи динамического содержимого в p:media
(в моем случае).
Вот мой код для вашей справки (если вам нужен):
PreviewFileServlet.java
@WebServlet("/PreviewFile")
public class PreviewFileServlet extends HttpServlet {
public PreviewFileServlet() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletContext context = request.getServletContext();
String path = request.getParameter("PREVIEW_FILE_PATH");
logger.info("Received pathe for Preview:"+path);
try{
if(null!=path){
java.io.File f = new java.io.File(path);
if(f.exists()){
FileInputStream fin = new FileInputStream(f);
byte b[] = new byte[(int)f.length()];
fin.read(b);
response.setContentLength(b.length);
response.setContentType(context.getMimeType(path));
response.getOutputStream().write(b);
response.getOutputStream().close();
logger.info("File sent successfully for Preview.");
}
else{
logger.warn("File sepecified by path:-"+path+"-:, NOT found");
}
}
}catch(Exception e){
}
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
Facelet Code
<p:media value="/PreviewFile?PREVIEW_FILE_PATH=#{fileManager.previewFilePath}" />
Надеюсь это поможет. И есть много вопросов по этой теме о StreamedContent в самом стеке потока, пройдитесь по ним один раз.