【Java Web】前端利用 form 表单传多项数据,后端 Servlet 取出的各项数据均为空

前端利用 form 表单传多项数据,后端 Servlet 取出的各项数据均为空


文章目录

  • 1.问题引入
  • 2.问题解决


1.问题引入

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

为便于读者理解,我先描述下当前的业务场景:弹窗界面用于提示录入用户信息,含姓名、学位和照片(这些信息将被组织在一个 form 表单中)。在点击 “Add” 后,该 form 表单会提交全部数据至后台,并将这些数据存放至数据库中。

业务场景描述

下面是这部分内容对应的代码(为便于读者快速进入题境,我省略了一些无关的头、尾部代码,并保证这部分代码在该问题中未造成任何影响):

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

<div style="height: 400px; overflow-y: auto; margin-bottom: 60px; padding: 20px"><form name="personForm" class="layui-form layui-form-pane" style="padding: 5px" enctype="multipart/form-data"><div class="layui-form-item"><label class="layui-form-label">Name</label><div class="layui-input-block"><input type="text" id="name" name="name" class="layui-input" /></div></div><div class="layui-form-item"><label class="layui-form-label">Degree</label><div class="layui-input-inline"><select id="degree" name="degree" size="3"><option value="0">B.S.</option><option value="1">M.S.</option><option value="2">Dr.</option></c:if></select></div></div><div class="layui-form-item"><label class="layui-form-label">Photo</label><div class="layui-input-block"><input type="file" name="photo" id="photo"style="position: relative;display: inline-block;background: #21997f;border: 1px solid #0e8050;border-radius: 4px;padding: 5px 12px;overflow: hidden;color: #ffffff;text-decoration: none;text-indent: 0;line-height: 25px;"></div></div><div class="layui-form-item"><button class="layui-btn" style="display:block; margin-left:auto; margin-right:auto; margin-top: 1rem;"lay-submit lay-filter="add" id="addpersopn" onclick="addPerson()">Modify</button></div></form></div>
 <script type="text/javascript">function addPerson() {var name = $("#name").val();var selectElement = document.getElementById("degree");var degree = selectElement.options[selectElement.selectedIndex].value;if (name == "") {alert("Please fill name!")return;} else if (degree == "") {alert("Please select degree!")return;} else {console.log("Get input message:")console.log(name)console.log(degree)personForm.method = "post";personForm.action = "PersonAddServlet";personForm.submit();}}
</script>

后端代码

@WebServlet("/PersonAddServlet")
public class PersonModifyServlet extends HttpServlet {@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println("\n*----------------------------- PersonAddServlet Log ----------------------------*");System.out.println("|                                                                               |");System.out.println("|                            Enter PersonAddServlet                             |");System.out.println("|                                                                               |");System.out.println("|                                                                               |");// 转码resp.setContentType("text/html; charset=UTF-8");// 设置请求编码req.setCharacterEncoding("UTF-8");// 得到输出流PrintWriter out = resp.getWriter();// IDTool 是一个我已实现的静态类, createID 方法能根据系统中已有的用户信息自动创建唯一的 IDString personID =  IDTool.createID(1);// 获取 form 表单的数据// 姓名String name = req.getParameter("name");System.out.println("|                         Get name: " + name);// 学位String degreeIndex = req.getParameter("degree");List<String> Degree = new ArrayList<>();Degree.add("B.S.");Degree.add("M.S.");Degree.add("Dr.");String degree = Degree.get(Integer.parseInt(degreeIndex));System.out.println("|                         Get degree: " + degree);// 照片Part part =  req.getPart("photo");String photo = null;// 获取待上传位置String realPath = req.getServletContext().getRealPath("/" + DirConfig.getFILEHOME() + "/" + DirConfig.getIMAGEDIR() + "/");// 拼接照片文件的上传地址photo = realPath + part .getSubmittedFileName();// 上传照片part.write(photo);// 将用户信息写入数据库(PersonRepository 是我已实现的用于和数据库进行数据交互的类)PersonRepository personRepository = new PersonRepository();if(personRepository.addPerson(personID, name, degree, photo)){out.flush();out.println("<script>");out.println("alert('Successfully updated personal information!');");out.println("top.location.href='manage.jsp';");out.println("</script>");}else{out.flush();out.println("<script>");out.println("alert('Updated personal information failed!');");out.println("top.location.href='manage.jsp';");out.println("</script>");}System.out.println("|                                                                               |");System.out.println("|                                                                               |");System.out.println("*----------------------------- PersonAddServlet END ----------------------------*\n");}
}

以上代码的逻辑很清晰:
1、前端获取输入;
2、后端拿取输入,并完成添加。

但在运行时,后端 Servlet 取出的 name 和 degree 始终为 null:

Servlet 中的输出
注:上面的报错是由于 String degreeIndex = req.getParameter(“degree”); 得到了 null ,因此在后续 Degree.get(Integer.parseInt(degreeIndex)) 时会出现 “对 null 强制转换为 int 型” 的错。

最关键的来了!当我用 F12 在浏览器中查看包的信息时,发现 post 请求中的确含有 name、degree 和 photo 的数据!!!

浏览器开发者选项的取值


于是,头疼开始了!
但是我们可以肯定一件事:form 表单完成了对表内数据的传送,问题在于 Servlet 无法取出!




2.问题解决

这时候通过网上查询,基本可以得到以下排错手段(参考博客:jsp提交form表单到servlet,但取值全为空):

1、form 表单中未写 name 属性;
2、jsp 的提交方式与 servlet 不一致(如:在 jsp 中用的 post ,但是在对应 servlet 中写的是 doGet);
3、form 表单的 enctype 属性与 servlet 不一致;
4、servlet 中的 getParameter() 参数与 form 表单不一致。

但遗憾的是,我都正确配置了这些参数,可取出的就是 null 。

于是,局面开始变得焦灼起来。

直到有一刻,当我在 CSDN 漫步时,无意点开了一个博客:【JAVA】前端multipart/form-data传文件及参数,后端拿值问题。因为当时已经看了很多博文,所以在看这些文章时基本都是走马观花式的,非常快,一扫而过的那种。我记得很清楚,当点开这篇博文的第一刻,我直接一眼扫到一个词汇,并当即顿悟:

在这里插入图片描述


我想,当你看到这张图片时应该和我一样,直接灵光乍现了吧?

在前端用了 multipart/form-data 封装 form 表单数据,后端接受到的数据是一个含文本、二进制数据的复杂数据对象,这时候肯定不能直接通过 getParameter() 获取。因为 getParameter() 方法是不能对这种 “打包数据对象” 进行解析的。这时候最简单的解决办法就是在 servlet 处添加 @MultipartConfig 注解,以告知 servlet,此时接受到的数据是同时含文本、二进制数据的,需要在 getParameter() 前进行适当预处理。这样一来, getParameter() 才能从前端发来的数据对象中正确解析出各项 name 对应的值。

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

@WebServlet("/PersonAddServlet")
@MultipartConfig
public class PersonModifyServlet extends HttpServlet {@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println("\n*----------------------------- PersonAddServlet Log ----------------------------*");System.out.println("|                                                                               |");System.out.println("|                            Enter PersonAddServlet                             |");System.out.println("|                                                                               |");System.out.println("|                                                                               |");// 转码resp.setContentType("text/html; charset=UTF-8");// 设置请求编码req.setCharacterEncoding("UTF-8");// 得到输出流PrintWriter out = resp.getWriter();// IDTool 是一个我已实现的静态类, createID 方法能根据系统中已有的用户信息自动创建唯一的 IDString personID =  IDTool.createID(1);// 获取 form 表单的数据// 姓名String name = req.getParameter("name");System.out.println("|                         Get name: " + name);// 学位String degreeIndex = req.getParameter("degree");List<String> Degree = new ArrayList<>();Degree.add("B.S.");Degree.add("M.S.");Degree.add("Dr.");String degree = Degree.get(Integer.parseInt(degreeIndex));System.out.println("|                         Get degree: " + degree);// 照片Part part =  req.getPart("photo");String photo = null;// 获取待上传位置String realPath = req.getServletContext().getRealPath("/" + DirConfig.getFILEHOME() + "/" + DirConfig.getIMAGEDIR() + "/");// 拼接照片文件的上传地址photo = realPath + part .getSubmittedFileName();// 上传照片part.write(photo);// 将用户信息写入数据库(PersonRepository 是我已实现的用于和数据库进行数据交互的类)PersonRepository personRepository = new PersonRepository();if(personRepository.addPerson(personID, name, degree, photo)){out.flush();out.println("<script>");out.println("alert('Successfully updated personal information!');");out.println("top.location.href='manage.jsp';");out.println("</script>");}else{out.flush();out.println("<script>");out.println("alert('Updated personal information failed!');");out.println("top.location.href='manage.jsp';");out.println("</script>");}System.out.println("|                                                                               |");System.out.println("|                                                                               |");System.out.println("*----------------------------- PersonAddServlet END ----------------------------*\n");}
}

即:添加 @MultipartConfig 注解。


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

说实话这是一个很隐秘的错,踩坑一次,绝不再犯,特此记录~~~



END


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/331653.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Windows远程连接命令?

Windows操作系统提供了多种远程连接命令&#xff0c;使用户可以通过网络连接到远程计算机&#xff0c;并在远程操作系统上执行操作。远程连接命令可方便实现远程工作、故障排查和系统维护等任务。本文将介绍几种常见的Windows远程连接命令及其基本使用方法。 远程连接命令 Win…

心链2---前端开发(整合路由,搜索页面,用户信息页开发)

心链——伙伴匹配系统 接口调试 说书人&#x1f4d6;&#xff1a;上回书说到用了两种方法查询标签1.SQL查询&#xff0c;2.内存查询&#xff1b;两种查询效率是部分上下&#xff0c;打的是难解难分&#xff0c;是时大地皴裂&#xff0c;天色聚变&#xff0c;老祖斟酌再三最后决…

仪器校准中移液器的使用规范,应当注意哪些细节?

校准行业中&#xff0c;移液器的使用是非常多的&#xff0c;尤其是理化室&#xff0c;经常需要借助到移液器来校准。作为常规的溶液定量转移器具&#xff0c;其在校准过程中的使用也需要遵守规范&#xff0c;既是保证校准结果准确低误差&#xff0c;也是为了规范实验室校准人员…

2024.5.25晚训题解

这套题挺简单的。。。 A题 AC率差不多100% B题 AC率差不多75% C题 AC率也差不多75% D题 AC率 50% E题 AC率 25% 向着top 1%出发 A题题解 Stair, Peak, or Neither? 简单判断题&#xff0c;自己写 #include<bits/stdc.h> using namespace std; int A[5]; int main() {…

llama-factory学习个人记录

框架、模型、数据集准备 1.llama-factory部署 # 克隆仓库 git clone https://github.com/hiyouga/LLaMA-Factory.git # 创建虚拟环境 conda create --name llama_factory python3.10 # 激活虚拟环境 conda activate llama_factory # 安装依赖 cd LLaMA-Factory pip install -…

线性回归模型

目录 1.概述 2.线性回归模型的定义 3.线性回归模型的优缺点 4.线性回归模型的应用场景 5.线性回归模型的未来展望 6.小结 1.概述 线性回归是一种广泛应用于统计学和机器学习的技术&#xff0c;用于研究两个或多个变量之间的线性关系。在本文中&#xff0c;我们将深入探讨…

会声会影调速怎么用 会声会影如何调整音频速度

会声会影是一款功能强大的视频编辑软件&#xff0c;可以帮助我们轻松的实现剪辑。 会声会影的操作简单易懂&#xff0c;界面简洁明快。适合家庭使用&#xff0c; 我们使用会声会影可以在家就能将视频剪辑成好莱坞大片。但是在使用的过程中&#xff0c;仍然会遇到一些操作上的问…

微信小程序预览图片和H5使用canvas实现图片+蒙层+文字

1、效果 2.H5实现 <!--* Author: limingfang* Date: 2024-05-20 10:26:51* LastEditors: limingfang* LastEditTime: 2024-05-21 16:31:11* Description: --> <!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8&q…

【小程序 按钮 表单 】

按钮 代码演示 xxx.wxml <view class"boss" hover-class"box"hover-start-time"2000"hover-stay-time"5000">测试文本<view hover-stop-propagation"true">子集</view><view>子集2</view>…

Capture One Studio for Mac:打造完美影像的利器

对于摄影师而言&#xff0c;每一次按下快门都是一次对完美影像的追求。而Capture One Studio for Mac正是这样一款能够帮助你实现这一追求的利器。 Capture One Studio for Mac v16.4.2.1中文直装版下载 首先&#xff0c;Capture One Studio for Mac拥有出色的图像处理能力。它…

Java—二分查找

介绍 二分查找&#xff08;Binary Search&#xff09;是一种在有序数组中查找特定元素的搜索算法。其基本思想是将目标值与数组中间的元素进行比较&#xff1a; 如果目标值等于中间元素&#xff0c;则查找成功。如果目标值小于中间元素&#xff0c;则在数组左半部分继续进行二…

2024年汉字小达人活动4个多月开赛:18道历年选择题和答案、解析

根据近年的安排&#xff0c;2024年第11届汉字小达人比赛还有4个多月就启动&#xff0c;那么孩子们如何利用这段时间有条不紊地备考呢&#xff1f;我的建议是两手准备&#xff1a;①把小学1-5年级的语文课本上的知识点熟悉&#xff0c;重点是字、词、成语、古诗。②把历年真题刷…

VTK 数据处理:特征边提取

VTK 数据处理&#xff1a;特征边提取 VTK 数据处理&#xff1a;特征边提取原理实例 1&#xff1a;边界边提取实例 2&#xff1a;模型特征边提取实例 3&#xff1a;利用 vtkFeatureEdges 提取的边界补洞实例 4&#xff1a;利用 vtkFillHolesFilter 补洞 VTK 数据处理&#xff1a…

全局平均池化笔记

全局平均池化&#xff08;Global Average Pooling, GAP&#xff09;是一种用于卷积神经网络&#xff08;CNN&#xff09;中的池化操作&#xff0c;其主要作用和优点包括&#xff1a; 减少参数数量&#xff1a;全局平均池化层将每个特征图通过取其所有元素的平均值&#xff0c;压…

初识Spring Boot

初识Spring Boot SpringBoot是建立在Spring框架之上的一个项目,它的目标是简化Spring应用程序的初始搭建以及开发过程。 对比Spring Spring Boot作为Spring框架的一个模块&#xff0c;旨在简化Spring应用程序的初始搭建和开发过程&#xff0c;以下是Spring Boot相对于传统Spri…

[datawhale202405]从零手搓大模型实战:TinyAgent

结论速递 TinyAgent项目实现了一个简单的Agent智能体&#xff0c;主要是实现了ReAct策略&#xff08;推理调用工具的能力&#xff09;&#xff0c;及封装了一个Tool。 项目实现有一定的疏漏。为了正确运行代码&#xff0c;本次对代码Agent部分进行了简单修改&#xff08;完善…

【Linux】Linux的安装

文章目录 一、Linux环境的安装虚拟机 镜像文件云服务器&#xff08;可能需要花钱&#xff09; 未完待续 一、Linux环境的安装 我们往后的学习用的Linux版本为——CentOs 7 &#xff0c;使用 Ubuntu 也可以 。这里提供几个安装方法&#xff1a; 电脑安装双系统&#xff08;不…

关于burp的intruder返回包空白问题

记录一下被自己蠢笑的问题 burp返回包为空怎么办&#xff0c;在查询无果后经过多次试验&#xff0c;确实没有效果 看那三个点还以为加载呢&#xff0c;攻击完了怎么一个显示没有 于是…… 鼠标到三个点&#xff0c;往下一拉 哈哈哈哈哈哈哈&#xff0c;真是被自己给蠢到了

基于地理坐标的高阶几何编辑工具算法(2)——相交面裁剪

文章目录 工具步骤应用场景算法输入算法输出算法示意图算法原理后处理 工具步骤 选中一个需要裁剪的面&#xff0c;点击“相交面裁剪”工具&#xff0c;多选裁剪模板面&#xff0c;空格执行。 应用场景 常用于基于遥感影像的建筑物几何面编辑。 算法输入 一个待裁剪的面&a…

Mysql 备份恢复 mysqldump与xtrabackup备份

1.1 备份的原因 备份是数据安全的最后一道防线&#xff0c;对于任何数据丢失的场景&#xff0c;备份虽然不一定能恢复百分之百的数据 (取决于备份周期)&#xff0c;但至少能将损失降到最低。衡量备份恢复有两个重要的指标&#xff1a;恢复点目标(RPO) 和恢复时间目标(RTO)&…