Wzorce projektowe aplikacje internetowe [zamknięte]

Projektuję prostą aplikację internetową. Jestem nowy w tej domenie internetowej.Potrzebowałem twojej rady odnośnie wzorców projektowych, takich jak sposób podziału odpowiedzialności pomiędzy Servlety, kryteria tworzenia nowych Servletów itp.

Właściwie mam kilka encji na mojej stronie głównej i odpowiadając każdemu z nich mamy kilka opcji, takich jak Dodaj, Edytuj i usuń. Wcześniej używałem jednego Servleta na opcje takie jak Servlet1 dla add entity1, Servlet2 dla edit entity1 i tak dalej i w w ten sposób otrzymaliśmy dużą liczbę serwletów.

Teraz zmieniamy nasz projekt. Moje pytanie brzmi jak dokładnie wybrać, jak wybrać odpowiedzialność servleta. Powinniśmy mieć jeden Servlet na jednostkę, który przetworzy wszystkie jego opcje i przekaże żądanie do warstwy usług. A może powinniśmy mieć jeden servlet dla całej strony, który przetworzy całe żądanie strony, a następnie przekaże je do odpowiedniej warstwy usług? Również, jeżeli obiekt żądania przekazany do warstwa usługowa czy nie.

Author: Broman, 2010-08-22

5 answers

Trochę przyzwoita aplikacja internetowa składa się z mieszanki wzorców projektowych. Wspomnę tylko o tych najważniejszych.


Model View Controller pattern

Podstawowy (architektoniczny) wzorzec projektowy, którego chcesz użyć, to wzorzec model-widok-kontroler. Kontroler ma być reprezentowany przez Servlet, który bezpośrednio tworzy/używa określonego modelu i widoku na podstawie żądania. Model ma być reprezentowane przez klasy Javabean. Jest to często dalej dzielone w model biznesowy , który zawiera działania (zachowanie) i model danych , który zawiera dane (informacje). Widok ma być reprezentowany przez pliki JSP, które mają bezpośredni dostęp do danych () Model by EL (Expression Language).

Następnie, istnieją różnice w zależności od tego, jak działania i zdarzenia są obsługiwane. Popularne są:

  • Request (action) based MVC: jest to najprostszy do zaimplementowania. Biznes () Model działa bezpośrednio z obiektami HttpServletRequest i HttpServletResponse. Musisz zebrać, przekonwertować i zweryfikować parametry żądania (głównie) samodzielnie. Widok może być reprezentowany przez zwykły waniliowy HTML / CSS / JS i nie zachowuje stanu między żądaniami. Tak m.in. Spring MVC, Rozpórki I paski działa.

  • MVC oparte na komponentach : jest to trudniejsze do wdrożenia. Ale kończy się prostszy model i widok, w którym wszystkie "surowe" API Servlet jest abstrakcyjny całkowicie. Nie powinieneś mieć potrzeby samodzielnego gromadzenia, konwersji i walidacji parametrów żądania. Kontroler wykonuje to zadanie i ustawia zebrane, przekonwertowane i zweryfikowane parametry żądania w modelu . Wszystko, co musisz zrobić, to zdefiniować metody działania, które działają bezpośrednio z właściwościami modelu. Widok jest reprezentowany przez "komponenty" w znacznikach JSP lub elementach XML, które z kolei generują HTML/CSS / JS. Stan widoku dla kolejnych żądań jest utrzymywany w sesji. Jest to szczególnie przydatne w przypadku konwersji po stronie serwera,walidacji i zmian wartości. Tak m.in. JSF, Wicket i Graj!Działa.

Na marginesie, hobby wokół z domowy Framework MVC jest bardzo miłym ćwiczeniem edukacyjnym i polecam go tak długo, jak długo przechowujesz go do celów osobistych/prywatnych. Ale gdy przejdziesz do profesjonalizmu, zdecydowanie zaleca się wybranie istniejących ram, a nie wymyślanie własnych. Uczenie się istniejących i dobrze rozwiniętych frameworków zajmuje w dłuższej perspektywie mniej czasu niż samodzielne opracowanie i utrzymanie solidnych frameworków.

W poniższym szczegółowym wyjaśnieniu ograniczę się do request based MVC, ponieważ to łatwiejsze do wdrożenia.


Wzór kontrolera przedniego (wzór mediatora )

Pierwszy, Kontroler część powinna zaimplementować przedni kontroler wzór (który jest wyspecjalizowanym rodzajem mediator wzór). Powinien on składać się tylko z jednego serwletu, który zapewnia scentralizowany punkt wejścia dla wszystkich żądań. Powinien on stworzyć model w oparciu o informacje dostępne w zapytaniu, takie jak pathinfo lub servletpath, metoda i / lub określone parametry. Model biznesowy nazywa się Action poniżej HttpServlet przykład.

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

Wykonanie akcji powinno zwrócić jakiś identyfikator, aby zlokalizować widok. Najprościej byłoby użyć go jako nazwy pliku JSP. Mapować ten servlet na konkretny url-pattern W web.xml, np. /pages/*, *.do lub nawet po prostu *.html.

W przypadku prefix-patterns jak na przykład /pages/* można wtedy wywołać URL ' a jak http://example.com/pages/register, http://example.com/pages/login , itp. i zapewniają /WEB-INF/register.jsp, /WEB-INF/login.jsp z odpowiednimi akcjami GET I POST. Części register, login, itp są wówczas dostępne przez request.getPathInfo() jak w powyższym przykładzie.

Gdy używasz sufiksów-wzorców takich jak *.do, *.html, itd, następnie można wywołać URL jest jak http://example.com/register.do, http://example.com/login.do , etc i należy zmienić kod przykłady w tej odpowiedzi (również ActionFactory), aby wyodrębnić register i login części przez request.getServletPath() zamiast tego.


Wzór strategii

Action powinny być zgodne ze schematem strategii . Musi być zdefiniowany jako typ abstrakcyjny / interfejs, który powinien wykonywać pracę w oparciu o przekazane w argumenty metody abstrakcyjnej (jest to różnica z wzorcem poleceń , w którym Typ abstrakcyjny / interfejs powinien wykonywać pracę na podstawie argumentów, które zostały przekazane podczas tworzenia implementacji).

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

Możesz chcieć uszczegółowić Exception za pomocą wyjątku niestandardowego, takiego jak ActionException. To tylko podstawowy przykład, reszta zależy od Ciebie.

Oto przykład LoginAction, który (jak sama nazwa mówi) loguje się do użytkownika. Sam model User jest z kolei modelem danych. widok {[59] } jest świadomy obecności 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.
        }
    }

}

Wzór metody Fabrycznej

ActionFactory powinny być zgodne ze wzorem metody Fabrycznej . Zasadniczo powinien on zapewniać metodę kreacyjną, która zwraca konkretną implementację typu abstrakcyjnego / interfejsu. W takim przypadku powinien on zwrócić implementację interfejsu Action w oparciu o informacje dostarczone przez żądanie. Na przykład, metoda i pathinfo (pathinfo jest częścią po kontekście i ścieżka servleta w adresie URL żądania, z wyłączeniem ciągu zapytania).

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

actions z kolei powinna być jakaś statyczna / aplikacyjna Map<String, Action>, która przechowuje wszystkie znane akcje. Od Ciebie zależy, jak wypełnić tę mapę. Hardcoding:

actions.put("POST/register", new RegisterAction());
actions.put("POST/login", new LoginAction());
actions.put("GET/logout", new LogoutAction());
// ...
Można je również skonfigurować na podstawie pliku konfiguracyjnego properties / XML w classpath: (pseudo)
for (Entry entry : configuration) {
    actions.put(entry.getKey(), Class.forName(entry.getValue()).newInstance());
}

Lub dynamicznie na podstawie skanowania w classpath dla klas implementujących określony interfejs i / lub adnotację: (pseudo)

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

Należy pamiętać, aby utworzyć "nic nie robić" Action W przypadku, gdy nie ma mapowania. Niech na przykład zwróci bezpośrednio request.getPathInfo().substring(1) wtedy.


Inne wzory

To były ważne wzory do tej pory.

Aby przejść o krok dalej, możesz użyć wzór elewacji do utworzenia klasy Context, która z kolei owija obiekty request I response i oferuje kilka wygodnych metod delegowania do obiektów request I response i przekazać to jako argument do metody Action#execute(). Dodaje to dodatkową warstwę abstrakcyjną, aby ukryć surowe API serwletów. Wtedy powinieneś skończyć z zero import javax.servlet.* deklaracje w każdym Action wdrożeniu. W sensie JSF, to jest to, co FacesContext oraz ExternalContext zajęcia się kończą. Konkretny przykład można znaleźć w tej odpowiedzi .

Potem jest wzorzec stanu Dla Przypadku, w którym chcesz dodać dodatkowy warstwa abstrakcji do podziału zadań gromadzenia parametrów żądania, ich konwersji, walidacji, aktualizacji wartości modelu i wykonywania akcji. W sensie JSF, to jest to, co LifeCycle robi.

Następnie istnieje wzorzec złożony Dla Przypadku, w którym chcesz utworzyć widok oparty na komponentach, który może być dołączony do modelu i którego zachowanie zależy od stanu cyklu życia opartego na żądaniach. W sensie JSF, to jest to, co UIComponent reprezentować.

W ten sposób możesz ewoluować bit po bitie w kierunku frameworka opartego na komponentach.


Zobacz też:

 471
Author: BalusC,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:02:47

W schemacie MVC Servlet jest kontrolerem "C".

Jego głównym zadaniem jest przeprowadzenie wstępnej oceny wniosku, a następnie wysłanie przetwarzania na podstawie wstępnej oceny do konkretnego pracownika. Jednym z obowiązków pracownika może być skonfigurowanie warstwy prezentacji i przekazanie żądania do strony JSP w celu renderowania HTML. Dlatego tylko z tego powodu należy przekazać obiekt żądania do warstwy usług.

Nie zacząłbym jednak pisać raw Servlet klasy. Praca, którą wykonują, jest bardzo przewidywalna i Na szczęście istnieje wiele dostępnych, sprawdzonych w czasie kandydatów (w kolejności alfabetycznej): Apache Wicket, Java Server Faces, Wiosna aby wymienić tylko kilka.

 9
Author: Alexander Pogrebnyak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-08-22 13:42:25

IMHO, nie ma dużej różnicy w przypadku aplikacji webowej, jeśli spojrzeć na nią z perspektywy przypisania odpowiedzialności. Zachowaj jednak przejrzystość w warstwie. Przechowuj w warstwie prezentacji Wszystko wyłącznie do celów prezentacji, takie jak kontrolka i kod specyficzny dla kontrolek internetowych. Po prostu trzymaj swoje podmioty w warstwie biznesowej i wszystkie funkcje (takie jak dodawanie, edycja, usuwanie) itp. Jednak renderowanie ich na przeglądarkę do obsługi w prezentacji warstwa. For. Net, the ASP.NET wzór MVC jest bardzo dobry pod względem utrzymania warstw oddzielonych. Spójrz na wzór MVC.

 3
Author: Kangkan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-08-22 10:25:46

Użyłem frameworka struts i uważam, że jest on dość łatwy do nauczenia się. Podczas korzystania z struktury struts każda strona witryny będzie miała następujące elementy.

1) akcja, która jest używana jest wywoływana za każdym razem, gdy strona HTML jest odświeżana. Operacja powinna wypełnić dane w formie, gdy strona jest ładowana po raz pierwszy i obsługuje interakcje między interfejsem sieciowym a warstwą biznesową. Jeśli używasz strony jsp do modyfikowania zmiennego obiektu java, Kopia obiektu java powinna być przechowywane w formie, a nie w oryginale, aby oryginalne dane nie były modyfikowane, chyba że użytkownik zapisze stronę.

2) formularz służący do przesyłania danych pomiędzy akcją a stroną jsp. Obiekt ten powinien składać się z zestawu getter i setter dla atrybutów, które muszą być dostępne dla pliku jsp. Formularz ma również metodę walidacji danych, zanim zostaną zachowane.

3) strona jsp, która służy do renderowania ostatecznego HTML strony. Strona jsp jest hybryda znaczników HTML i specjalnych struts używanych do dostępu i manipulowania danymi w formularzu. Chociaż struts pozwala użytkownikom na wstawianie kodu Javy do plików jsp, powinieneś być bardzo ostrożny, ponieważ utrudnia to odczyt kodu. Kod Java wewnątrz plików jsp jest trudny do debugowania i nie może być testowany jednostkowo. Jeśli zauważysz, że piszesz więcej niż 4-5 linii kodu java wewnątrz pliku jsp, kod powinien być prawdopodobnie przeniesiony do akcji.

 1
Author: EsotericNonsense,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-11 14:51:57

BalusC doskonała odpowiedź obejmuje większość wzorców dla aplikacji internetowych.

Niektóre aplikacje mogą wymagać łańcucha odpowiedzialności_pattern

W projektowaniu obiektowym, wzór łańcuch odpowiedzialności jest wzorcem projektowym składającym się ze źródła obiektów poleceń i szeregu obiektów przetwarzających. Każdy obiekt przetwarzania zawiera logikę, która określa typy obiektów poleceń, które może obsługiwać; reszta jest przekazywana do następnego przetwarzanie obiektu w łańcuchu.

Użyj case, aby użyć tego wzoru:

Gdy funkcja obsługi przetwarzania żądania (polecenia) jest nieznana i żądanie to może zostać wysłane do wielu obiektów. Zazwyczaj ustawia się następcę na obiekt. Jeśli bieżący obiekt nie może obsłużyć żądania lub przetworzyć żądania częściowo i przesłać to samo żądanie do następcy obiektu.

Przydatne pytania/artykuły SE:

Po co miałbym używać łańcucha Odpowiedzialność za dekoratora?

Typowe zastosowania łańcucha odpowiedzialności?

Chain-Of-responsibility-pattern from oodesign

Chain_of_responsibility from sourcemaking

 1
Author: Ravindra babu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-04 09:47:57