dd1
、dd2
和dd3
。每个下拉列表的值都来自数据库。dd3
的值取决于dd2
的值,而dd2
的值取决于dd1
的值。请问我该如何调用servlet来解决这个问题?dd1
、dd2
和dd3
。每个下拉列表的值都来自数据库。dd3
的值取决于dd2
的值,而dd2
的值取决于dd1
的值。请问我该如何调用servlet来解决这个问题?基本上有三种方法可以实现这一点:
在第一个下拉菜单的onchange事件期间将表单提交给servlet(您可以使用JavaScript完成此操作),让servlet将第一个下拉菜单中选择的项目作为请求参数获取,让它从数据库中获取第二个下拉菜单的关联值作为Map<String, String>
,并将它们存储在请求作用域中。最后让JSP/JSTL显示第二个下拉列表中的值。您可以使用JSTL(只需在/WEB-INF/lib
中放置jstl-1.2.jar)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中确定请求是更新下拉菜单(子下拉菜单值为null)还是提交实际表单。
以Javascript对象的形式打印出第二个和第三个下拉列表的所有可能值,并在第一个下拉列表的onchange事件期间使用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格式,反之亦然。另请参阅如何使用Servlet和Ajax?
<form action="servlet2.do">
<select name="dd1" onchange="Your JavaScript Here">
<option>....
</select>
</form>
您可以编写JavaScript代码,在onchange事件中提交表单。如果使用现有的库,如jQuery,则会简单10倍。
这是一个非常棒的简单解决方案。我喜欢JQuery代码非常小,也很感谢提供GSON API的链接。所有的例子都使得实现变得非常容易。
在构建JSON服务器URL时遇到了一个问题,需要引用父级SELECT(例如$(this).val()
),需要指定: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>
$.getJSON
的文档在这里:http://api.jquery.com/jQuery.getJSON/ URL只是/json/options
。同时请查看文本(不仅仅是代码)。您可以选择任何URL。opts
确实是由servlet返回的JSON字符串。另请参阅JSON链接以了解更多信息。如果您熟悉Javabeans,那么JSON应该足够熟悉。$('>option', dd).remove()
从下拉列表中删除所有先前的选项,否则它将只被追加,追加等等。顺便说一句,如果您喜欢答案,请点赞。我发现您几乎从未投过票。 - BalusC