PrimeFaces p : fileUpload를 사용하는 방법? 리스너 메소드가 호출되지 않거나 UploadedFile이 널 (null) / 오류 발생 / 사용 불가능


101

PrimeFaces를 사용하여 파일을 업로드하려고하는데 fileUploadListener업로드가 완료된 후 메서드가 호출되지 않습니다.

보기는 다음과 같습니다.

<h:form>
    <p:fileUpload fileUploadListener="#{fileUploadController.handleFileUpload}"
        mode="advanced" 
        update="messages"
        sizeLimit="100000" 
        allowTypes="/(\.|\/)(gif|jpe?g|png)$/"/>

    <p:growl id="messages" showDetail="true"/>
</h:form>

그리고 콩 :

@ManagedBean
@RequestScoped
public class FileUploadController {

    public void handleFileUpload(FileUploadEvent event) {
        FacesMessage msg = new FacesMessage("Succesful", event.getFile().getFileName() + " is uploaded.");
        FacesContext.getCurrentInstance().addMessage(null, msg);
    }

}

메서드에 중단 점을 두었지만 호출되지 않았습니다. mode="simple"및을 사용할 때 ajax="false"호출되었지만 고급 모드에서 작동하기를 원합니다. Netbeans 및 Glassfish 3.1을 사용하고 있습니다.

답변:


224

구성 및 문제 해결 방법 <p:fileUpload>은 PrimeFaces 버전에 따라 다릅니다.

모든 PrimeFaces 버전

아래 요구 사항은 모든 PrimeFaces 버전에 적용됩니다.

  1. enctype속성 <h:form>을로 설정해야 multipart/form-data합니다. 이것이 없으면 ajax 업로드가 작동 할 수 있지만 일반적인 브라우저 동작은 지정되지 않으며 양식 구성 및 웹 브라우저 만들기 / 버전에 따라 다릅니다. 항상 안전한쪽에 있도록 지정하십시오.

  2. 사용할 때 mode="advanced"(즉, ajax 업로드, 이것이 기본값), <h:head>(마스터) 템플릿에 있는지 확인하십시오 . 이렇게하면 필요한 JavaScript 파일이 제대로 포함됩니다. 이것은 mode="simple"(AJAX가 아닌 업로드)에는 필요하지 않지만 다른 모든 PrimeFaces 구성 요소의 모양과 기능이 깨질 수 있으므로 어쨌든 놓치고 싶지 않습니다.

  3. 사용하는 경우 mode="simple"(즉, ajax가 아닌 업로드) PrimeFaces 명령 단추 / 링크에서를 사용하여 ajax를 비활성화해야하며 (PrimeFaces <= 7.x의 경우) 또는 (PrimeFaces> = 8.x의 경우) 대신 with ajax="false"를 사용해야합니다.<p:fileUpload value><p:commandButton action><p:fileUpload fileUploadListener><p:fileUpload listener>

따라서 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!
}

메모를 수행 같은 AJAX 관련 특성이 auto, allowTypes, update,onstart , oncomplete, 등이있다 무시 에를 mode="simple". 따라서 이러한 경우 지정할 필요가 없습니다.

또한 나중에 HTTP 요청에 의해 호출 된 다른 Bean 메소드가 아니라 위에 언급 된 메소드 내에서 즉시 파일 내용을 읽어야합니다 . 이는 업로드 된 파일 내용이 요청 범위이므로 이후 / 다른 HTTP 요청에서 사용할 수 없기 때문입니다. 이후 요청에서이를 읽으려는 시도는 대부분 java.io.FileNotFoundException임시 파일에서 끝날 것입니다 .


PrimeFaces 8.x

구성은 아래 5.x 버전 정보와 동일하지만 리스너가 호출되지 않은 경우 속성이 호출되었는지 확인하십시오 listener(8.x 이전 버전과 같이).fileUploadListener

PrimeFaces 5.x

JSF 2.2를 사용하고 있으며 faces-config.xmlJSF 2.2 버전을 준수하는 것으로 선언 된 경우 추가 구성이 필요하지 않습니다 . PrimeFaces 파일 업로드 필터는 전혀 필요하지 않습니다. 사용하는 대상 서버에 따라 JSF를 올바르게 설치하고 구성하는 방법이 명확하지 않은 경우 Maven을 통해 JSF 라이브러리를 올바르게 설치하고 구성하는 방법을 참조하십시오. 그리고 우리의 JSF 위키 페이지의 섹션 "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.FacesServletweb.xmlFaces Servlet


PrimeFaces 4.x

PrimeFaces 5.x와 동일한 이야기가 4.x에도 적용됩니다.

에 의해 업로드 된 파일 콘텐츠를 가져 오는 데는 잠재적 인 문제 만 있습니다 UploadedFile#getContents(). nullApache Commons FileUpload 대신 네이티브 API를 사용할 때 반환 됩니다. UploadedFile#getInputStream()대신 사용해야 합니다. p : fileUpload에서 업로드 된 이미지를 MySQL에서 BLOB로 삽입하는 방법 도 참조하십시오 .

네이티브 API의 또 다른 잠재적 인 문제는 업로드 구성 요소를 처리하지 않는 다른 "일반"ajax 요청이 실행되는 양식에 업로드 구성 요소가있는 경우입니다. PrimeFaces 4.0 / JSF 2.2.x-javax.servlet.ServletException : The request content-type is not a multipart / form-data에서 파일 업로드가 AJAX에서 작동하지 않음을 참조하십시오 .

두 문제 모두 Apache Commons FileUpload로 전환하여 해결할 수도 있습니다. 자세한 내용은 PrimeFaces 3.x 섹션을 참조하십시오.


PrimeFaces 3.x

이 버전은 JSF 2.2 / Servlet 3.0 기본 파일 업로드를 지원하지 않습니다. Apache Commons FileUpload를 수동으로 설치하고 파일 업로드 필터를 web.xml.

다음 라이브러리가 필요합니다.

웹앱의 런타임 클래스 경로에 있어야합니다. Maven을 사용할 때 최소한 런타임 범위인지 확인하십시오 (기본 컴파일 범위도 좋습니다). JAR을 수동으로 운반 할 때 /WEB-INF/lib폴더에 있는지 확인하십시오 .

파일 업로드 필터 등록 세부 정보는 위의 PrimeFaces 5.x 섹션에서 찾을 수 있습니다. PrimeFaces 4+를 사용하고 JSF 2.2 / Servlet 3.0 기본 파일 업로드 대신 Apache Commons FileUpload를 명시 적으로 사용하려는 경우 언급 된 라이브러리 옆에 다음 컨텍스트 매개 변수도 필터링해야합니다 web.xml.

<context-param>
    <param-name>primefaces.UPLOADER</param-name>
    <param-value>commons</param-value><!-- Allowed values: auto, native and commons. -->
</context-param>

문제 해결

여전히 작동하지 않는 경우 PrimeFaces 구성과 관련이없는 또 다른 가능한 원인은 다음과 같습니다.

  1. 당신이 PrimeFaces 파일 업로드 필터를 사용하는 경우에만 : 다른있다 Filter실행되는 사용자의 웹 애플리케이션에서 전에 PrimeFaces 파일 업로드 필터 이미 예를 들어 호출에 의해 요청 본문을 소비하고있다 getParameter(), getParameterMap(), getReader(), 등등. 요청 본문은 한 번만 구문 분석 할 수 있습니다. 파일 업로드 필터가 작업을 수행하기 전에 이러한 메서드 중 하나를 호출하면 파일 업로드 필터가 빈 요청 본문을 가져옵니다.

    이 문제를 해결하려면 <filter-mapping>파일 업로드 필터 의를 다른 필터 앞에 넣어야합니다 web.xml. 요청이 요청이 아닌 경우 multipart/form-data파일 업로드 필터는 아무 일도 일어나지 않은 것처럼 계속됩니다. 주석 (예 : PrettyFaces)을 사용하기 때문에 자동으로 추가되는 필터를 사용하는 경우 web.xml을 통해 명시 적 순서를 추가해야 할 수 있습니다. WAR에서 주석을 사용하여 서블릿 필터 실행 순서를 정의하는 방법을 참조하십시오.

  2. 당신이 PrimeFaces 파일 업로드 필터를 사용하는 경우에만 : 다른있다 Filter실행하여 웹 애플리케이션에서 전에 PrimeFaces 파일 업로드 필터와 수행 RequestDispatcher#forward()호출. 일반적으로 PrettyFaces 와 같은 URL 재 작성 필터 가이를 수행합니다. 이는 FORWARD디스패처를 트리거 하지만 필터는 기본적으로 REQUEST디스패처에서만 수신 합니다.

    이 문제를 해결하려면 전달 필터 앞에 PrimeFaces 파일 업로드 필터 배치하거나 FORWARD디스패처에서도 수신하도록 PrimeFaces 파일 업로드 필터를 재구성해야합니다 .

    <filter-mapping>
        <filter-name>primeFacesFileUploadFilter</filter-name>
        <servlet-name>facesServlet</servlet-name>
        <dispatcher>REQUEST</dispatcher>
        <dispatcher>FORWARD</dispatcher>
    </filter-mapping>
  3. 중첩 된 <h:form>. 이것은 HTML에서 불법이며 브라우저 동작은 지정되지 않습니다. 종종 브라우저는 제출시 예상 데이터를 보내지 않습니다. 중첩되지 않았는지 확인하십시오 <h:form>. 이것은 양식의 enctype. 양식을 전혀 중첩하지 마십시오.

여전히 문제가있는 경우 HTTP 트래픽을 디버그하십시오. 웹 브라우저의 개발자 도구 모음을 열고 (Chrome / Firebug23 + / IE9 +에서 F12 누르기) Net / Network 섹션을 확인합니다. HTTP 부분이 괜찮아 보이면 JSF 코드를 디버그하십시오. 중단 점을 설정 FileUploadRenderer#decode()하고 거기에서 진행하십시오.


업로드 된 파일 저장

마침내 작동하게 된 후 다음 질문은 아마도 "업로드 된 파일을 어떻게 / 어디에 저장합니까?"와 같을 것입니다. 음, 계속 여기 : 업로드 된 파일을 JSF에 저장하는 방법 .


2
또 다른 원인은 web.xmlPrimeFaces 사용자 가이드 에 따라 PrimeFaces 업로드 필터를 등록하지 않았기 때문일 수 있습니다 . 어쨌든 읽어 봤어? 그러나 그것은 왜 mode="simple"당신에게 효과가 있는지 설명하지 않습니다 .
BalusC

1
예, 읽었고 필터를 등록했지만 "SEVERE : WebModule [/ EventsCalendary] PWC1270 : Exception starting filter PrimeFaces FileUpload Filter"서버를 시작할 때 오류가 발생한다는 것을 알았습니다. 전에 알아 차 렸습니다. 이 오류를 해결하기위한 팁이 있습니까?
Rodrigo Cavalcante 2012 년

2
필터 매핑이 잘못되었을 수 있습니다. <servlet-name>에서 정의 FacesServlet한대로 의 에 매핑되어야 web.xml합니다. 대부분의 IDE / 코드 생성기에서 기본값 Faces Servlet은으로 설정되어 있지만 facesServlet이름 지정 규칙을 확인하는 것과 같을 수도 있습니다 .
BalusC

2
Nevermind는 commons-fileupload를 classpath 및 commons-io에 추가하여 해결했습니다. 이러한 라이브러리가 필요하다고 말하는 곳이 있습니까? 어쨌든, 모든 것이 바로 지금 작동하는 것 같습니다. 메서드가 예상대로 호출되고 있습니다. 감사합니다.
Rodrigo Cavalcante 2012 년


30

당신도 prettyfaces를 사용하고 있습니까? 그런 다음 발송자를 FORWARD로 설정합니다.

<filter-mapping>
   <filter-name>PrimeFaces FileUpload Filter</filter-name>
   <servlet-name>Faces Servlet</servlet-name>
   <dispatcher>FORWARD</dispatcher>
</filter-mapping>

이것은 OCP Rewrite와 함께 사용할 때 여전히 문제입니다. 나는 당신에게 맥주를 빚지고 있습니다 :)
Babl

7

Primefaces 3.4 및 Netbeans 7.2에서 주목 한 한 가지 사항 :

handleFileUpload 즉 (이벤트) 함수에 대한 Netbeans 자동 입력 매개 변수를 제거합니다. 그렇지 않으면 이벤트가 null이 될 수 있습니다.

<h:form>
    <p:fileUpload fileUploadListener="#{fileUploadController.handleFileUpload(event)}"
        mode="advanced" 
        update="messages"
        sizeLimit="100000" 
        allowTypes="/(\.|\/)(gif|jpe?g|png)$/"/>

    <p:growl id="messages" showDetail="true"/>
</h:form>


0

나는 프라임 페이스 5.3에서 같은 문제를 겪었고 BalusC에서 설명하는 모든 요점을 아무런 결과도 얻지 못했습니다. FileUploadRenderer # decode () 디버깅에 대한 그의 조언을 따랐고 내 web.xml이 부적절하게 설정되었음을 발견했습니다.

<context-param>
  <param-name>primefaces.UPLOADER</param-name>
  <param-value>auto|native|commons</param-value>
</context-param>

param-value는이 3 개의 값 중 하나 여야하지만 전부는 아닙니다 !! 전체 context-param 섹션을 제거 할 수 있으며 기본값은 자동입니다.


0

bean.xhtml

    <h:form enctype="multipart/form-data">    
<p:outputLabel value="Choose your file" for="submissionFile" />
                <p:fileUpload id="submissionFile"
                    value="#{bean.file}"
                    fileUploadListener="#{bean.uploadFile}" mode="advanced"
                    auto="true" dragDropSupport="false" update="messages"
                    sizeLimit="100000" fileLimit="1" allowTypes="/(\.|\/)(pdf)$/" />

</h:form>

Bean.java

@ManagedBean

@ViewScoped 공용 클래스 제출은 Serializable {을 구현합니다.

private UploadedFile file;

//Gets
//Sets

public void uploadFasta(FileUploadEvent event) throws FileNotFoundException, IOException, InterruptedException {

    String content = IOUtils.toString(event.getFile().getInputstream(), "UTF-8");

    String filePath = PATH + "resources/submissions/" + nameOfMyFile + ".pdf";

    MyFileWriter.writeFile(filePath, content);

    FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_INFO,
            event.getFile().getFileName() + " is uploaded.", null);
    FacesContext.getCurrentInstance().addMessage(null, message);

}

}

web.xml

    <servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
<filter>
    <filter-name>PrimeFaces FileUpload Filter</filter-name>
    <filter-class>org.primefaces.webapp.filter.FileUploadFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>PrimeFaces FileUpload Filter</filter-name>
    <servlet-name>Faces Servlet</servlet-name>
</filter-mapping>

이것이 왜 대답인지 설명해 주시겠습니까? 그것은 단지 코드가 아닌 설명 또는 무엇
Kukeltje

"# {bean.uploadFile}"대 "# {bean.uploadFasta}", update = "messages"를 제거하면 저에게만 작동합니다!
romsky

0

여기에 제시된 제안 중 어느 것도 도움이되지 않았습니다. 그래서 프라임 페이스를 디버깅해야했고 문제의 원인은 다음과 같습니다.

java.lang.IllegalStateException: No multipart config for servlet fileUpload

그런 다음 web.xml의 faces 서블릿에 섹션을 추가했습니다. 그래서 문제가 해결되었습니다.

<servlet>
    <servlet-name>main</servlet-name>

        <servlet-class>org.apache.myfaces.webapp.MyFacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
        <multipart-config>
            <location>/tmp</location>
            <max-file-size>20848820</max-file-size>
            <max-request-size>418018841</max-request-size>
            <file-size-threshold>1048576</file-size-threshold>
        </multipart-config>
    </servlet>

0

이 게시물에서 설명하는 모든 구성이 있었기 때문에 동일한 문제가 발생했지만 제 경우에는 두 개의 jquery 가져 오기 (하나는 프라임 페이스의 쿼리였습니다)가있어 파일 업로드 충돌이 발생했기 때문입니다.

Primefaces Jquery 충돌 참조


브라우저 개발자 콘솔에서 특정 오류가 발생하지 않았습니까?
Kukeltje

이 콘솔이 보였다 무엇 @Kukeltje : catch되지 않은 형식 오류가 : 개체 [개체 개체]있는 방법 '파일 업로드'가 없다
기독교 알타미라노 아얄라

0

Tomee 또는 Tomcat을 사용하고 작동하지 않는 사람들의 경우 META-INF 에서 context.xml 을 만들고 allowCasualMultipartParsing = "true"를 추가하십시오.

<?xml version="1.0" encoding="UTF-8"?>
<Context allowCasualMultipartParsing="true">
  <!-- empty or not depending your project -->
</Context>

이것은 잘못된 필터 구성 / 순서에 대한 해결 방법입니다.
BalusC

안녕하세요 @BalusC, 더 설명해 주시겠습니까? 이 해결 방법보다 더 좋은 방법이 있습니까?
Xavier Lambros 2019

이 질문에서 내 대답을 참조하십시오.
BalusC

0

JBoss 7.2 (Undertow) 및 PrimeFaces 6.0에서는 org.primefaces.webapp.filter.FileUploadFilter를 web.xml에서 제거하고 컨텍스트 매개 변수 파일 업 로더를 기본으로 설정해야합니다.

<context-param>
    <param-name>primefaces.UPLOADER</param-name>
    <param-value>native</param-value>
</context-param>

할까요? 당신은받을 수 있나요 특정 오류를 그렇게하지 않으면?
Kukeltje

예,이 변경 사항 없이는 FileUploadEvent가 호출되지 않습니다.
Alex D

즉, 그 예기치 않은 동작이 명시 적으로 오류가 발생하지 않습니다
Kukeltje
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.