在JSP / Servlet中填充级联下拉列表

时间:2010-02-15 04:01:13

标签: jsp servlets drop-down-menu cascading

假设我有三个名为dd1dd2dd3的下拉列表控件。每个下拉列表的值来自数据库。 dd3的值取决于dd2的值,而dd2的值取决于dd1的值。谁能告诉我如何为这个问题调用servlet?

4 个答案:

答案 0 :(得分:48)

基本上有三种方法可以实现这一目标:

  1. 在第一个下拉列表的onchange事件期间将表单提交给servlet(您可以使用Javascript),让servlet获取第一个下拉列表的选定项作为请求参数,让它获取相关的值数据库中的第二个下拉列表为Map<String, String>,让它将它们存储在请求范围内。最后让JSP / JSTL在第二个下拉列表中显示值。您可以使用JSTL(只需在/WEB-INF/libjstl-1.2.jar标记中删除c:forEach即可。您可以在与JSP页面关联的doGet()的{​​{1}}方法中预填充第一个列表。

    Servlet

    然而,一旦提出警告,这将提交整个表单并导致“内容闪现”,这可能对用户体验不利。您还需要根据请求参数以相同的形式保留其他字段。您还需要在servlet中确定请求是更新下拉列表(子下拉列表值为空)还是提交实际表单。

  2. 将第二个和第三个下拉列表的所有可能值作为Javascript对象打印出来并使用Javascript函数根据第一个下拉列表的onchange事件中第一个下拉列表的选定项填充第二个下拉列表。没有表单提交,这里不需要服务器周期。

    <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>
    
    然而,有一点需要注意的是,如果您拥有很多项目,这可能会变得不必要地冗长且昂贵。想象一下,每100个可能的项目中有3个步骤,这意味着JS对象中有100 * 100 * 100 = 1,000,000个项目。 HTML页面的长度将超过1MB。

  3. 在第一个下拉列表的onchange事件中,利用Javascript中的XMLHttpRequest向servlet发出异步请求,让servlet获取第一个下拉列表中的选定项作为请求参数,让它获取相关值从数据库中获取第二个下拉列表,将其作为XML或JSON字符串返回。最后让Javascript通过HTML DOM树显示第二个下拉列表中的值(Ajax方式,如前所述)。最好的方法是使用jQuery

    <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>
    

    .. <%@ 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); } Google Gson,它可以轻松地将满足的Java对象转换为JSON,反之亦然。另请参阅How to use Servlets and Ajax?

答案 1 :(得分:4)

您可能需要多个servlet。

Servlet 1:从数据库中加载第一个下拉列表的值。在JSP页面上构建下拉列表。在用户选择提交给servlet二的值时。

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倍。

答案 2 :(得分:4)

根据您的问题判断,您实际上并没有使用Web框架,而是使用servlet来呈现html。

我会很高兴并说你落后了大约十年:),人们使用JSP(以及像struts这样的Web框架)来做这类事情。但是,话说回来:

  1. 在表单中创建一个隐藏字段,并将值设置为“1”,“2”或“3”,具体取决于要填充的下拉列表;
  2. 在您的servlet中,捕获此值(request.getParamter())并使用'case'/ if / else语句返回相应的下拉值。
  3. 我会再说一遍,只需使用一个网络框架,或至少使用普通的旧jsp来做到这一点。

答案 3 :(得分:3)

这是一个很棒的简单解决方案。我喜欢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>