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

StackOverflow https://stackoverflow.com/questions/2263996

Вопрос

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

Это было полезно?

Решение

В основном есть три способа достичь этого:

  1. Отправьте форму сервлету во время события onchange 1-го выпадающего списка (вы можете использовать Javascript для этого), позвольте сервлету получить выбранный элемент 1-го выпадающего списка в качестве параметра запроса, позвольте ему получить связанные значения 2-го выпадающего списка из базы данных в качестве Map<String, String>, пусть он сохранит их в области запроса.Наконец, позвольте JSP / JSTL отобразить значения во 2-м выпадающем списке.Вы можете использовать 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>
    

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

  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 objects.HTML-страница увеличится более чем на 1 МБ в длину.

  3. Используйте XMLHttpRequest в Javascript для запуска асинхронного запроса к сервлету во время события onchange 1-го выпадающего списка, позвольте сервлету получить выбранный элемент 1-го выпадающего списка в качестве параметра запроса, позвольте ему получить связанные значения 2-го выпадающего списка из базы данных, вернуть его обратно в виде XML или JSON строка.Наконец, позвольте Javascript отображать значения во 2-м выпадающем списке через HTML DOM-дерево (Ajax-способ, как предлагалось ранее).Лучшим способом для этого было бы использование jQuery - 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>
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top