一尘不染

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

jsp

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


阅读 345

收藏
2020-06-08

共1个答案

一尘不染

基本上有三种方法可以实现此目的:

  1. 在第一个下拉菜单的onchange事件期间向servlet提交表单(您可以使用Javascript),让servlet获取第一个下拉列表的选定项作为请求参数,让它从数据库中获取第二个下拉列表的关联值作为Map<String, String>,让其将它们存储在请求范围内。最后,让JSP / JSTL在第二个下拉列表中显示值。您可以为此使用JSTL标签(只需将jstl-1.2.jar放入/WEB-INF/libc: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>

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

  1. 在第一个下拉菜单的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。

  1. 在第一个下拉菜单的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>

.. 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);
    }

这里GsonGoogle Gson,它可以轻松地将有价值的Java对象转换为JSON,反之亦然。另请参见如何使用Servlet和Ajax?

2020-06-08