1. Введение
1.1 Web MVC
В веб-разработке браузер обычно отправляет запрос на сервер, сервер получает запрос и передает ответ клиенту, а клиент обрабатывает его и затем отображает пользователю. Таким образом, общий сервер не может активно уведомлять клиента об обновлении содержимого, хотя некоторые технологии push могут активно уведомлять клиента.
В стандартном MVC сервер может активно передавать данные клиенту, но реальный WebMVC не может этого сделать.Если пользователь хочет обновить представление, ему нужно отправить еще один запрос.
Разработка веб-стороны началась сCGI->Servlet->JSP->Model1->Model2->Front Controller+PageControllerпроцесс:
- CGI: (Общий интерфейс шлюза) Интерфейс общедоступного шлюза используется для приема и обработки запросов веб-пользователей и, наконец, для динамической генерации ответа пользователю, но каждый запрос будет генерировать тяжеловесный процесс.
- Servlet: получать и обрабатывать запросы веб-пользователей и, наконец, динамически генерировать ответ пользователю. Но на запрос генерируется только один поток (и есть пул потоков), легковесный. Суть в том, чтобы вывести html поток в java код.
- JSP: Запуск скриптового языка, встроенного в стандартную HTML-страницу, суть заключается во встраивании java-кода в html-код. JSP в конечном итоге будут скомпилированы в сервлеты.
- Model1: Расширенная версия JSP, может рассматриваться как jsp+javabean, используйтеjsp:useBeanСтандартные действия упрощают получение/создание javabeans и инкапсуляцию параметров запроса в javabeans.
- Model2: Модель Web MVC, но контроллер использует Servlet, модель использует JavaBean, а представление использует JSP.
- Front Controller+PageController: То есть фронт-контроллер + контроллер приложения + контроллер страницы (он же action) + контекст, который тоже Web MVC, но ответственность более понятна.
1.2 Spring MVC
Комбинация Spring MVC и Spring может предоставить нам мощные функции и более лаконичный метод настройки. Ниже показан процесс обработки запросов с помощью Spring Web MVC:
На приведенной выше диаграмме мы резюмируем поток обработки запросов Spring MVC. После того, как пользователь отправит запрос:
- Запрос пользователя достигаетпередний контроллер, фронт-контроллер находит обработчик запроса на основе URLконтроллер, и делегируйте ему запрос;
- Когда контроллер получает запрос, он вызываетобъект бизнес-процессингаобработайте его и обработайте полученную модель данных, чтобы получитьModelAndView, и верните его на передний контроллер;
- Фронт-контроллер выбирает соответствующее представление для рендеринга в соответствии с возвращенным именем представления и возвращает окончательный ответ пользователю.
В сочетании с конкретными классами в среде Spring MVC мы можем получить следующую более подробную картину:
Основные классы в SpringMVC:DispatcherServlet
, согласно приведенному выше анализу, его можно рассматривать как мост промежуточного планирования. Давайте посмотрим на соответствующий код после знакомства с зависимостями Spring MVC.
существуетDispatcherServlet
Основным методом являетсяdoDispatch()
, вот его код:
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
try {
ModelAndView mv = null;
Object dispatchException = null;
try {
// 1.首先查看是否是Multipart,即是否包含要上传的文件
processedRequest = this.checkMultipart(request);
multipartRequestParsed = processedRequest != request;
// 2.根据请求和handlerMappings(列表),找到对应的HandlerExecutionChain
mappedHandler = this.getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
this.noHandlerFound(processedRequest, response);
return;
}
// 3.同样的方式,从一个HandlerAdapter的列表中获取到对应的HandlerAdapter
HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (this.logger.isDebugEnabled()) {
this.logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
return;
}
}
// 4.执行处理器相关的拦截器的预处理
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 5.由适配器执行处理器(调用处理器相应功能处理方法),注意返回了ModelAndView
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
this.applyDefaultViewName(processedRequest, mv);
// 6.执行处理器相关的拦截器的后处理
mappedHandler.applyPostHandle(processedRequest, response, mv);
} catch (Exception var20) {
dispatchException = var20;
} catch (Throwable var21) {
dispatchException = new NestedServletException("Handler dispatch failed", var21);
}
// 7.处理分发结果,其中包含了一部分异常处理,也包括根据视图名称获取视图解析器并进行渲染等等
this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
} catch (Exception var22) {
this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
} catch (Throwable var23) {
this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
}
} finally {
if (asyncManager.isConcurrentHandlingStarted()) {
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
} else if (multipartRequestParsed) {
// 清理multipart请求占用的资源
this.cleanupMultipart(processedRequest);
}
}
}
// 该方法用来处理从处理器拿到的结果,不论是异常还是得到的ModelAndView都会被处理
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {
boolean errorView = false;
// 处理异常信息
if (exception != null) {
if (exception instanceof ModelAndViewDefiningException) {
this.logger.debug("ModelAndViewDefiningException encountered", exception);
mv = ((ModelAndViewDefiningException)exception).getModelAndView();
} else {
Object handler = mappedHandler != null ? mappedHandler.getHandler() : null;
mv = this.processHandlerException(request, response, handler, exception);
errorView = mv != null;
}
}
// 解析视图并进行视图的渲染
if (mv != null && !mv.wasCleared()) {
// 实际的渲染方法,会根据ModelAndView的名称找到对应的视图解析器,并渲染得到一个视图View
this.render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
} else if (this.logger.isDebugEnabled()) {
this.logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + this.getServletName() + "': assuming HandlerAdapter completed request handling");
}
if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
if (mappedHandler != null) {
mappedHandler.triggerAfterCompletion(request, response, (Exception)null);
}
}
}
Итак, мы можем резюмировать, как работает Spriung MVC:
- Запрос, отправленный пользователем, придет первым
DispatcherServlet
, и обработанный им; -
DispatcherServlet
пройти первымHandlerMapping
Найдите соответствующий запросHandlerExecutionChain
(включает в себяHandler
процессор, несколькоHandlerInterceptor
перехватчик), с помощью этого шаблона стратегии легко добавлять новые стратегии сопоставления; - потом
DispatcherServlet
Продолжайте отправлять запросы наHandlerAdapter
,HandlerAdapter
Процессор будет упакован в виде адаптера для поддержки нескольких типов процессоров, то есть шаблона проектирования адаптера, который может легко поддерживать многие типы процессоров; -
HandlerAdapter
Метод обработки функции реального процессора будет вызываться в соответствии с результатом адаптации для завершения обработки функции и возвратаModelAndView
Объект (включая данные модели, имя логического представления); - Затем по
DispatcherServlet
согласно сModelAndView
найти соответствующийViewResolver
, и анализирует имя логического представления в определенноеView
, с помощью этого шаблона стратегии легко заменить другие технологии просмотра; - следующий
View
рендерить,View
судя по поступающимModel
Данные модели визуализируются Модель на самом деле представляет собой структуру данных карты, поэтому легко поддерживать другие технологии просмотра; - вернуть управление
DispatcherServlet
,Зависит отDispatcherServlet
Верните ответ пользователю, и на этом процесс завершится.
2. Использование Spring MVC
2.1 Конфигурация Spring MVC на основе XML
Во-первых, чтобы использовать Spring MVC, вам нужно добавить соответствующие зависимости:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
Мы проанализировали вышеDispatcherServlet
Он прописан в web.xml, нам нужно добавить следующую конфигурацию:
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<servlet>
<servlet-name>spring_is_coming</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring_is_coming</servlet-name>
<url-pattern>*.mvc</url-pattern>
</servlet-mapping>
</web-app>
Здесь мы зарегистрировалиservlet
, о котором сказано вышеDispatcherServlet
, и присвоить ему имяspring_is_coming
. Соответственно, нам также необходимо указатьservlet-mapping
.
Как показано выше, мыurl-pattern
Шаблон URL-адреса, который будет обрабатываться сервлетом, указан в*.mvc
конечный URL. load-on-startup означает, что сервлет инициализируется при запуске контейнера.
по умолчанию,DispatcherServlet
будет загружатьсяWEB-INF/[DispatcherServlet的Servlet名字]-servlet.xml
Файл конфигурации ниже. В соответствии с приведенной выше конфигурацией нам нужноWEB-INF
добавить ниже каталогspring_is_coming-servlet.xml
документ. и добавьте в файл следующий код:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"
xmlns:p="http://www.springframework.org/schema/p">
<!-- HandlerMapping -->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<!-- HandlerAdapter -->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
<!-- ViewResolver -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
<bean name="/hello.mvc" class="me.shouheng.spring.mvc.HelloController"/>
</beans>
Здесь мы объявляем несколько bean-компонентов, реализации HandlerMapping и HandlerAdapter по умолчанию. Затем мы также определяем преобразователь представленияInternalResourceViewResolver
.
Это преобразователь представлений по умолчанию, и в его свойствах мы указываем префикс и суффикс пути к загруженному файлу. На самом деле, когда мы указываем имя представления как hello, синтаксический анализатор представления загружает файл/WEB-INF/jsp/hello.jsp
.
Далее мы определяем контроллер, имя которого соответствует указанному URL-адресу. Потому что до того, как мы использовали правило отображения BeanBeanNameUrlHandlerMapping
, то есть имя компонента соответствует URL-адресу.
Затем есть код для контроллера, определенный выше:
public class HelloController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
ModelAndView mv = new ModelAndView();
// 添加模型数据 可以是任意的POJO对象
mv.addObject("message", "Hello Spring MVC!");
// 设置逻辑视图名,视图解析器会根据该名字解析到具体的视图页面
mv.setViewName("hello");
return mv;
}
}
Здесь мы использовалиModelAndView.setViewName()
Для ModelAndView указывается имя соответствующего jsp-файла, и файл с указанным именем будет записан в указанный каталог в соответствии с правилами разбора представления, которые мы настроили выше.
Запустите сервер и введите адрес в браузере:http://localhost:8080/hello.mvc, вы можете проверить это.
2.2 Использование фильтров
Мы также можем обработать запрос до того, как его обработает диспетчер, что мы и делаем с помощью фильтров. Мы можем использовать фильтры для выполнения основных задач, таких как кодирование строк. Давайте продемонстрируем использование фильтров на простом пользовательском примере:
Сначала настраиваем простой фильтр и в нем выводим некоторую информацию в консоль:
public class TheFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("init, filterConfig" + filterConfig);
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("==================================== doFilter, servletRequest: "
+ servletRequest
+ "\nservletResponse: "
+ servletResponse
+ "\nfilterChain: " + filterChain);
// 必须调用这个方法,否则请求就要在这里被拦截了
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
System.out.println("destroy");
}
}
Здесь мы хотим реализовать три метода, связанных с циклом объявления интерфейса Fileter. Затем настройте его в web.xml, и все готово:
<filter>
<filter-name>the_filter</filter-name>
<filter-class>me.shouheng.spring.mvc.TheFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>the_filter</filter-name>
<url-pattern>*.mvc</url-pattern>
</filter-mapping>
Таким образом, мы можем*.mvc
Конечный запрос обрабатывается.
2.3 Подробное объяснение DispatcherServlet
По сути, DispatcherServlet — это своего рода сервлет, то есть когда мы используем Spring MVC, нам нужно настроить этот класс, потому что это основной класс конфигурации Spring MVC. А когда мы не планируем использовать Spring MVC и хотим предоставить интерфейсы для других клиентов, нам нужно настроить другие типы сервлетов, но их конфигурация и принцип использования в сервлетах одинаковы..
Мы упоминали вышеDispatcherServlet
Значение двух параметров и использование конфигурационного файлаspring_is_coming-servlet.xml
. и на самом делеDispatcherServlet
Существует несколько способов указать файл конфигурации:
По умолчанию используется первый[DispatcherServlet的Servlet名字]-servlet.xml
Это соглашение об именах дляWEB-INF
Файл загружается в каталог, который мы использовали выше.
Второй способ — при настройке сервлета, в<servlet>
используется в этикеткахcontextClass
и укажите класс конфигурации, который должен реализоватьWebApplicationContext
Класс интерфейса. Если этот параметр не указан, используется значение по умолчаниюXmlWebApplicationContext
.
Третий способ аналогичен второму способу, который указывается при настройке сервлета, но здесьcontextConfigLocation
и используйте строку, чтобы указать местоположение контекста. Эта строка может быть разделена на несколько строк (с использованием запятых в качестве разделителей) для поддержки нескольких контекстов (в случае нескольких контекстов, если один и тот же bean-компонент определен дважды, последний имеет приоритет). Следующим образом:
<servlet>
<servlet-name>chapter2</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-servlet-config.xml</param-value>
</init-param>
</servlet>
Обычно, когда мы настраиваем контекст, мы указываем несколько контекстов, и у каждого контекста также есть своя область ответственности. В дополнение к контексту сервлета, который мы настроили ранее, при использовании Spring нам также необходимо настроить контекст всего приложения:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:spring-common-config.xml,
classpath:spring-budget-config.xml
</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
Здесь настраивается контекст всего приложения.ContextLoaderListener
Контекст приложения автоматически инициализируется при запуске контейнера. И файл конфигурации контекста приложения состоит из вышеперечисленногоcontext-param
указать. Контекст приложения обычно используется для загрузки основных классов всей программы, таких как уровень DAO и уровень службы. Таким образом, их можно использовать с любым другим веб-уровнем. Контекст конфигурации сервлета обычно используется для загрузки классов, требуемых веб-уровнем, таких как Controller, HandlerMapping, HandlerAdapter и т. д.
2.4 Перехватчики
существуетDispatcherServlet
Логика обработки этого перехватчика очень проста и понятна.DispatcherServlet
будет в основном методеdoDispatch()
Различные этапы обработки вызоваHandlerExecutionChain
Три метода (в новой версии Spring связанная логика извлекается и инкапсулируется в независимые методы).
-
HandlerExecutionChain.applyPreHandle()
Будет вContoller
Метод вызывается до его выполнения; -
HandlerExecutionChain.applyPostHandle()
Будет вContoller
После выполнения метода и до рендеринга представления он не будет вызываться, если в середине возникнет исключение; ` -
HandlerExecutionChain.triggerAfterCompletion()会在
Contoller的视图被渲染之后调用,无论是否异常,总是被调用;
Итак, что же делается в этих трех методах? Ниже приведена соответствующая логика.На самом деле, эти три метода похожи, то есть извлекают определенный перехватчик из массива и выполняют вызов обхода:
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
HandlerInterceptor[] interceptors = this.getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for(int i = 0; i < interceptors.length; this.interceptorIndex = i++) {
HandlerInterceptor interceptor = interceptors[i];
if (!interceptor.preHandle(request, response, this.handler)) {
this.triggerAfterCompletion(request, response, (Exception)null);
return false;
}
}
}
return true;
}
Поэтому логика этой части не сложная. Итак, давайте посмотрим, как использовать перехватчики в Spring MVC:
<bean name="interceptor" class="me.shouheng.spring.mvc.TestInterceptor"/>
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/hello2.mvc"/>
<ref bean="interceptor"/>
</mvc:interceptor>
</mvc:interceptors>
мы еще впередиspring_is_coming-servlet.xml
Добавьте приведенные выше строки кода, здесь мы используем собственный перехватчик, и мы даем его определение ниже:
public class TestInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("=========preHandle");
return super.preHandle(request, response, handler);
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("=========postHandle");
super.postHandle(request, response, handler, modelAndView);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("=========afterCompletion");
super.afterCompletion(request, response, handler, ex);
}
@Override
public void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("=========afterConcurrentHandlingStarted");
super.afterConcurrentHandlingStarted(request, response, handler);
}
}
Затем мы используем<mvc:interceptor>
Тег определяет соответствующий перехватчик и путь для сопоставления. Таким образом, при доступе к указанному URL-адресу определенный нами перехватчик будет вызываться при срабатывании отвечающего контроллера.
Здесь мы также объясняемHandlerInterceptorAdapter
несколько методов.
Фактически, все перехватчики в конечном итоге реализуют интерфейсы.HandlerInterceptor
, и первые три метода в приведенном выше классе фактически исходят из этого интерфейса.
существуетpreHandle()
Возвращаемое значение по умолчанию — true, что означает, что после обработки текущего перехватчика он будет продолжать обрабатываться следующим перехватчиком.
На самом деле обратитесь к вышеHandlerExecutionChain.applyPreHandle()
Метод также может видеть это.
2.5 Конфигурация на основе аннотаций
В методе конфигурации на основе аннотаций нам нужно внести некоторые изменения в приведенную выше конфигурацию. Во-первых, мы используем адаптер на основе аннотаций и механизм сопоставления. существуетspring_is_coming-servlet.xml
, мы заменяем предыдущий код на:
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
Обратите внимание, что приведенные выше две строки кода являются методами настройки после Spring 3.1, а код до 3.1 был удален в последней версии Spring и повторяться не будет.
Затем мы определяем следующий контроллер:
@Controller
public class HelloController3 {
@RequestMapping(value = "/hello3")
public ModelAndView handle() {
ModelAndView mv = new ModelAndView();
// 添加模型数据 可以是任意的POJO对象
mv.addObject("message", "Hello Spring MVC!");
// 设置逻辑视图名,视图解析器会根据该名字解析到具体的视图页面
mv.setViewName("hello3");
return mv;
}
}
Метод настройки здесь аналогичен предыдущему механизму, основанному на сопоставлении имен компонентов, за исключением того, что здесь используется метод настройки на основе аннотаций. В классе, используемом в качестве контроллера, мы хотим использовать@Controller
Аннотация, выше используется конкретный метод бизнес-уровня.@RequestMapping
Аннотируйте и укажите путь к отображению. Затем мы регистрируем bean-компонент с контекстом:
<bean class="me.shouheng.spring.mvc.HelloController3"/>
Эта базовая конфигурация завершена. Затем запустите веб-контейнер и введитеurl:http://localhost:8080/hello3
Вот и все. Также обратите внимание, что вам также необходимо изменить соответствующий путь сервлета в web.xml, если он*.mvc
затем измените его на/
.
По сути, единственная разница между данным способом настройки и предыдущим способом настройки заключается в том, что правила сопоставления изменены по сравнению с предыдущими.Имя компонента для URLконвертировано вАннотировать к URL.
В дополнение к настройке пути URL-адреса указанным выше способом мы также можем добавить различные подпути. Например:
@Controller
@RequestMapping("/user")
public class HelloController3 {
@RequestMapping(value = "/hello3")
public ModelAndView handle() {
ModelAndView mv = new ModelAndView();
// 添加模型数据 可以是任意的POJO对象
mv.addObject("message", "Hello Spring MVC!");
// 设置逻辑视图名,视图解析器会根据该名字解析到具体的视图页面
mv.setViewName("hello3");
return mv;
}
}
Согласно приведенному выше методу, он будет соответствовать: /user/hello3.
2.6 Аннотация RequestMapping
Из вышеизложенного видно, что в способе настройки с использованием аннотаций конфигурация ядра должна принадлежать@RequestMapping
аннотация. Вот определение аннотации:
public @interface RequestMapping {
String name() default "";
@AliasFor("path") String[] value() default {};
@AliasFor("value") String[] path() default {};
RequestMethod[] method() default {};
String[] params() default {};
String[] headers() default {};
String[] consumes() default {};
String[] produces() default {};
}
в:
-
name
Используется для указания имени текущего контроллера; -
value
а такжеpath
эквивалентны и используются для указания правил сопоставления URL-адреса; -
method
Используется для указания методов сопоставления, таких как POST, GET и т. д.; -
consumes
Используется для указания типа отправленного контента (Content-Type) запроса, например, application/json, text/html; -
params
: указывает, что определенные значения параметров должны быть включены в запрос, прежде чем метод сможет его обработать; -
headers
: указывает, что запрос должен содержать определенные указанные значения заголовка, чтобы этот метод мог обработать запрос; -
produces
: указывает, что запрос должен содержать определенные указанные значения заголовка, чтобы этот метод мог обработать запрос;
Ниже мы кратко опишем некоторые из этих методов.
2.6.1 значение и путь
Эффекты этих двух параметров эквивалентны, потому что они являются лишь псевдонимами друг друга. Эти два параметра используются для указания URL-адреса, который должен быть сопоставлен контроллером.Здесь мы перечисляем общие методы настройки сопоставления URL-адресов:
-
@RequestMapping(value={"/test1", "/user/create"})
: несколько путей URL соответствуют одному и тому же процессору; -
@RequestMapping(value="/users/{userId}")
: используйте заполнители URL, такие как «/users/123456» или «/users/abcd», через@PathVariable
Переменные в шаблонах шаблонов URI могут быть извлечены; -
@RequestMapping(value="/users/**")
: может соответствовать "/users/abc/abc", но "/users/123" будет предпочтительно отображаться по шаблону в 2; -
@RequestMapping(value="/product?")
: соответствует "/product1" или "/producta", но не "/product" или "/productaa"; -
@RequestMapping(value="/product*")
: может соответствовать "/productabc" или "/product", но не "/productabc/abc"; -
@RequestMapping(value="/product/*")
: матчи "/ product / abc", но не "/ productabc" -
@RequestMapping(value="/products/**/{productId}")
: может соответствовать "/products/abc/abc/123" или "/products/123"; - Подход на основе регулярных выражений.
Специальные инструкции для режима конфигурации 2, конкретный пример указания параметров в пути и получения параметров в методе:
@RequestMapping("/testPathVariable/{id}")
public String testPathVariable(@PathVariable("id") Integer id2) {
System.out.println("testPathVariable: " + id2);
return SUCCESS;
}
2.6.2 params
Этот параметр используется для ограничения обрабатываемых данных только тогда, когда запрос содержит данные с указанным именем параметра, например:
@Controller
@RequestMapping("/parameter1") //①处理器的通用映射前缀
public class RequestParameterController1 {
@RequestMapping(params="create", method=RequestMethod.GET)
public String showForm() {
....
}
@RequestMapping(params="create", method=RequestMethod.POST)
public String submit() {
....
}
}
Первый метод означает, что запрос имеет имя параметра «создать», а метод запроса — «GET» для сопоставления, например, соответствующий URL-адрес запроса.http://×××/parameter1?create»;Второй метод указывает, что в запросе есть имя параметра «создать», а метод запроса — «POST» для соответствия.
Конечно, вы можете дополнительно ограничить обработку запроса только в том случае, если указанные параметры включены в запрос и являются указанными значениями, такими как@RequestMapping(params="submitFlag=create", method=RequestMethod.GET)
: указывает, что запрос содержит «submitFlag=create», а метод запроса — «GET» для соответствия.
Также обратите внимание, что из@RequestMapping
серединаparams
Из определения видно, что это массив.Когда указано несколько значений, эти значения принадлежат отношению «и», то есть два параметра включаются одновременно.
2.6.3 consumes
потребляет используется для указания типа данных запроса, который должен быть обработан контроллером.Так называемый тип носителя относится кtext/plain
application/json
и т.п.
Они будут размещены в заголовке запроса, например.Content-Type: application/x-www-form-urlencoded
Указывает, что запрошенные данные являются данными типа "ключ-значение",
Только когда данные запроса и контроллер находятся в@RequestMapping
Указанный запрос будет обработан контроллером только в том случае, если данные, указанные в нем, совпадают.
@RequestMapping(value = "/testMethod", method = RequestMethod.POST,consumes="application/json")
public String testMethod() {
System.out.println("testMethod");
return SUCCESS;
}
Например, приведенный выше контроллер принимает только данные типа json. Когда запрашиваемые данные не json, они не будут им обрабатываться.
2.6.4 produces
производит используется для указания типа данных, которые ожидает получить текущий запрос.Этот параметр будет помещен в Accept заголовка запроса при выполнении запроса.
Только когда тип запроса Accept используется с контроллеромproduces
Только если указанный тип совпадает, он будет принят и обработан контроллером.
2.6.5 headers
Если предыдущее потребление и производство используются для указания запрошенного и желаемого типа данных, это особый случай, Затем заголовки здесь можно использовать для более гибкого указания, какая информация должна быть включена в заголовки для обработки текущим контроллером. Например:
@RequestMapping(value = "testParamsAndHeaders", params = { "username","age!=10" }, headers = { "Accept-Language=US,zh;q=0.8" })
public String testParamsAndHeaders() {
System.out.println("testParamsAndHeaders");
return SUCCESS;
}
Используется для установки первого языка в заголовке запроса, который должен быть американским.
3. Другое
3.1 Разница между перехватчиками и фильтрами
- Перехватчик основан на механизме отражения java, а фильтр основан на обратном вызове функции;
- Перехватчик не зависит от контейнера сервлета, а фильтр зависит от контейнера сервлета, потому что фильтр определяется спецификацией сервлета и используется только в веб-программах, тогда как перехватчик может использоваться в приложениях и Swing;
- В жизненном цикле Action перехватчик можно вызывать несколько раз, а фильтр можно вызывать только один раз при инициализации контейнера;
- Перехватчик может получить каждый компонент в контейнере IOC, но фильтр не может Это очень важно Внедрение службы в перехватчик может вызвать бизнес-логику;
- Фильтры предварительно обрабатываются после того, как запрос поступает в контейнер, но до того, как запрос поступает в сервлет. Конец запроса также возвращается после обработки сервлета и перед его возвратом во внешний интерфейс.
На самом деле из приведенной выше конфигурации видно, что фильтр вызывается до того, как запрос доходит до сервлета, и он принадлежит сервлету, а не спрингу.