【发布时间】:2026-02-18 15:30:01
【问题描述】:
假设我有三个名为dd1、dd2 和dd3 的下拉列表控件。每个下拉列表的值来自数据库。 dd3 的值取决于dd2 的值,dd2 的值取决于dd1 的值。谁能告诉我如何为这个问题调用 servlet?
【问题讨论】:
标签: jsp servlets drop-down-menu cascading
假设我有三个名为dd1、dd2 和dd3 的下拉列表控件。每个下拉列表的值来自数据库。 dd3 的值取决于dd2 的值,dd2 的值取决于dd1 的值。谁能告诉我如何为这个问题调用 servlet?
【问题讨论】:
标签: jsp servlets drop-down-menu cascading
基本上有三种方法可以实现:
在第一个下拉菜单的onchange事件期间提交表单到一个servlet(可以使用Javascript),让servlet获取第一个下拉菜单的选中项作为请求参数,让它获取第二个下拉菜单的关联值从数据库中作为Map<String, String>,让它将它们存储在请求范围内。最后让 JSP/JSTL 显示第二个下拉列表中的值。您可以为此使用JSTL(只需将jstl-1.2.jar 放入/WEB-INF/lib)c:forEach 标记。您可以在与 JSP 页面关联的Servlet 的doGet() 方法中预填充第一个列表。
<select name="dd1" onchange="submit()">
<c:forEach items="${dd1options}" var="option">
<option value="${option.key}" ${param.dd1 == option.key ? 'selected' : ''}>${option.value}</option>
</c:forEach>
</select>
<select name="dd2" onchange="submit()">
<c:if test="${empty dd2options}">
<option>Please select parent</option>
</c:if>
<c:forEach items="${dd2options}" var="option">
<option value="${option.key}" ${param.dd2 == option.key ? 'selected' : ''}>${option.value}</option>
</c:forEach>
</select>
<select name="dd3">
<c:if test="${empty dd3options}">
<option>Please select parent</option>
</c:if>
<c:forEach items="${dd3options}" var="option">
<option value="${option.key}" ${param.dd3 == option.key ? 'selected' : ''}>${option.value}</option>
</c:forEach>
</select>
然而,需要注意的是,这将提交整个表单并导致“内容闪现”,这可能对用户体验不利。您还需要根据请求参数以相同的形式保留其他字段。您还需要在 servlet 中确定请求是更新下拉列表(子下拉列表值为空)还是提交实际表单。
在第一个下拉列表的 onchange 事件期间,将第二个和第三个下拉列表的所有可能值打印为 Javascript 对象,并使用 Javascript 函数根据第一个下拉列表的选定项填充第二个下拉列表。这里不需要提交表单,也不需要服务器周期。
<script>
var dd2options = ${dd2optionsAsJSObject};
var dd3options = ${dd3optionsAsJSObject};
function dd1change(dd1) {
// Fill dd2 options based on selected dd1 value.
var selected = dd1.options[dd1.selectedIndex].value;
...
}
function dd2change(dd2) {
// Fill dd3 options based on selected dd2 value.
var selected = dd2.options[dd2.selectedIndex].value;
...
}
</script>
<select name="dd1" onchange="dd1change(this)">
<c:forEach items="${dd1options}" var="option">
<option value="${option.key}" ${param.dd1 == option.key ? 'selected' : ''}>${option.value}</option>
</c:forEach>
</select>
<select name="dd2" onchange="dd2change(this)">
<option>Please select parent</option>
</select>
<select name="dd3">
<option>Please select parent</option>
</select>
但需要注意的是,当您拥有很多物品时,这可能会变得不必要的冗长和昂贵。想象一下,每 100 个可能的项目有 3 个步骤,这意味着 JS 对象中有 100 * 100 * 100 = 1,000,000 个项目。 HTML 页面的长度将超过 1MB。
利用Javascript中的XMLHttpRequest在第一个下拉菜单的onchange事件期间向servlet发起一个异步请求,让servlet获取第一个下拉菜单的选中项作为请求参数,让它获取第二个下拉菜单的关联值从数据库中下拉,将其作为 XML 或 JSON 字符串返回。最后让 Javascript 通过 HTML DOM 树显示第二个下拉列表中的值(Ajax 方式,如前所述)。最好的方法是使用jQuery。
<%@ page pageEncoding="UTF-8" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html lang="en">
<head>
<title>SO question 2263996</title>
<script src="http://code.jquery.com/jquery-latest.min.js"></script>
<script>
$(document).ready(function() {
$('#dd1').change(function() { fillOptions('dd2', this); });
$('#dd2').change(function() { fillOptions('dd3', this); });
});
function fillOptions(ddId, callingElement) {
var dd = $('#' + ddId);
$.getJSON('json/options?dd=' + ddId + '&val=' + $(callingElement).val(), function(opts) {
$('>option', dd).remove(); // Clean old options first.
if (opts) {
$.each(opts, function(key, value) {
dd.append($('<option/>').val(key).text(value));
});
} else {
dd.append($('<option/>').text("Please select parent"));
}
});
}
</script>
</head>
<body>
<form>
<select id="dd1" name="dd1">
<c:forEach items="${dd1}" var="option">
<option value="${option.key}" ${param.dd1 == option.key ? 'selected' : ''}>${option.value}</option>
</c:forEach>
</select>
<select id="dd2" name="dd2">
<option>Please select parent</option>
</select>
<select id="dd3" name="dd3">
<option>Please select parent</option>
</select>
</form>
</body>
</html>
../json/options 后面的 Servlet 可能如下所示:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String dd = request.getParameter("dd"); // ID of child DD to fill options for.
String val = request.getParameter("val"); // Value of parent DD to find associated child DD options for.
Map<String, String> options = optionDAO.find(dd, val);
String json = new Gson().toJson(options);
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
response.getWriter().write(json);
}
这里,Gson 是 Google Gson,它可以轻松地将完全有价值的 Java 对象转换为 JSON,反之亦然。另见How to use Servlets and Ajax?
【讨论】:
$.getJSON 记录在这里:api.jquery.com/jQuery.getJSON URL 只是/json/options。另请参阅文本(不要只看代码)。您可以选择任何您想要的 URL。 opts 确实是 servlet 返回的 JSON 字符串。另请参阅 JSON 链接以了解更多信息。如果您对 Javabeans 非常了解,那么 JSON 应该看起来已经足够熟悉了。 $('>option', dd).remove() 会从下拉列表中删除所有以前的选项,否则它只会被附加、附加等。顺便说一句,如果您喜欢答案,请点赞。我看到你几乎从未投票过。
从您的问题来看,您实际上并没有使用 Web 框架,而是使用 servlet 来呈现 html。
我会很高兴地说你落后了大约十年 :),人们使用 JSP(和类似 struts 的 Web 框架)来处理这类事情。然而,话虽如此,这里是:
我再说一遍,只需使用网络框架,或者至少是普通的旧 jsp 来做到这一点。
【讨论】:
您可能需要多个 servlet。
Servlet 1:从数据库加载第一个下拉列表的值。在 JSP 页面上构建下拉列表。在用户选择一个值时提交给 servlet 2。
Servlet 2:从第一个列表中检索值并执行数据库搜索以查找第二个列表的值。构造第二个列表。当用户选择第二个值时,将其提交给 servlet 3。
Servlet 3:检索在第二个下拉菜单中选择的值并执行数据库搜索以获取最后一个下拉菜单的值。
您可能需要考虑使用 AJAX 来使列表的填充对用户来说是无缝的。如果你愿意的话,jQuery 有一些非常好的插件可以让这变得非常简单。
<form action="servlet2.do">
<select name="dd1" onchange="Your JavaScript Here">
<option>....
</select>
</form>
您可以编写在 onchange 事件中提交表单的 JavaScript。同样,如果你使用像 jQuery 这样的现有库,它会简单 10 倍。
【讨论】:
这是一个很棒的简单解决方案。我喜欢 JQuery 代码有多小,并且非常感谢 GSON API 的链接。所有的例子都让这个实现变得很容易。
在使用对父 SELECT 的引用(例如 $(this).val() )构建 JSON 服务器 URL 时遇到一个问题 [需要指定 :selected 属性]。我稍微修改了脚本以包含建议的更新。感谢您提供初始代码。
<script>
$(document).ready(function()
{
$('#dd1').change(function() { fillOptions('dd1', 'dd2'); });
$('#dd2').change(function() { fillOptions('dd2', 'dd3'); });
});
function fillOptions(parentId, ddId)
{
var dd = $('#' + ddId);
var jsonURL = 'json/options?dd=' + ddId + '&val=' + $('#' + parentId + ' :selected').val();
$.getJSON(jsonURL, function(opts)
{
$('>option', dd).remove(); // Clean old options first.
if (opts)
{
$.each(opts, function(key, value)
{
dd.append($('<option/>').val(key).text(value));
});
}
else
{
dd.append($('<option/>').text("Please select parent"));
}
});
}
</script>
【讨论】: