первоначальный проект
Используйте Spring Boot и web, тимелеаф-стартер для настройки исходного проекта. Конфигурация xml выглядит следующим образом:
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.1</version> <relativePath/></parent><dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency></dependencies>
скопировать код
Тестовые задания
Чтобы понять, как работает Spring Web MVC, сначала можно реализовать простую функцию входа в систему. Создать@Controller
класс для измененияInternalController
, этот класс содержит метод для обработки запросов GET.hello()
Возвращает строку имени представления, интерпретируемую Spring. (в данном случае этоlogin.html
)
@GetMapping("/")public String hello() { return "login";}
скопировать код
Чтобы обработать логику входа пользователя, создайте другой метод с данными входа, который принимает запрос POST. Затем верните страницу успеха или неудачи в соответствии с результатом обработки. Уведомление,login()
Функция принимает доменный объект в качестве параметра и возвращаетModelAndView
объект.
@PostMapping("/login")public ModelAndView login(LoginData loginData) { if (LOGIN.equals(loginData.getLogin()) && PASSWORD.equals(loginData.getPassword())) { return new ModelAndView("success", Collections.singletonMap("login", loginData.getLogin())); } else { return new ModelAndView("failure", Collections.singletonMap("login", loginData.getLogin())); }}
скопировать код
ModelAndView
Сохраняются два разных объекта:
-
Модель: карта, используемая для отображения страницы.
-
Вид: страница шаблона.
Для удобства они объединены, чтобы метод контроллера мог возвращать оба. последнее использованиеThymeleaf
Действует как механизм шаблонов для рендеринга страниц.
Основы веб-приложений Java — сервлет
при вводе в браузереhttp://localhost:8080/
, а затем нажмите Enter, что именно происходит, когда запрос достигает сервера? Как данные этого веб-запроса отображаются в браузере? Поскольку этот проект представляет собой простое приложение Spring Boot, к нему можно получить доступ черезSpring5Application
Основной метод запускает проект. Spring Boot использует Apache Tomcat для запуска программы по умолчанию.После успешного запуска вы можете увидеть тот же журнал, что и ниже:
2018-04-10 20:36:11.626 INFO 57414 --- [main]
o.s.b.w.embedded.tomcat.TomcatWebServer :
Tomcat initialized with port(s): 8080 (http)2018-04-10 20:36:11.634 INFO 57414 --- [main]
o.apache.catalina.core.StandardService :
Starting service [Tomcat]2018-04-10 20:36:11.635 INFO 57414 --- [main]
org.apache.catalina.core.StandardEngine :
Starting Servlet Engine: Apache Tomcat/8.5.23
скопировать код
Поскольку Tomcat является контейнером сервлетов, почти все HTTP-запросы обрабатываются сервлетами Java. Естественная точка входа в Spring Web — это сервлет. Сервлет является основным компонентом всех веб-приложений Java; он очень низкого уровня и не предоставляет каких-либо конкретных шаблонов программирования, таких как MVC. HTTP-сервер может принимать только HTTP-запросы и возвращает ответ после обработки запроса. Последний API Servlet 3.0 больше не может использовать конфигурацию XML и может напрямую использовать конфигурацию Java.
Ядро Spring MVC — DispatcherServlet
Как веб-разработчики, мы хотим абстрагироваться от следующих скучных задач и сосредоточиться на полезной бизнес-логике.
-
Сопоставьте HTTP-запросы с соответствующими функциями обработчика.
-
Разбирать данные и заголовки HTTP-запроса в объекты DTO или домена.
-
Использование шаблона проектирования модель-представление-контроллер
-
Генерируйте ответы непосредственно из DTO, объектов домена и т. д.
ВеснаDispatcherServlet
Предоставляет вышеуказанные функции, является ядром среды Spring WEB MVC и основным компонентом приложения для приема всех запросов.DispatcherServlet
Расширяемость очень сильная. Например: он позволяет добавлять существующие или новые адаптеры для решения различных задач:
-
Сопоставьте запрос с классом или функцией, которая его обрабатывает (путем
HandlerMapping
выполнить) -
Используйте определенный шаблон для обработки запросов, например простой сервлет, сложный рабочий процесс MVC или просто метод. (Зависит от
HandlerAdapter
выполнить) -
Разрешает объекты представления по имени, позволяя вам использовать различные механизмы шаблонов, такие как XML, XSLT или другие технологии представления (путем
ViewResolver
выполнить) -
По умолчанию компонент загрузки файлов Apache Commons используется для разбора загрузки файлов, или вы можете реализовать его самостоятельно.
-
Зависит от
LocalResolver
Реализуйте локализацию, включая файлы cookie, сеансы, HTTP-заголовок Accept или другие локализации, определенные пользователем.
Обработка HTTP-запросов
DispatcherServlet
Существует длинная иерархия наследования. Необходимо понимать каждое отдельное понятие сверху вниз.
GenericServlet
GenericServlet是
Часть спецификации сервлета, определяющаяservice()
методы для приема запросов и возврата ответов.
public abstract void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;
скопировать код
Все запросы с сервера будут вызывать этот метод.
HttpServlet
Как его имя,HttpServelt
Является реализацией HTTP-запроса в спецификации сервлета. Точнее,HttpServlet
это реализацияservice()
абстрактный класс. При разделении различных типов HTTP-запросов, которые должны обрабатываться разными функциями, реализация выглядит примерно так:
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String method = req.getMethod(); if (method.equals(METHOD_GET)) { // ... doGet(req, resp); } else if (method.equals(METHOD_HEAD)) { // ... doHead(req, resp); } else if (method.equals(METHOD_POST)) { doPost(req, resp); // ... }
скопировать код
HttpServletBean
в этих наследственных отношенияхHttpServletBean
это первый весенний класс. Начальные параметры, полученные из web.xml или WebApplicationInitialzer для внедрения свойств компонента. Запросы в приложении вызывают doGet, doPost и другие методы соответственно для обработки различных HTTP-запросов.
FrameworkServlet
FrameworkServlet
ДостигнутоApplicationContextAware
, Интегрированный контекст веб-приложения. Однако он также может создавать собственный контекст приложения. Как упоминалось выше, родительский классHttpServletBean
Путем внедрения начальных параметров в качестве свойств bean-компонента. Итак, если имя класса контекста находится вcontextClass
В этом начальном параметре есть этот параметр для создания приложения
экземпляр контекста, в противном случае используется значение по умолчаниюXmlWebApplicationContext
. Поскольку конфигурация XML сейчас не является рекомендуемым способом настройки для Spring. Spring Boot использует по умолчаниюAnnotationConfigWebApplicationContext
настроитьDispatcherServlet
.
DispatcherServlet: Унифицированная обработка запросов
HttpServlet.service()
Отправка разных запросов к разным методам через типы HTTP-запросов хорошо реализована в базовом сервлете. Однако на уровне абстракции SpringMVC запросы не могут маршрутизироваться только по типу метода. такой же,FrameworkServlet
Другая основная функция заключается в использовании различной обработкиprocessRequest()
соединить все вместе.
@Overrideprotected final void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response);}@Overrideprotected final void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response);}
скопировать код
DispatcherServlet: добавьте полезную информацию в запрос
DispatcherServlet
выполнитьdoService()
метод. Он добавляет в запрос некоторые полезные объекты, а затем передает их в обработку веб-запроса, например: контекст веб-приложения, преобразователь локали, преобразователь темы, источник темы и т. д.
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
скопировать код
в то же время,doService()
Добавлена флэш-карта ввода-вывода, базовый шаблон для передачи параметров из одного запроса в другой. Полезно в редиректах. (например, показ простого сообщения пользователю после перенаправления)
FlashMap inputFlashMap = this.flashMapManager .retrieveAndUpdate(request, response);if (inputFlashMap != null) { request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));}request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
скопировать код
тогдаdoService()
позвонюdoDispatch()
способ отправки запроса.
DispatcherServlet: Отправка запросов
dispatch()
Основная цель — найти подходящий обработчик для обработки запроса и передачи параметров запроса/ответа. Обработчик может быть любым объектом и не ограничен конкретным интерфейсом. Это также означает, что Spring необходимо найти адаптер для использования этого обработчика. Чтобы найти подходящий обработчик для запроса, Spring просматривает реализациюHandlerMapping
Зарегистрированная реализация интерфейса. Существует множество различных реализаций для удовлетворения наших различных потребностей.SimpleUrlHandlerMapping
Сопоставьте запросы с обработкой bean-компонентов с помощью URL-адресов.RequestMappingHandlerMapping
Вероятно, наиболее широко используемый картографический процессор. он сопоставляет запрос с@Controller
под класс@RequestMapping
способ модификации. Это пример вышеhello()
иlogin()
.
Обратите внимание, что два вышеуказанных метода@GetMapping
и@PostMapping
декоративный. Эти две аннотации взяты из@RequestMapping
.dispatch()
Он также может обрабатывать некоторые другие задачи HTTP:
-
Если ресурс не существует, сократите запрос GET.
-
Используйте составной анализ для соответствующего запроса.
-
Если процессор предпочитает обрабатывать запрос асинхронно, замкните запрос.
обработать запрос
Теперь, когда Spring определил обработчик и адаптер обработчика для обработки запроса, пришло время обработать запрос. НижеHandlerAdapter.handle()
подпись. Более важным моментом является то, что процессор может выбирать, как обрабатывать запрос:
-
Запишите ответ непосредственно в тело ответа и верните null
-
возвращает
DispatcherServlet
оказанныйModelAndView
объект.
@NullableModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
скопировать код
Spring предоставляет множество типов обработчиков, следующиеSimpleControllerHandlerAdapter
Как обрабатывать экземпляры контроллера Spring MVC (не путать с @Controller, вот класс).
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return ((Controller) handler).handleRequest(request, response);}
скопировать код
ВторойSimpleServletHandlerAdapter
Он адаптируется к обычному сервлету. сервлет не знаетModelAndView
, обработайте запрос полностью самостоятельно и запишите возврат в соответствующее тело. Поэтому его адаптер просто возвращает null.
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { ((Servlet) handler).service(request, response); return null;}
скопировать код
В этом примере контроллер создается@RequestMapping
оформленный POJO, поэтому процессор будет использоватьHandlerMethod
метод его инкапсуляции. Весеннее использованиеRequestMappingHandlerAdapter
для этого типа процессора.
Обработать аргументы, вернуть значение функции-обработчика
Обратите внимание, что обычно контроллер не получаетHttpServletRequest
иHttpServletResponse
В качестве параметра, но может принимать и возвращать многие другие типы, такие как: объекты домена, параметры пути и т. д. Аналогичным образом, контроллер не обязан возвращатьModelAndView
пример. необязательно возвращать имя представления,ResponseEntity
или POJO, который можно преобразовать в JSON.RequestMappingHandlerAdapter
гарантировано отHttpServletRequest
Параметры, требуемые методом синтаксического анализа вModelAndView
Объект возвращен. Следующий кодRequestMappingHandlerAdapter
Гарантия этой вещи:
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);if (this.argumentResolvers != null) { invocableMethod.setHandlerMethodArgumentResolvers( this.argumentResolvers);}if (this.returnValueHandlers != null) { invocableMethod.setHandlerMethodReturnValueHandlers( this.returnValueHandlers);}
скопировать код
argumentResolvers
существуетHandlerMethodArgumentResolver
В примерах разные реализации. Существует более 30 различных реализаций парсеров параметров. Они могут анализировать параметры, необходимые функции, из параметров запроса. В том числе: переменные URL-адреса, параметры тела запроса, заголовки запроса, файлы cookie, сеанс и т. д.returnValueHandlers
существуетHandlerMethodArgumentResolver
В примерах разные реализации. Существует также множество различных обработчиков возвращаемых значений для обработки результатов, возвращаемых методами, создаваяModelAndView
объект. Например: когда функцияhello()
При возврате строкиViewNameMethodReturnValueHandler
обработать это значение.login()
вернутьModelAndView
объект, Sring используетModelAndViewMethodReturnValueHandler
обработать это значение.
визуализировать вид
Теперь, когда Spring обработал HTTP-запрос, получитеModelAndView
Например, теперь ему нужно отобразить HTML-страницу в браузере пользователя. Он опирается на модель, состоящую из модели и выбранного шаблона.ModelAndView
объект. Точно так же Spring также может отображать JSON, XML или другие типы, принимаемые протоколом HTTP. Подробнее об REST вы узнаете в следующих главах. Вернитесь и посмотрите сейчасDispatcherServlet
.render()
первое использованиеLocaleResolver
Экземпляр устанавливает возвращенный Local. Сначала предположим, что в браузере правильно установлен заголовок Accetp. Использовать по умолчаниюAcceptHeaderLocaleResolver
обрабатывать. Во время рендерингаModelAndView
Может содержать имя представления или выбранного представления или ничего, если контроллер зависит от представления по умолчанию. теперь, когдаhello()
иlogin()
Метод указывает имя строки в качестве имени представления, поэтому вам нужно использовать viewResolvers, чтобы найти представление.
for (ViewResolver viewResolver : this.viewResolvers) { View view = viewResolver.resolveViewName(viewName, locale); if (view != null) { return view; }}
скопировать код
Существует много реализаций ViewResolver, здесь мы используемthymeleaf-spring5
который предоставилThymeleafViewResolver
выполнить. Анализатор знает, где искать представление, и предоставляет соответствующий экземпляр представления. вызов завершенrender()
После этого Spring завершает задачу рендеринга HTML-страницы в браузере пользователя.