目录:
- 一. 问题引入
- 二 解决问题
一. 问题引入
近在写一个 java web 项目时,遇到一个让我头疼了晚上的问题:前端通过 post 提交的 form 表单数据可以传到后端,但当我从 Servlet 中通过 request.getParameter(“name”) 拿取各项数据时,得到的内容均为 Null !
为便于读者理解,我先描述下当前的业务场景:弹窗界面用于提示录入合同名称,合同类型和合同文件(这些信息将被组织在一个 form 表单中)。在点击 “归档合同” 后,该 form 表单会提交全部数据至后台,并将这些数据存放至数据库中。
下面是这部分内容对应的代码
前端代码(仅展示 form 表单和对应的 JS 代码):
<!-- Contract archiving form --><form id="contractArchivingForm" class="bg-light p-3" action="file.do" method="post" enctype="multipart/form-data" ><input type="hidden" name="flag" value="insert"/><div class="form-group"><label for="contractName">合同名称</label><input type="text" class="form-control" id="contractName" name="contractName" placeholder="输入合同名称" required></div><div class="form-group"><label for="contractCategory">合同类别</label><select class="form-control" id="contractCategory" name="contractCategory"><option>租赁协议</option><option>销售合同</option><option>服务协议</option><!-- More contract categories can be added as needed --></select></div><div class="form-group"><label for="contractFileUpload">上传合同文件</label><input type="file" class="form-control-file" id="contractFileUpload" name="contractFileUpload" required><small class="form-text text-muted">请上传PDF格式的文件,大小不超过10MB。</small></div><div class="form-group form-check"><input type="checkbox" class="form-check-input" id="agreement"><label class="form-check-label" for="agreement">我确认合同信息准确无误,并同意归档。</label></div><input type="submit" class="btn btn-primary" value="归档合同" ></form>
后端代码
package com.jjy.web.servlet;import com.jjy.pojo.FileInfo;import javax.servlet.ServletContext;
import javax.servlet.ServletException;
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 java.io.IOException;
import java.io.InputStream;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
@WebServlet("/file.do")
public class FileInfoServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {super.doPost(req, resp);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String flag = req.getParameter("flag");System.out.println("未进入"+flag);if ("insert".equals(flag)) {System.out.println(flag);insertFileinfo(req, resp);}}private void insertFileinfo(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {String contractName = request.getParameter("contractName");String contractCategory = request.getParameter("contractCategory");FileInfo fileInfo = new FileInfo();Part part = request.getPart("contractFileUpload");//通过Part对象得到上传的文件名String fileName = part.getSubmittedFileName();System.out.println("上传文件名:" + fileName);//得到文件存放的路径String filePath = request.getServletContext().getRealPath("/");System.out.println("文件存放路径:" + filePath);part.write(filePath + "/" + fileName);fileInfo.setFilename(contractName);fileInfo.setFiletype(contractCategory);LocalDateTime currentDateTime = LocalDateTime.now();// 定义日期时间格式DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");// 将LocalDateTime转换为StringString formattedDateTime = currentDateTime.format(formatter);fileInfo.setFiletime(formattedDateTime);System.out.println(fileInfo);// 处理完毕后重定向或者显示成功消息response.sendRedirect("guidang.html");}
}
以上代码的逻辑很清晰:
1、前端获取输入;
2、后端拿取输入,并完成添加。
但在运行时,后端 Servlet 取出的值始终为 null:
当我用 F12 在浏览器中查看包的信息时,发现 post 请求中的确含数据!!!
二 解决问题
这时候通过网上查询,基本可以得到以下排错手段
1、form 表单中未写 name 属性;
2、jsp 的提交方式与 servlet 不一致(如:在 jsp 中用的 post ,但是在对应 servlet 中写的是 doGet);
3、form 表单的 enctype 属性与 servlet 不一致;
4、servlet 中的 getParameter() 参数与 form 表单不一致。
但遗憾的是,我都正确配置了这些参数,可取出的就是 null 。
最后发现
在前端用了 multipart/form-data 封装 form 表单数据,后端接受到的数据是一个含文本、二进制数据的复杂数据对象,这时候肯定不能直接通过 getParameter() 获取。因为 getParameter() 方法是不能对这种 “打包数据对象” 进行解析的。这时候最简单的解决办法就是在 servlet 处添加 @MultipartConfig 注解,以告知 servlet,此时接受到的数据是同时含文本、二进制数据的,需要在 getParameter() 前进行适当预处理。这样一来, getParameter() 才能从前端发来的数据对象中正确解析出各项 name 对应的值。
所以,正确的后端代码应改为:
package com.jjy.web.servlet;import com.jjy.pojo.FileInfo;import javax.servlet.ServletContext;
import javax.servlet.ServletException;
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 java.io.IOException;
import java.io.InputStream;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
@MultipartConfig
@WebServlet("/file.do")
public class FileInfoServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {super.doPost(req, resp);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String flag = req.getParameter("flag");System.out.println("未进入"+flag);if ("insert".equals(flag)) {System.out.println(flag);insertFileinfo(req, resp);}}private void insertFileinfo(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {String contractName = request.getParameter("contractName");String contractCategory = request.getParameter("contractCategory");FileInfo fileInfo = new FileInfo();Part part = request.getPart("contractFileUpload");//通过Part对象得到上传的文件名String fileName = part.getSubmittedFileName();System.out.println("上传文件名:" + fileName);//得到文件存放的路径String filePath = request.getServletContext().getRealPath("/");System.out.println("文件存放路径:" + filePath);part.write(filePath + "/" + fileName);fileInfo.setFilename(contractName);fileInfo.setFiletype(contractCategory);LocalDateTime currentDateTime = LocalDateTime.now();// 定义日期时间格式DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");// 将LocalDateTime转换为StringString formattedDateTime = currentDateTime.format(formatter);fileInfo.setFiletime(formattedDateTime);System.out.println(fileInfo);// 处理完毕后重定向或者显示成功消息response.sendRedirect("guidang.html");}
}
即:添加 @MultipartConfig 注解。
这时,所有的数据均能正确地取出!
如果我的内容对你有帮助,请点赞,评论,收藏。创作不易,大家的支持就是我坚持下去的动力