Ръководство за модела на предния контролер в Java

1. Общ преглед

В този урок ще разгледаме по-задълбочено шаблона на предния контролер , част от корпоративните модели, както е дефинирано в книгата на Мартин Фаулър „Модели на архитектурата на корпоративното приложение“.

Front Controller се дефинира като „контролер, който обработва всички заявки за уеб сайт“. Той стои пред уеб приложение и делегира заявки на следващи ресурси. Той също така осигурява интерфейс за общо поведение като сигурност, интернационализация и представяне на конкретни гледни точки на определени потребители.

Това позволява на приложението да промени поведението си по време на изпълнение. Освен това помага за четене и поддържане на приложение, като предотвратява дублирането на код.

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

2. Как работи?

Моделът на предния контролер е главно разделен на две части. Един диспечерски контролер и йерархия на командите. Следният UML изобразява връзките между класовете на обща реализация на Front Controller:

Този единичен контролер изпраща заявки към команди, за да задейства поведение, свързано със заявка.

За да демонстрираме изпълнението му, ще внедрим контролера в FrontControllerServlet и команди като класове, наследени от абстрактна FrontCommand .

3. Настройка

3.1. Зависимости на Maven

Първо ще настроим нов проект на Maven WAR с включен javax.servlet-api :

 javax.servlet javax.servlet-api 4.0.0-b01 provided  

както и jetty-maven-plugin :

 org.eclipse.jetty jetty-maven-plugin 9.4.0.M1   /front-controller   

3.2. Модел

След това ще дефинираме клас Model и хранилище на модели . Като наш модел ще използваме следния клас на книга :

public class Book { private String author; private String title; private Double price; // standard constructors, getters and setters }

Това ще бъде хранилището, можете да търсите изходния код за конкретна реализация или да го предоставите сами:

public interface Bookshelf { default void init() { add(new Book("Wilson, Robert Anton & Shea, Robert", "Illuminati", 9.99)); add(new Book("Fowler, Martin", "Patterns of Enterprise Application Architecture", 27.88)); } Bookshelf getInstance();  boolean add(E book); Book findByTitle(String title); }

3.3. FrontControllerServlet

Прилагането на самия Servlet е доста просто. Извличаме името на командата от заявка, създаваме динамично нов екземпляр на команден клас и го изпълняваме.

Това ни позволява да добавяме нови команди, без да променяме кодовата база на нашия преден контролер .

Друга възможност е да се приложи Servlet, използвайки статична, условна логика. Това има предимството при проверка на грешки по време на компилация:

public class FrontControllerServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) { FrontCommand command = getCommand(request); command.init(getServletContext(), request, response); command.process(); } private FrontCommand getCommand(HttpServletRequest request) { try { Class type = Class.forName(String.format( "com.baeldung.enterprise.patterns.front." + "controller.commands.%sCommand", request.getParameter("command"))); return (FrontCommand) type .asSubclass(FrontCommand.class) .newInstance(); } catch (Exception e) { return new UnknownCommand(); } } }

3.4. FrontCommand

Нека реализираме абстрактен клас, наречен FrontCommand , който държи поведението, общо за всички команди.

Този клас има достъп до ServletContext и неговите обекти за заявки и отговори. Освен това ще се справи с разделителната способност на изгледа:

public abstract class FrontCommand { protected ServletContext context; protected HttpServletRequest request; protected HttpServletResponse response; public void init( ServletContext servletContext, HttpServletRequest servletRequest, HttpServletResponse servletResponse) { this.context = servletContext; this.request = servletRequest; this.response = servletResponse; } public abstract void process() throws ServletException, IOException; protected void forward(String target) throws ServletException, IOException { target = String.format("/WEB-INF/jsp/%s.jsp", target); RequestDispatcher dispatcher = context.getRequestDispatcher(target); dispatcher.forward(request, response); } }

Конкретно изпълнение на този абстрактен FrontCommand би било SearchCommand . Това ще включва условна логика за случаи, когато е намерена книга или липсва книга:

public class SearchCommand extends FrontCommand { @Override public void process() throws ServletException, IOException { Book book = new BookshelfImpl().getInstance() .findByTitle(request.getParameter("title")); if (book != null) { request.setAttribute("book", book); forward("book-found"); } else { forward("book-notfound"); } } }

If the application is running, we can reach this command by pointing our browser to //localhost:8080/front-controller/?command=Search&title=patterns.

The SearchCommand resolves to two views, the second view can be tested with the following request //localhost:8080/front-controller/?command=Search&title=any-title.

To round up our scenario we'll implement a second command, which is fired as fallback in all cases, a command request is unknown to the Servlet:

public class UnknownCommand extends FrontCommand { @Override public void process() throws ServletException, IOException { forward("unknown"); } }

This view will be reachable at //localhost:8080/front-controller/?command=Order&title=any-title or by completely leaving out the URL parameters.

4. Deployment

Тъй като решихме да създадем проект с WAR файл, ще ни е необходим дескриптор за уеб разполагане. С този web.xml можем да стартираме нашето уеб приложение във всеки контейнер на Servlet:

   front-controller  com.baeldung.enterprise.patterns.front.controller.FrontControllerServlet    front-controller /  

Като последна стъпка ще стартираме „mvn install jetty: run“ и ще проверим нашите изгледи в браузър.

5. Заключение

Както видяхме досега, сега трябва да сме запознати с модела на предния контролер и неговото изпълнение като Servlet и йерархия на командите.

Както обикновено, ще намерите източниците на GitHub.