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

dev*_*ven 40 jsp servlets cascading drop-down-menu

假设我有三个名为的下拉列表控件dd1,dd2dd3.每个下拉列表的值来自数据库.dd3价值取决于价值dd2dd2价值取决于价值dd1.任何人都可以告诉我如何调用servlet来解决这个问题?

Bal*_*usC 49

基本上有三种方法可以达到这个目的:

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

    <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>
    
    Run Code Online (Sandbox Code Playgroud)

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

  2. 将第二个和第三个下拉列表的所有可能值作为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>
    
    Run Code Online (Sandbox Code Playgroud)

    但有一点需要注意的是,当你有很多物品时,这可能会变得不必要地冗长和昂贵.想象一下,每100个可能的项目中有3个步骤,这意味着JS对象中有100*100*100 = 1,000,000个项目.HTML页面的长度将超过1MB.

  3. 在第一个下拉列表的onchange事件期间,使用Javascript中的XMLHttpRequest向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>
    
    Run Code Online (Sandbox Code Playgroud)

    .. 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);
    }
    
    Run Code Online (Sandbox Code Playgroud)

    这里,Gson谷歌GSON从而简化了转换fullworthy Java对象到JSON,反之亦然.另请参见如何使用Servlet和Ajax?

  • @BalusC:你的JQuery示例不起作用,因为fillOptions函数中的"this"将指向Window对象."this"将仅指向传递给.change函数的函数内的HTMLSelectElement.我必须将"this"传递给fillOptions("fillOptions('dd2',this)"),以便在另一端检索值("function fillOptions(ddId,callingElement)",然后是"$(callingElement)". VAL()"). (2认同)