最近写javaweb出现的一个小bug---前端利用 form 表单传多项数据,后端 Servlet 取出的各项数据均为空

目录:

  • [一. 问题引入](#一. 问题引入)
  • [二 解决问题](#二 解决问题)

一. 问题引入

近在写一个 java web 项目时,遇到一个让我头疼了晚上的问题:前端通过 post 提交的 form 表单数据可以传到后端,但当我从 Servlet 中通过 request.getParameter("name") 拿取各项数据时,得到的内容均为 Null !

为便于读者理解,我先描述下当前的业务场景:弹窗界面用于提示录入合同名称,合同类型和合同文件(这些信息将被组织在一个 form 表单中)。在点击 "归档合同" 后,该 form 表单会提交全部数据至后台,并将这些数据存放至数据库中。

下面是这部分内容对应的代码

前端代码(仅展示 form 表单和对应的 JS 代码):

html 复制代码
                        <!-- 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>

后端代码

java 复制代码
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 {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
    }

    @Override
    protected 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转换为String
        String 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 对应的值。

所以,正确的后端代码应改为:

java 复制代码
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 {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
    }

    @Override
    protected 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转换为String
        String formattedDateTime = currentDateTime.format(formatter);
        fileInfo.setFiletime(formattedDateTime);
        System.out.println(fileInfo);
        // 处理完毕后重定向或者显示成功消息
        response.sendRedirect("guidang.html");

    }
}

即:添加 @MultipartConfig 注解。

这时,所有的数据均能正确地取出!

如果我的内容对你有帮助,请点赞,评论,收藏。创作不易,大家的支持就是我坚持下去的动力

相关推荐
MartinYeung521 分钟前
npm爆发大规模供应链攻击 蠕虫污染 2000+ 个包版本: 深度技术剖析
前端·npm·node.js
huabuyu22 分钟前
治好 AI 长回答的卡、闪、膨胀:渲染开销从 50 万次砍到 1000
前端·javascript
嘟嘟071726 分钟前
学了 useContext 还是不理解?从 prop drilling 到 useMouse 的一次完整复盘
前端·javascript·react.js
玉宇夕落26 分钟前
React useContext 与自定义 Hook —— 从零到一理解跨组件通信与状态共享
前端
涛涛ing27 分钟前
一行命令让AI帮你修性能问题:perfpatch正在改变前端优化的游戏规则
前端
huabuyu29 分钟前
模型吐到一半的 JSON 为什么不崩、不卡、不抖?流式 Function Call 的三层修复
前端·javascript
触底反弹32 分钟前
JS 运行原理与 Event Loop:从 Web Worker 实战说起
前端·javascript·react.js
无糖可可果34 分钟前
React Context 与自定义 Hooks 学习分享
前端
胡萝卜术36 分钟前
声明式与命令式的边界:从鉴权路由守卫到 useRef 的引用哲学
前端·javascript·面试
Python私教39 分钟前
如意 Django CRM 容器化实战:后端、前端、数据库、Redis 的协同启动逻辑
前端·数据库·django