Установщик прикладного 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 в самом стеке потока, пройдитесь по ним один раз.

Другие вопросы по тегам