Заполнение каскадных выпадающих списков в JSP/Servlet

Предположим, у меня есть три элемента управления выпадающего списка с именем dd1, dd2 а также dd3, Значение каждого выпадающего списка происходит из базы данных. dd3значение зависит от стоимости dd2 а также dd2Значение зависит от стоимости dd1, Может кто-нибудь сказать мне, как я могу вызвать сервлет для этой проблемы?

4 ответа

Решение

Есть три основных способа добиться этого:

  1. Отправьте форму сервлету во время события onchange 1-го выпадающего меню (для этого вы можете использовать Javascript), пусть сервлет получит выбранный элемент 1-го выпадающего списка в качестве параметра запроса, позволит ему получить связанные значения 2-го выпадающего списка из базы данных как Map<String, String>, пусть хранит их в объеме запроса. Наконец, позвольте JSP/JSTL отобразить значения во втором раскрывающемся списке. Вы можете использовать JSTL (просто бросьте jstl-1.2.jar в /WEB-INF/lib) c:forEach тег для этого. Вы можете предварительно заполнить 1-й список в doGet() метод Servlet связанный со страницей JSP.

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

    Однако, если вы настаиваете на том, что это отправит всю форму и вызовет "вспышку контента", которая может быть плохой для пользовательского опыта. Вам также необходимо сохранить другие поля в той же форме на основе параметров запроса. Вам также необходимо определить в сервлете, должен ли запрос обновить раскрывающийся список (значение дочернего раскрывающегося списка равно нулю) или отправить фактическую форму.

  2. Выведите все возможные значения 2-го и 3-го выпадающего списка в виде объекта Javascript и используйте функцию Javascript для заполнения 2-го раскрывающегося списка на основе выбранного элемента 1-го раскрывающегося списка во время события onchange 1-го раскрывающегося списка. Здесь не нужно отправлять форму и серверный цикл.

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

    Однако одно предостережение заключается в том, что это может стать излишне длительным и дорогим, когда у вас много предметов. Представьте, что у вас есть 3 шага на каждые 100 возможных элементов, что будет означать 100 * 100 * 100 = 1 000 000 элементов в объектах JS. HTML-страница будет расти более 1 МБ в длину.

  3. Используйте XMLHttpRequest в Javascript для запуска асинхронного запроса к сервлету во время события onchange 1-го раскрывающегося списка, позвольте сервлету получить выбранный элемент 1-го раскрывающегося списка в качестве параметра запроса, позвольте ему получить связанные значения 2-го раскрывающегося списка из базы данных, вернуть его обратно в виде строки 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);
    }
    

    Вот, Gson Google Gson, который упрощает преобразование полноценных объектов Java в JSON и наоборот. Смотрите также Как использовать сервлеты и Ajax?

Судя по вашему вопросу, вы действительно не используете веб-фреймворк, а используете сервлеты для рендеринга html.

Я буду мил и скажу, что вы на десять лет отстали от времени:), люди используют JSP (и веб-фреймворк наподобие Struts) для такого рода вещей. Однако, сказав это, здесь идет:

  1. Создайте скрытое поле в вашей форме и установите значение "1", "2" или "3" в зависимости от того, какой выпадающий список должен быть заполнен;
  2. В вашем сервлете запишите это значение (request.getParamter()) и используйте его в качестве оператора case /if/else для возврата соответствующих выпадающих значений.

Я скажу это снова, просто используйте веб-фреймворк или, по крайней мере, обычный старый jsp для этого.

Вам может понадобиться несколько сервлетов для этого.

Сервлет 1. Загрузите значения для первого выпадающего списка из базы данных. На странице JSP постройте выпадающий список. При выборе пользователем значения отправьте сервлету два.

Сервлет 2: получить значение из первого списка и выполнить поиск в базе данных по значениям второго списка. Построить второй список. Когда пользователь выбирает второе значение, отправьте его сервлету 3.

Сервлет 3: получить значение, выбранное во втором раскрывающемся списке, и выполнить поиск в базе данных, чтобы получить значения для последнего раскрывающегося списка.

Возможно, вы захотите использовать AJAX, чтобы заполнение списков казалось пользователям незаметным. У jQuery есть несколько очень хороших плагинов, которые делают это довольно легко, если вы готовы сделать это.


     <form action="servlet2.do">
          <select name="dd1" onchange="Your JavaScript Here">
               <option>....
          </select>
     </form>

Вы можете написать JavaScript, который отправит форму в событие onchange. Опять же, если вы используете существующую библиотеку, такую ​​как jQuery, это будет в 10 раз проще.

Это было потрясающее простое решение. Мне нравится, насколько мал код JQuery, и я очень ценю ссылку на GSON API. Все примеры сделали это легкой реализацией.

Была одна проблема при создании URL-адреса JSON-сервера со ссылкой на родительский 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>
Другие вопросы по тегам