Веб-приложения для проектирования шаблонов

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

На самом деле, у меня мало объектов на моей домашней странице и соответствует каждому из них, у нас есть несколько вариантов, таких как добавление, редактирование и удаление. Раньше я использовал один сервлет на такие параметры, как Servlet1 для добавления сущности1, Servlet2 для редактирования entity1 и т.д., И таким образом у нас получилось большое количество сервлетов.

Теперь мы меняем наш дизайн. Мой вопрос заключается в том, как вы точно определяете, как вы выбираете ответственность сервлета. Должен ли мы иметь один сервлет на сущность, который будет обрабатывать все его параметры и перенаправлять запрос на сервисный уровень. Или у нас должен быть один сервлет для всей страницы, который обрабатывает весь запрос страницы, а затем перенаправляет его на соответствующий уровень сервиса? Кроме того, если объект запроса перенаправляется на сервисный уровень или нет.

Ответы

Ответ 1

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


Модель контроллера модели Model

Основным (архитектурным) шаблоном проектирования, который вы хотите использовать, является шаблон Model-View-Controller. Контроллер должен быть представлен сервлетом, который (in) напрямую создает/использует конкретную модель и представление на основе запроса. Модель должна быть представлена ​​джавабскими классами. Это часто можно отделить в бизнес-модели, которая содержит действия (поведение) и модель данных, которая содержит данные (информацию). Вид должен быть представлен JSP файлами, которые имеют прямой доступ к (Data) Model по EL (язык выражений).

Затем существуют варианты, основанные на действиях и событиях. Популярные:

  • Запрос (действие) на основе MVC: это самый простой способ реализации. Модель (бизнес) напрямую работает с объектами HttpServletRequest и HttpServletResponse. Вы должны сами собирать, конвертировать и проверять параметры запроса (в основном). Вид может быть представлен простым ванильным HTML/CSS/JS и не поддерживает состояние по запросам. Вот как среди прочих Spring MVC, Struts и Stripes работает.

  • MVC на основе компонентов: это сложнее реализовать. Но вы получаете более простую модель и вид, в котором весь "сырой" API сервлета полностью абстрагирован. У вас не должно быть необходимости самостоятельно собирать, конвертировать и проверять параметры запроса. Контроллер выполняет эту задачу и устанавливает собранные, преобразованные и проверенные параметры запроса в модели. Все, что вам нужно сделать, это определить методы действий, которые напрямую работают с свойствами модели. Вид представлен "компонентами" в аромате тегов JSP или XML-элементов, которые, в свою очередь, генерируют HTML/CSS/JS. Состояние представления для последующих запросов сохраняется в сеансе. Это особенно полезно для серверных преобразований, проверки и изменения значений. Вот как среди других JSF, Wicket и Play! работает.

В качестве побочного примечания, хобби вокруг с доморощенной структурой MVC - это очень хорошее упражнение по обучению, и я рекомендую его, если вы храните его в личных/личных целях. Но как только вы станете профессионалом, тогда настоятельно рекомендуется выбрать существующую структуру, а не изобретать свои собственные. Изучение существующей и хорошо развитой структуры занимает в течение длительного времени меньше времени, чем разработка и поддержание надежной структуры.

В нижеследующем подробном объяснении я ограничусь запросом на основе MVC, поскольку это проще реализовать.


Образец переднего контроллера (шаблон посредника)

Во-первых, часть контроллера должна реализовать шаблон Front Controller (который является специализированным видом шаблон посредника). Он должен состоять только из одного сервлета, который обеспечивает централизованную точку входа для всех запросов. Он должен создать модель на основе информации, доступной по запросу, такой как путь pathinfo или servletpath, метод и/или конкретные параметры. Бизнес-модель называется Action в приведенном ниже примере HttpServlet.

protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    try {
        Action action = ActionFactory.getAction(request);
        String view = action.execute(request, response);

        if (view.equals(request.getPathInfo().substring(1)) {
            request.getRequestDispatcher("/WEB-INF/" + view + ".jsp").forward(request, response);
        }
        else {
            response.sendRedirect(view); // We'd like to fire redirect in case of a view change as result of the action (PRG pattern).
        }
    }
    catch (Exception e) {
        throw new ServletException("Executing action failed.", e);
    }
}

Выполнение действия должно возвращать некоторый идентификатор, чтобы найти представление. Проще всего было бы использовать его как имя файла JSP. Сопоставьте этот сервлет на конкретном url-pattern в web.xml, например. /pages/*, *.do или даже просто *.html.

В случае префикса-шаблонов, например, /pages/*, вы можете вызвать URL-адрес, например http://example.com/pages/register, http://example.com/pages/login и т.д. и предоставить /WEB-INF/register.jsp, /WEB-INF/login.jsp соответствующие действия GET и POST. Части register, login и т.д. Затем доступны request.getPathInfo(), как в приведенном выше примере.

Когда вы используете суффикс-шаблоны, такие как *.do, *.html и т.д., тогда вы можете вызвать URL-адрес, например http://example.com/register.do, http://example.com/login.do и т.д., и вы должны изменить примеры кода в этом ответе (также ActionFactory), чтобы извлечь register и login части request.getServletPath() вместо этого.


Стратегия

Action должен следовать шаблону стратегии . Его нужно определить как абстрактный/тип интерфейса, который должен выполнять работу, основанную на аргументах переданного абстрактного метода (это отличие от команды pattern, в котором тип abstract/interface должен выполнять работу на основе аргументов, которые были переданы во время создания реализации).

public interface Action {
    public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception;
}

Возможно, вы захотите сделать Exception более конкретным с настраиваемым исключением, например ActionException. Это просто базовый пример, остальное зависит от вас.

Здесь приведен пример LoginAction, который (по его словам) регистрируется пользователем. Сама модель User является моделью данных. Вид знает о наличии User.

public class LoginAction implements Action {

    public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        User user = userDAO.find(username, password);

        if (user != null) {
            request.getSession().setAttribute("user", user); // Login user.
            return "home"; // Redirect to home page.
        }
        else {
            request.setAttribute("error", "Unknown username/password. Please retry."); // Store error message in request scope.
            return "login"; // Go back to redisplay login form with error.
        }
    }

}

Factory шаблон метода

ActionFactory должен следовать шаблону Factory. В принципе, он должен обеспечить метод создания, который возвращает конкретную реализацию абстрактного/интерфейса. В этом случае он должен вернуть реализацию интерфейса Action на основе информации, предоставленной запросом. Например, method и pathinfo ( pathinfo - это часть после контекста и пути сервлета в URL-адресе запроса, за исключением строки запроса).

public static Action getAction(HttpServletRequest request) {
    return actions.get(request.getMethod() + request.getPathInfo());
}

В свою очередь, actions должен быть частью static/applicationwide Map<String, Action>, который содержит все известные действия. Это зависит от вас, как заполнить эту карту. Жестко прописывать:

actions.put("POST/register", new RegisterAction());
actions.put("POST/login", new LoginAction());
actions.put("GET/logout", new LogoutAction());
// ...

Или настраивается на основе файла свойств/XML-конфигурации в пути к классам: (псевдо)

for (Entry entry : configuration) {
    actions.put(entry.getKey(), Class.forName(entry.getValue()).newInstance());
}

Или динамически на основе проверки в пути к классам для классов, реализующих определенный интерфейс и/или аннотацию: (псевдо)

for (ClassFile classFile : classpath) {
    if (classFile.isInstanceOf(Action.class)) {
       actions.put(classFile.getAnnotation("mapping"), classFile.newInstance());
    }
}

Имейте в виду создать "ничего не делать" Action для случая отсутствия сопоставления. Пусть, например, вернет обратно request.getPathInfo().substring(1).


Другие шаблоны

Это были важные модели.

Чтобы получить еще один шаг, вы можете использовать шаблон фасада для создания класса Context, который, в свою очередь, обертывает объекты запроса и ответа и предлагает несколько методов удобства, делегирующих объекты запроса и ответа и передавая это как аргумент в метод Action#execute(). Это добавляет дополнительный абстрактный слой, чтобы скрыть исходный API сервлетов. В итоге вы должны в конечном итоге создать объявления ноль import javax.servlet.* в каждой реализации Action. В терминах JSF это то, что FacesContext и ExternalContext классы. Вы можете найти конкретный пример в этом ответе.

Тогда существует шаблон состояния для случая, когда вы хотите добавить дополнительный уровень абстракции для разделения задач по сбору параметров запроса, их преобразования, проверки их, обновления значений модели и выполнения действий. В терминах JSF это то, что делает LifeCycle.

Затем создайте Composite pattern для случая, когда вы хотите создать компонентный вид, который может быть присоединен к модели и чей поведение зависит от состояния жизненного цикла, основанного на запросе. В терминах JSF это означает UIComponent.

Таким образом, вы можете постепенно развиваться в сторону основывания на основе компонентов.


См. также:

Ответ 2

В пробитом шаблоне MVC сервлет является "C" - контроллером.

Его основная задача - выполнить первоначальную оценку запроса, а затем отправить обработку на основе начальной оценки конкретному работнику. Одна из рабочих обязанностей может заключаться в настройке некоторого уровня представления beans и пересылка запроса на страницу JSP для визуализации HTML. Поэтому по этой причине вам нужно передать объект запроса на уровень обслуживания.

Я бы, однако, не начал писать raw Servlet классы. Работа, которую они делают, является очень предсказуемой и готовой, что делает рамки очень хорошо. К счастью, есть много доступных, проверенных временем кандидатов (в алфавитном порядке): Apache Wicket, Java Server Faces, Spring, чтобы назвать несколько.

Ответ 3

IMHO, нет большой разницы в случае веб-приложения, если вы посмотрите на него с точки зрения назначения ответственности. Однако сохраните ясность в слое. Храните что-либо чисто для цели презентации в уровне презентации, например, для элемента управления и кода, характерного для веб-элементов управления. Просто держите свои объекты в бизнес-слое и всех функциях (например, добавьте, отредактируйте, удалите) и т.д. На бизнес-уровне. Однако, превращая их в браузер, который будет обрабатываться на уровне презентации. Для .Net шаблон ASP.NET MVC очень хорош с точки зрения сохранения слоев. Посмотрите на шаблон MVC.

Ответ 4

Я использовал структуру struts и считаю ее довольно простой в освоении. При использовании структуры расположений каждая страница вашего сайта будет иметь следующие элементы.

1) Действие, которое используется, вызывается каждый раз, когда обновляется страница HTML. Действие должно заполнять данные в форме при первой загрузке страницы и обрабатывать взаимодействия между веб-интерфейсом и бизнес-слоем. Если вы используете страницу jsp для изменения изменяемого java-объекта, копия java-объекта должна храниться в форме, а не в оригинале, чтобы исходные данные не изменялись, если пользователь не сохранил страницу.

2) Форма, которая используется для передачи данных между действием и страницей jsp. Этот объект должен состоять из набора getter и seters для атрибутов, которые должны быть доступны для jsp файла. У формы также есть метод проверки данных до того, как он будет сохранен.

3) Страница jsp, которая используется для отображения окончательного HTML-страницы. Страница jsp представляет собой гибрид HTML и специальных таблиц расположений, используемых для доступа к данным и их обработки в форме. Хотя struts позволяет пользователям вставлять Java-код в файлы jsp, вы должны быть очень осторожны в этом, потому что это затрудняет чтение вашего кода. Java-код внутри jsp файлов трудно отлаживать и не может быть проверен модулем. Если вы обнаружите, что в jsp файле написано более 4-5 строк кода Java, код, вероятно, должен быть перемещен в действие.

Ответ 5

Отличный ответ BalusC охватывает большинство шаблонов для веб-приложений.

Некоторым приложениям может потребоваться Chain-of-responsibility_pattern

В объектно-ориентированном дизайне шаблон цепочки ответственности представляет собой шаблон проектирования, состоящий из источника командных объектов и серии объектов обработки. Каждый объект обработки содержит логику, которая определяет типы объектов команд, которые он может обрабатывать; остальные передаются следующему процессу обработки в цепочке.

Использовать случай для использования этого шаблона:

Когда обработчик для обработки запроса (команды) неизвестен, и этот запрос может быть отправлен нескольким объектам. Как правило, вы устанавливаете преемника объекта. Если текущий объект не может обработать запрос или обработать запрос частично и передать тот же запрос объекту-преемнику.

Полезные вопросы/статьи SE:

Почему я должен использовать цепочку ответственности над декоратором?

Общие нормы ответственности за цепочку ответственности

chain-of-responsibility-pattern из oodesign

chain_of_responsibility от sourcemaking