【问题标题】:JSF 2.0 File uploadJSF 2.0 文件上传
【发布时间】:2011-07-22 01:21:37
【问题描述】:

我正在浏览一些博客,试图找到如何使用 JSF 2.0 上传文件 但是所有的解决方案都让我感到困惑。我想知道我究竟需要什么才能成功上传文件(MP3、PDF、视频......无论输入什么类型)并将其作为@Lob 存储在数据库中。 这是我到目前为止所做的:

  • 我创建了一个具有 byte[] 类型属性的实体,并且还使用 @Lob 注释进行了注释。

  • 我创建了一个 EJB,它将使用以 byte[] 作为参数的方法引入实体,并使用 EntityManager 类(持久方法)将其插入数据库。

  • 我创建了一个带有“文件”类型的输入标签和一个提交按钮的 JSF 页面

  • 我准备了一个托管 bean 来与 JSF 页面交换有关文件的信息。

现在我被卡住了,我有很多疑问:

  • 我应该怎么做才能将文件从 JSF 传递到托管 bean,然后将其转换为 byte[](以便能够将其处理到 EJB)?

  • servlet 如何帮助我?

  • 我需要一个 servlet 来执行此操作吗?

  • 另外我发现在一些博客中提到了一些关于 servlets 3.0 的内容,但是我不知道我的工作环境是否在使用它,如果我使用的是 servlets 3.0(我使用的是 JEE6)怎么办?

我以前从未上传过文件,而且我对 servlet 也不是很熟悉。我很困惑,有人可以给我一些入门提示吗?

【问题讨论】:

标签: jsf file-upload jsf-2


【解决方案1】:

首先,这个(旧)问题和答案假定 JSF 2.0/2.1。从 JSF 2.2 开始,有一个原生的 &lt;h:inputFile&gt; 组件,不需要 3rd 方组件库。另见How to upload file using JSF 2.2 <h:inputFile>? Where is the saved File?


最简单的方法是使用Tomahawk for JSF 2.0。它提供了一个&lt;t:inputFileUpload&gt; 组件。

这是一个分步教程:

  • 为 Servlet 3.0 和 JSF 2.0 创建一个空白的动态 Web 项目。 web.xml 必须符合 Servlet 3.0 规范并且已经包含 JSF servlet:

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app 
        xmlns="http://java.sun.com/xml/ns/javaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
        id="YourProjectName" version="3.0">
    
        <display-name>Your Project Name</display-name>
    
        <servlet>
            <servlet-name>Faces Servlet</servlet-name>
            <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
            <load-on-startup>1</load-on-startup>
        </servlet>
        <servlet-mapping>
            <servlet-name>Faces Servlet</servlet-name>
            <url-pattern>*.xhtml</url-pattern>
        </servlet-mapping>
    
    </web-app>
    

    faces-config.xml 必须符合 JSF 2.0 规范:

    <?xml version="1.0" encoding="UTF-8"?>
    <faces-config
        xmlns="http://java.sun.com/xml/ns/javaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"
        version="2.0">
    
    </faces-config>
    

  • 下载Tomahawk 1.1.10 for JSF 2.0。解压 zip 文件,转到/lib 文件夹并将所有*.jar 文件复制到您的/WEB-INF/lib 中。

    共有18个文件,其中batik*.jarxml*.jar对于单独使用t:inputFileUpload组件是不必要的。你可以离开他们。


  • web.xml 中配置 Tomahawk 扩展过滤器。它负责处理multipart/form-data 请求,这是能够通过 HTTP 发送文件所必需的。

    <filter>
        <filter-name>MyFacesExtensionsFilter</filter-name>
        <filter-class>org.apache.myfaces.webapp.filter.ExtensionsFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>MyFacesExtensionsFilter</filter-name>
        <servlet-name>Faces Servlet</servlet-name>
    </filter-mapping>
    

    请注意,&lt;servlet-name&gt; 必须与您在 web.xml 中定义的 FacesServlet&lt;servlet-name&gt; 完全匹配。


  • 创建一个简单的 Facelet,upload.xhtml

    <!DOCTYPE html>
    <html lang="en"
        xmlns="http://www.w3.org/1999/xhtml"
        xmlns:f="http://java.sun.com/jsf/core"
        xmlns:h="http://java.sun.com/jsf/html"
        xmlns:t="http://myfaces.apache.org/tomahawk"
        xmlns:ui="http://java.sun.com/jsf/facelets">
        <h:head>
            <title>Tomahawk file upload demo</title>
        </h:head>
        <h:body>
            <h:form enctype="multipart/form-data">
                <t:inputFileUpload value="#{bean.uploadedFile}" />
                <h:commandButton value="submit" action="#{bean.submit}" />
                <h:messages />
            </h:form>
        </h:body> 
    </html>
    

    注意&lt;h:form&gt; 上的enctype="multipart/form-data" 属性,这对于能够使用HTTP 发送文件非常重要。


  • 创建一个简单的托管 bean,com.example.Bean

    package com.example;
    
    import java.io.IOException;
    
    import javax.faces.application.FacesMessage;
    import javax.faces.bean.ManagedBean;
    import javax.faces.bean.RequestScoped;
    import javax.faces.context.FacesContext;
    
    import org.apache.commons.io.FilenameUtils;
    import org.apache.myfaces.custom.fileupload.UploadedFile;
    
    @ManagedBean
    @RequestScoped
    public class Bean {
    
        private UploadedFile uploadedFile;
    
        public void submit() throws IOException {
            String fileName = FilenameUtils.getName(uploadedFile.getName());
            String contentType = uploadedFile.getContentType();
            byte[] bytes = uploadedFile.getBytes();
    
            // Now you can save bytes in DB (and also content type?)
    
            FacesContext.getCurrentInstance().addMessage(null, 
                new FacesMessage(String.format("File '%s' of type '%s' successfully uploaded!", fileName, contentType)));
        }
    
        public UploadedFile getUploadedFile() {
            return uploadedFile;
        }
    
        public void setUploadedFile(UploadedFile uploadedFile) {
            this.uploadedFile = uploadedFile;
        }
    
    }
    

应该是这样的。通过http://localhost:8080/projectname/upload.xhtml打开它。

关于你的具体问题:

我应该怎么做才能将文件从 JSF 传递到托管 bean,然后将其转换为 byte[](以便能够将其处理到 EJB)?

上面已经回答了。

servlet 如何帮助我?

它能够处理和控制 HTTP 请求/响应。在 JSF 环境中,FacesServlet 已经完成了所有工作。

我需要一个 servlet 来执行此操作吗?

在 JSF 环境中,FacesServlet 是强制性的。但是API已经提供了,不需要自己写。但是,为了能够从数据库下载文件,另一个 servlet 绝对有用。您可以在这里找到一个基本示例:Servlet for serving static content

我还发现在一些博客中提到了一些关于 servlets 3.0 的内容,但我不知道我的工作环境是否正在使用它,如果我正在使用 servlets 3.0(我正在使用 JEE6)怎么办?

如果您使用 Servlet 3.0 容器,如 Glassfish 3、JBoss AS 6、Tomcat 7 等,并且 web.xml 被声明为 Servlet 3.0,那么您肯定使用的是 Servlet 3.0。 Servlet 3.0 是 Java EE 6 的一部分。

【讨论】:

  • 我都做到了。看起来没问题,我没有更多错误,但看起来我无法将该字节 [] 保存到数据库中。我打开了一个新问题,并逐步解释了我所做的一切:stackoverflow.com/questions/5431512/…
  • 试过这个方法,有一些问题。 Netbeans 仅在 http://myfaces.apache.org/tomahawk 命名空间 inputHtml 中找到单个标记。经过一番调查,我发现这是META-INF.resources.org.apache.myfaces.custom 包中的唯一文件。我仍然可以使用该组件,它似乎具有完整的功能,但我收到警告:JSF1064: Unable to find or serve resource, inputFileUpload.xhtml, from library, org.apache.myfaces.custom。知道这是关于什么的吗?我看到其他人问过同样的问题,但这些帖子上的答案总是 0。
  • 很好的答案,谢谢!我在 Java 6 中运行时遇到的一个问题:在服务器启动时我得到了这个:javax.faces.FacesException: java.lang.ClassNotFoundException: [Ljava.lang.String;,我在这里找到了解决方案:java.net/node/656623。总之,将其添加到服务器的启动选项中:-Dsun.lang.ClassLoader.allowArraySyntax=true
  • 嗨 BaluC 感谢您的解决方案,但解决方案似乎不适用于 windows 上的 TomEE 1.5.2 / CODI。我有一个页面,其中包含 primefaces 表单和 tomahawk 子表单以及 tomahawk inputfileuploads。没有为 fileUpload 调用 getter/setter 方法,我在托管 bean 中使用来自 CODI 的 @ConversationScoped。战斧配置如您所述。请让我知道我哪里出错了。问候,senthil
  • 解决方案有效,但 Tomahawk 下载链接已失效。使用 myfaces.apache.org 主页进行下载。
【解决方案2】:

为了完整起见,我只想提供一个功能齐全的 self contained 示例,说明如何使用 JSF 2.2,以及非 Ajax 和 Ajax 请求来完成此操作。请记住,JSF 2.2 使用不同的命名空间,而您 need to be working with a Servlet 3.0 container(就像 Tomcat 7.0.x、JBoss AS 6.x 和 7.x 以及 GlassFish 3.x 一样)。

fileUpload.xhtml

<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://xmlns.jcp.org/jsf/html"
    xmlns:f="http://xmlns.jcp.org/jsf/core">
<h:head />
<h:body>
    <h:form enctype="multipart/form-data">
        <h:inputFile value="#{uploadBean.file}" />
        <h:commandButton value="Post Upload" action="#{uploadBean.upload}" />
    </h:form>
    <h:form enctype="multipart/form-data">
        <h:inputFile value="#{uploadBean.file}" />
        <h:commandButton value="Ajax Upload">
            <f:ajax listener="#{uploadBean.upload}" execute="@form"
                render="countOutput" />
        </h:commandButton>
    <!-- Counts the uploaded items -->
    <h:outputText id="countOutput"
        value="Files uploaded #{uploadBean.filesUploaded}" />
    </h:form>
</h:body>
</html>

上传Bean.java:

@ManagedBean
@ViewScoped
public class UploadBean {

    private int filesUploaded = 0;

    //javax.servlet.http.Part (Servlet 3.0 API)
    private Part file;
    private String fileContent;

    /**
     * Just prints out file content
     */
    public void upload() {
        try {
            fileContent = new Scanner(file.getInputStream())
                    .useDelimiter("\\A").next();
            System.out.println(fileContent + " uploaded");
            filesUploaded++;
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public int getFilesUploaded() {
        return filesUploaded;
    }

    public Part getFile() {
        return file;
    }

    public void setFile(Part file) {
        this.file = file;
    }
}

另请参阅:

【讨论】:

  • 不要误会我的意思,但我正在为您的示例而苦苦挣扎。它根本不适合我。 file 已经为空...?
  • 我在 tomcat 7 中尝试了一个测试项目,并让它工作了@alexander。您使用的是哪个服务器?您是否配置了一些过滤器?
  • 来自 JBoss 的新版本 - wildfly-8.1.0.Final。是的,&lt;filter&gt; &lt;filter-name&gt;PrimeFaces FileUpload Filter&lt;/filter-name&gt; &lt;filter-class&gt;org.primefaces.webapp.filter.FileUploadFilter&lt;/filter-class&gt; &lt;/filter&gt;
  • 我用谷歌搜索了很多,并没有发现任何关于普通 JSF 中的过滤器的信息。只有战斧和jsf。所以我删除了我的过滤器 - 它根本不起作用。我在这里想念什么?如果我只使用 jsf,是否需要过滤器?甚至您的资源都没有过滤器?
  • @itgirl 我想没有办法做到这一点,它与您的应用程序的视图逻辑完全无关,这是肯定的。我现在可以想到的两种可能性是让客户端分析文件内容或将其发送到某个系统,该系统在您通过电子邮件发送之前在云中为您执行此任务。 stackoverflow.com/questions/4721406/…
【解决方案3】:

我建议使用像 Tomahawk's &lt;t:inputFileUpload&gt;PrimeFaces &lt;p:fileUpload&gt; 这样的组件库。

BalusC 还有一篇关于Uploading files with JSF 2.0 and Servlet 3.0. 的精彩博文

【讨论】:

    【解决方案4】:

    BalusC 的博文:Uploading files with JSF 2.0 and Servlet 3.0 救了我,因为我在使用 Spring WebFlow 运行 RichFaces 4 fileUpload 标签时遇到了问题。

    值得修改 BalusC 的代码以使用 Spring 的 MultipartResolver - 你不需要来自 another blog postMultipartMap

    我通过像这样修改FileRenderer 中的decode 方法来实现它:

        UploadedFile ret = null;
    
        Object req = context.getExternalContext().getRequest();
        if (req instanceof MultipartHttpServletRequest) {
          MultipartFile file = ((MultipartHttpServletRequest)req).getFile(clientId);
    
          File temp = null;
          try {
            temp = File.createTempFile("_UPLOAD_", null);
            file.transferTo(temp);
    
            String name = new File(file.getOriginalFilename()).getName();
            ret = new UploadedFile(temp, name);
    
          } catch (IOException e) {
            throw new RuntimeException("Could not create temp file.", e);
          }
        } else {
          throw new IllegalStateException("Request is not multipart. Use spring's multipart resolver.");
        }
        // If no file is specified, set empty String to trigger validators.
        ((UIInput) component).setSubmittedValue( ret == null ? EMPTY_STRING : ret);
    

    UploadedFile 是一个简单的可序列化 POJO,用于将结果返回到支持 bean。

    【讨论】:

      【解决方案5】:

      在 JSF 2.2 中,您可以使用标签轻松上传文件,而无需使用 commons-io 或过滤器。该标签支持普通和ajax进程。

      正常:

          <h:inputFile id="file"  value="#{fileUploadBean.uploadedFile}"/> 
          <h:commandButton id="button" action="#{fileUploadBean.sumbit()}" value="Upload"/>
      

      阿贾克斯:

          <h:inputFile id="file" value="#{fileUploadBean.uploadedFile}"/> 
          <h:commandButton id="button" value="submit">
            <f:ajax execute="@all" render="@all" onevent="statusUpdate"/>
          </h:commandButton>
      

      按如下方式设计您的托管 bean:

        @Named
        @RequestScoped
        public class FileUploadBean {
      
         private Part uploadedFile;
      
        }
      

      【讨论】:

        【解决方案6】:

        最简单的方法可能是使用 inputFileUpload 标签,你可以 在 MyFaces 中查找:

        http://myfaces.apache.org/

        【讨论】:

          【解决方案7】:

          IceFaces2.0 有一个,http://wiki.icefaces.org/display/ICE/FileEntry 还没有尝试实现它,但是下载有示例应用程序,它可以在 Tomcat 6(servlet 2.5,所以不是 JEE6)下运行

          【讨论】:

            【解决方案8】:

            您必须在我们的项目构建路径中添加commons-fileupload-1.2.1.jar

            1.配置web.xml文件:

            Web.xml
            
                <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>
                <mime-mapping>        
                    <extension>png</extension>
                    <mime-type>image/png</mime-type>
                </mime-mapping>
            

            2。创建 ManagedBean

               @ManagedBean
               @SessionScoped
            public class FileUploadBean implements Serializable{
            public FileUpload (){
            }
              private StreamedContent file;
            public void loadFile(FileUploadEvent event) throws IOException, InterruptedException {
            
                    InputStream input = new ByteArrayInputStream(event.getFile().getContents());
                    file= new DefaultStreamedContent(input, "image/jpg");
                }
            }
            

            3.jsf 文件(xhtml)

               <h:form enctype="multipart/form-data"> 
                     <p:fileUpload fileUploadListener="#{fileUploadBean.file}" sizeLimit="100000" allowTypes="/(\.|\/)(gif|jpe?g|png|bmp)$/"/>
                    </h:form>
            

            【讨论】:

              猜你喜欢
              • 2011-07-22
              • 1970-01-01
              • 2013-12-16
              • 2012-09-23
              • 2023-03-27
              • 1970-01-01
              • 2011-06-09
              • 1970-01-01
              • 2013-09-12
              相关资源
              最近更新 更多