在JSP / Servlet中填充级联下拉列表
假设我有三个名为dd1
, dd2
和dd3
下拉列表控件。 每个dropdownlist的值都来自数据库。 dd3
的值取决于dd3
的值,而dd2
的值取决于dd2
的值。 任何人都可以告诉我如何调用这个问题的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中确定请求是否要更新下拉列表(子级下拉列表值为空)或提交实际表单。
-
将第二个和第三个下拉列表的所有可能值作为Javascript对象打印出来,并使用Javascript函数在第一个下拉列表的onchange事件期间根据第一个下拉列表中的所选项填充第二个下拉列表。 这里不需要表单提交和服务器周期。
<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个可能的项目有三个步骤,这意味着在JS对象中有100 * 100 * 100 = 1,000,000个项目。 HTML页面将会增长超过1MB。
-
使用Javascript中的XMLHttpRequest在第一个下拉列表的onchange事件中向servlet发出一个asynchronous请求,让servlet获取第一个下拉列表中选中的项作为请求参数,让它从第二个下拉列表中获取关联的值数据库,将其作为XML或JSONstring返回。 最后,让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>
..其中的
Servlet
后面/json/options
可以看起来像这样: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
是谷歌的Gson ,它可以轻松地将完整的Java对象转换为JSON,反之亦然。 另请参见如何使用Servlet和Ajax?
从你的问题来看,你真的没有使用web框架,而是使用servlet来呈现html。
我会很高兴的说,你已经差不多十年了:),人们使用JSP(以及像struts这样的web框架)来处理这种事情。 不过,话虽如此,
- 在表单中创build一个隐藏字段,并根据要填充的下拉列表将值设置为“1”,“2”或“3”;
- 在你的servlet中,捕获这个值(request.getParamter()),并用它'case'/ if / else语句返回合适的下拉值。
我会再说一遍,只是使用一个web框架,或者至less用普通的旧jsp来做到这一点。
你可能需要多个servlet。
servlets程序1:从数据库加载第一个下拉列表的值。 在JSP页面上构build下拉列表。 在用户select一个值提交给servlet二。
Servlet 2:从第一个列表中检索值,并执行数据库search第二个列表的值。 构build第二个列表。 当用户select第二个值时,将其提交给servlet 3。
Servlet 3:检索在第二个下拉列表中select的值,并执行数据库search以获取最后一个下拉列表的值。
您可能要考虑AJAX使用户对列表的填充显示无缝。 如果你愿意这样做,jQuery有一些非常好的插件可以使它变得非常简单。
<form action="servlet2.do"> <select name="dd1" onchange="Your JavaScript Here"> <option>.... </select> </form>
您可以编写提交onchange事件中的表单的JavaScript。 再一次,如果你使用像jQuery这样的现有库,它将会简单10倍。
这是一个非常简单的解决scheme。 我喜欢JQuery代码有多小,真正感谢GSON API的链接。 所有的例子都很容易实现。
有一个关于构buildJSON服务器URL的问题,引用了父SELECT(例如$(this).val()
)[需要指定:selected
属性]。 我已经修改了一些脚本以包含build议的更新。 感谢您的初始代码。
<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>