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

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

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

相关推荐
彭世瑜几秒前
ts: TypeScript跳过检查/忽略类型检查
前端·javascript·typescript
FØund4041 分钟前
antd form.setFieldsValue问题总结
前端·react.js·typescript·html
Backstroke fish2 分钟前
Token刷新机制
前端·javascript·vue.js·typescript·vue
小五Five3 分钟前
TypeScript项目中Axios的封装
开发语言·前端·javascript
小曲程序3 分钟前
vue3 封装request请求
java·前端·typescript·vue
临枫5414 分钟前
Nuxt3封装网络请求 useFetch & $fetch
前端·javascript·vue.js·typescript
前端每日三省5 分钟前
面试题-TS(八):什么是装饰器(decorators)?如何在 TypeScript 中使用它们?
开发语言·前端·javascript
小刺猬_9856 分钟前
(超详细)数组方法 ——— splice( )
前端·javascript·typescript
渊兮兮7 分钟前
Vue3 + TypeScript +动画,实现动态登陆页面
前端·javascript·css·typescript·动画
鑫宝Code7 分钟前
【TS】TypeScript中的接口(Interface):对象类型的强大工具
前端·javascript·typescript