最近写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 注解。

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

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

相关推荐
乌兰麦朵10 分钟前
Vue吹的颅内高潮,全靠选择性失明和 .value 的PUA!
前端·vue.js
Code季风11 分钟前
Gin Web 层集成 Viper 配置文件和 Zap 日志文件指南(下)
前端·微服务·架构·go·gin
蓝倾11 分钟前
如何使用API接口实现淘宝商品上下架监控?
前端·后端·api
舂春儿13 分钟前
如何快速统计项目代码行数
前端·后端
毛茸茸13 分钟前
⚡ 从浏览器到编辑器只需1秒,这个React定位工具改变了我的开发方式
前端
Pedantic13 分钟前
我们什么时候应该使用协议继承?——Swift 协议继承的应用与思
前端·后端
Software攻城狮14 分钟前
vite打包的简单配置
前端
Codebee14 分钟前
如何利用OneCode注解驱动,快速训练一个私有的AI代码助手
前端·后端·面试
流星稍逝15 分钟前
用vue3的写法结合uniapp在微信小程序中实现图片压缩、调整分辨率、做缩略图功能
前端·vue.js
知了一笑18 分钟前
独立开发问题记录-margin塌陷
前端