简单 Jetty/JSF 文件上传不会提交
Simple Jetty/JSF file upload won't submit
I've already looked at this one 和相关的门票无济于事。
我有最简单的例子
<h:form enctype="multipart/form-data" prependId="false">
<h:outputText value="File: "></h:outputText>
<h:inputFile value="#{configUploadController.uploadedFile}" />
<h:commandButton value="Save" type="submit" action="#{configUploadController.uploadFile}" style="color: red;"></h:commandButton>
</h:form>
我在我的 uploadFile
方法中放置了一个断点,但它从未命中。当我从表单中删除 enctype
时,它确实尝试提交,但随后出现明显的错误...
javax.servlet.ServletException: Content-Type != multipart/form-data
为了完整起见,我删除了 <h:inputFile>
和 enctype
并且可以看到我的断点被命中。当我将 enctype
设置为 text/plain
时,它 DOESNT 命中断点。但是,当我将 enctype
设置为乱码时 DOES 命中断点:(
我是不是在某处缺少依赖项或配置?
万一重要,我的 web.xml...
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<!-- File(s) appended to a request for a URL that is not mapped to a web
component -->
<welcome-file-list>
<welcome-file>status.xhtml</welcome-file>
</welcome-file-list>
<context-param>
<param-name>com.sun.faces.expressionFactory</param-name>
<param-value>com.sun.el.ExpressionFactoryImpl</param-value>
</context-param>
<listener>
<description>Initializes Oracle JSF</description>
<listener-class>com.sun.faces.config.ConfigureListener</listener-class>
</listener>
<!-- Define the JSF servlet (manages the request processing life cycle for
JavaServer Faces) -->
<servlet>
<servlet-name>faces-servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>0</load-on-startup>
</servlet>
<!-- Map following files to the JSF servlet -->
<servlet-mapping>
<servlet-name>faces-servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
</web-app>
- jsf-api-2.2.15
- jsf-impl-2.2.15
- el-api-2.2
- el-impl-2.2
- 码头 9.4.18
- javax.servlet-api-3.1.0
因此,我没有花时间去查明原因,但 jetty 似乎不喜欢多部分表单。我通过使用 servlet 解决了这个问题。解决方案如下所示...
我使用了 ajax 方法和 HTML 表单,因此我可以指定我的操作,匹配 servlet 模式...
<form action="upload/config" enctype="multipart/form-data" method="post">
<h:inputFile id="file" />
<br />
<h:commandButton type="submit" value="Upload">
<f:ajax execute="file" render="@all"/>
</h:commandButton>
</form>
还有 servlet...
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import javax.servlet.MultipartConfigElement;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
import org.eclipse.jetty.server.Request;
@WebServlet("upload")
@MultipartConfig
public class UploadServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse resp) {
try {
// This needed to get access to the parts
MultipartConfigElement multipartConfigElement = new MultipartConfigElement((String)null);
request.setAttribute(Request.__MULTIPART_CONFIG_ELEMENT, multipartConfigElement);
Part filePart = request.getPart("file");
try ( InputStream inputStream = filePart.getInputStream(); ) {
// Do what you want with your part
} catch (Exception e) {
resp.setStatus(500);
}
} catch (Exception e) {
resp.setStatus(500);
}
}
}
实际问题是 Jetty 需要为每个多部分请求设置多部分配置,而不是使用 servlet(根据其他答案)。
执行此操作的简单方法是添加一个过滤器,根据需要添加它,例如。
public class LoginFilter implements Filter {
private static final String MULTIPART_FORM_DATA = "multipart/form-data";
private static final MultipartConfigElement MULTI_PART_CONFIG =
new MultipartConfigElement(System.getProperty("java.io.tmpdir"));
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
String contentType = request.getContentType();
if (contentType != null && contentType.startsWith(MULTIPART_FORM_DATA))
request.setAttribute(Request.__MULTIPART_CONFIG_ELEMENT, MULTI_PART_CONFIG);
filterChain.doFilter(request, response);
}
}
另请参阅:
- How to implement FileUpload in embedded Jetty?
I've already looked at this one 和相关的门票无济于事。
我有最简单的例子
<h:form enctype="multipart/form-data" prependId="false">
<h:outputText value="File: "></h:outputText>
<h:inputFile value="#{configUploadController.uploadedFile}" />
<h:commandButton value="Save" type="submit" action="#{configUploadController.uploadFile}" style="color: red;"></h:commandButton>
</h:form>
我在我的 uploadFile
方法中放置了一个断点,但它从未命中。当我从表单中删除 enctype
时,它确实尝试提交,但随后出现明显的错误...
javax.servlet.ServletException: Content-Type != multipart/form-data
为了完整起见,我删除了 <h:inputFile>
和 enctype
并且可以看到我的断点被命中。当我将 enctype
设置为 text/plain
时,它 DOESNT 命中断点。但是,当我将 enctype
设置为乱码时 DOES 命中断点:(
我是不是在某处缺少依赖项或配置?
万一重要,我的 web.xml...
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<!-- File(s) appended to a request for a URL that is not mapped to a web
component -->
<welcome-file-list>
<welcome-file>status.xhtml</welcome-file>
</welcome-file-list>
<context-param>
<param-name>com.sun.faces.expressionFactory</param-name>
<param-value>com.sun.el.ExpressionFactoryImpl</param-value>
</context-param>
<listener>
<description>Initializes Oracle JSF</description>
<listener-class>com.sun.faces.config.ConfigureListener</listener-class>
</listener>
<!-- Define the JSF servlet (manages the request processing life cycle for
JavaServer Faces) -->
<servlet>
<servlet-name>faces-servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>0</load-on-startup>
</servlet>
<!-- Map following files to the JSF servlet -->
<servlet-mapping>
<servlet-name>faces-servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
</web-app>
- jsf-api-2.2.15
- jsf-impl-2.2.15
- el-api-2.2
- el-impl-2.2
- 码头 9.4.18
- javax.servlet-api-3.1.0
因此,我没有花时间去查明原因,但 jetty 似乎不喜欢多部分表单。我通过使用 servlet 解决了这个问题。解决方案如下所示...
我使用了 ajax 方法和 HTML 表单,因此我可以指定我的操作,匹配 servlet 模式...
<form action="upload/config" enctype="multipart/form-data" method="post">
<h:inputFile id="file" />
<br />
<h:commandButton type="submit" value="Upload">
<f:ajax execute="file" render="@all"/>
</h:commandButton>
</form>
还有 servlet...
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import javax.servlet.MultipartConfigElement;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
import org.eclipse.jetty.server.Request;
@WebServlet("upload")
@MultipartConfig
public class UploadServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse resp) {
try {
// This needed to get access to the parts
MultipartConfigElement multipartConfigElement = new MultipartConfigElement((String)null);
request.setAttribute(Request.__MULTIPART_CONFIG_ELEMENT, multipartConfigElement);
Part filePart = request.getPart("file");
try ( InputStream inputStream = filePart.getInputStream(); ) {
// Do what you want with your part
} catch (Exception e) {
resp.setStatus(500);
}
} catch (Exception e) {
resp.setStatus(500);
}
}
}
实际问题是 Jetty 需要为每个多部分请求设置多部分配置,而不是使用 servlet(根据其他答案)。
执行此操作的简单方法是添加一个过滤器,根据需要添加它,例如。
public class LoginFilter implements Filter {
private static final String MULTIPART_FORM_DATA = "multipart/form-data";
private static final MultipartConfigElement MULTI_PART_CONFIG =
new MultipartConfigElement(System.getProperty("java.io.tmpdir"));
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
String contentType = request.getContentType();
if (contentType != null && contentType.startsWith(MULTIPART_FORM_DATA))
request.setAttribute(Request.__MULTIPART_CONFIG_ELEMENT, MULTI_PART_CONFIG);
filterChain.doFilter(request, response);
}
}
另请参阅:
- How to implement FileUpload in embedded Jetty?