使用Ajax与Servlet 3上传文件时request.getPart()返回NULL求助
看起来你遇到的request.getPart("file")返回null的问题,大概率是前端没有正确把文件数据传递到Servlet,或者Servlet的配置有遗漏。我来帮你一步步排查和解决:
1. 确认前端是否正确获取并传递了文件
你的ajaxUploadFile()函数里用到了fileList,但代码里没看到这个变量的定义和赋值逻辑。如果fileList是空的或者未正确获取文件,那formData.append("file", ...)就不会添加任何文件数据,Servlet自然拿不到对应的Part。
修改JS函数,直接从文件输入框获取文件列表:
function ajaxUploadFile() { var form = document.getElementById('uploadImageForNewCustomerformId'); if (form == null) return; // 直接从fileInput获取文件列表 var fileInput = document.getElementById('fileInput'); var fileList = fileInput.files; // 先检查是否有选中文件 if (fileList.length === 0) { document.getElementById("uploadStatusId").innerHTML = "请先选择要上传的文件"; return; } // 初始化FormData时可以不传form,避免携带JSF自动生成的多余字段(比如viewState) var formData = new FormData(); for (var i = 0; i < fileList.length; i++) { formData.append("file", fileList[i], fileList[i].name); } var uploadStatusOutput = document.getElementById("uploadStatusId"); var request = new XMLHttpRequest(); // 建议用动态上下文路径,避免硬编码 var contextPath = '#{pageContext.request.contextPath}'; request.open("POST", contextPath + "/fileUpload"); request.responseType = 'text'; request.onload = function(oEvent) { if (request.readyState === request.DONE) { if (request.status === 200) { if (request.responseText == "OK") { form.action = contextPath + "/pages/customers.jsf"; form.submit(); return; } } uploadStatusOutput.innerHTML = "Error uploading image"; } }; request.send(formData); };
2. 完善Servlet的@MultipartConfig配置
虽然@MultipartConfig可以无参数使用,但明确配置文件大小限制能避免因默认限制过小导致的上传失败(这也可能导致getPart()返回null):
@WebServlet("/fileUpload") @MultipartConfig( fileSizeThreshold = 1024 * 1024, // 当文件大小超过1MB时,先写入临时文件 maxFileSize = 1024 * 1024 * 5, // 单个文件最大5MB maxRequestSize = 1024 * 1024 * 10 // 整个请求最大10MB ) public class ImageUploadServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { HttpSession session = request.getSession(false); System.out.println(session); Long savedKundeId = (Long) session.getAttribute(NewCustomerBean.SESSION_ATTRIBUTE_CUST_ID); // 先打印所有Part名称,确认是否有"file"这个Part Collection<Part> parts = request.getParts(); for (Part part : parts) { System.out.println("收到的Part名称:" + part.getName()); } Part filePart = request.getPart("file"); if (filePart == null) { System.out.println("未获取到名为'file'的Part"); response.getWriter().write("ERROR"); return; } // 后续处理文件的逻辑... // 记得关闭PrintWriter等资源 response.getWriter().write("OK"); } }
添加打印Part名称的代码,可以帮你确认前端是否真的把文件传递过来了。如果控制台没打印出file,那还是前端的问题,需要再检查JS逻辑。
3. 检查请求路径是否正确
你JS里硬编码了请求路径/javakurs3-biliothek-jsf-mobile/fileUpload,如果应用部署的上下文路径不是这个,请求会找不到Servlet。用#{pageContext.request.contextPath}动态获取上下文路径更可靠,就像上面JS代码里修改的那样。
4. 排除JSF表单的干扰
虽然你给第二个表单设置了enctype="multipart/form-data",但JSF的<h:form>会自动添加一些隐藏字段(比如javax.faces.ViewState)。不过用new FormData()而不是new FormData(form)可以避免携带这些字段,减少不必要的干扰。
按照上面的步骤修改后,应该就能解决request.getPart("file")返回null的问题了。如果还是不行,看看控制台打印的Part名称,再针对性排查。
内容的提问来源于stack exchange,提问作者Alex Mi

