Главная » Spring » Договоренность о представлении ресурса Spring

0

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

В веб-приложениях, взаимодействующих с человеком, обычно всегда выбирается представление, отображающее результаты в фор- мате HTML. Выбор представления осуществляется по одному пара- метру – имени представления.

Что касается преобразования имен представлений в фактические представления отображения ресурсов, в операцию выбора добав- ляется еще один параметр. Представление не только должно соот- ветствовать имени, но и отображать данные в формате, требуемом клиенту. Если клиент требует представить ресурс в формате XML, то представление, возвращающее данные в формате HTML, не го- дится, даже если оно соответствует указанному имени.

В состав Spring входит класс ContentNegotiatingViewResolver – спе- циализированный арбитр представлений, который при выборе пред- ставления учитывает также, в каком формате клиент желает полу- чить ресурс. Подобно любым другим арбитрам представлений, он настраивается в виде компонента в контексте приложения Spring, как показано в листинге 12.4.

Листинг 12.4. ContentNegotiatingViewResolver выбирает наиболее подходящее представление

<bean     class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">

<property name="mediaTypes">

<map>

<entry  key="json"  value="application/json"  />

<entry key="xml" value="text/xml" />

<entry key="htm" value="text/html" />

</map>

</property>

<property  name="defaultContentType"  value="text/html"  />

</bean>

Чтобы понять принцип действия арбитра ContentNegotiatingView- Resolver, необходимо знать, что договоренность о формате ресурса выполняется в два этапа:

1.   Определяется тип возвращаемых данных.

2.   Отыскивается представление для данного типа.

Рассмотрим подробнее каждый из этих этапов, чтобы лучше понять  механизм  действия  ContentNegotiatingViewResolver.  Начнем с определения типа возвращаемых данных.

Определение запрошенного типа возвращаемых данных

Первый этап в процессе определения формата представления ресурса заключается в выяснении требований клиента. На первый взгляд кажется, что в этом нет ничего сложного, поскольку клиент может явно указать требуемый формат в заголовке Accept запроса.

К сожалению, заголовок Accept не является достаточно надеж- ным для этого. Если клиент пользуется веб-браузером, нет никакой гарантии, что клиент желает получить именно то, что браузер от- правляет в заголовке Accept. Обычно веб-браузеры указывают фор- маты, доступные для восприятия человеком (такие как text/html) и

не предоставляют возможности указать другой формат (за исклю- чением случаев использования расширений, предназначенных для разработчиков).

Арбитр ContentNegotiatingViewResolver учитывает содержимое заго- ловка Accept и выбирает то или иное представление в соответствии с ним, но только после того, как попытается определить расширение файла в URL. Если в конце URL присутствует расширение файла, будет выполнена попытка отыскать соответствующий ему элемент в свойстве mediaTypes. Свойство mediaTypes – это отображение, ключа- ми в котором являются расширения имен файлов, а значениями – типы содержимого. При обнаружении совпадения используется со- ответствующий тип содержимого. При таком подходе расширения имен файлов пользуются более высоким приоритетом по отноше- нию к заголовку Accept.

Если имеющееся расширение не соответствует ни одному под- держиваемому типу содержимого, тогда в учет принимается содер- жимое заголовка Accept. Но если запрос не имеет заголовка Accept, тогда используется тип содержимого,  определяемый свойством defaultContentType.

В качестве примера предположим, что арбитр ContentNegotiating- ViewResolver настроен, как показано в листинге 12.4, и ему предла- гается определить тип содержимого по запросу, содержащему рас- ширение файла .json. В данном случае этому расширению соответ- ствует элемент с ключом json в свойстве mediaTypes. Поэтому будет выбран тип содержимого application/json.

А теперь допустим, что запрос содержит расширение .huh. Этому расширению не соответствует ни один элемент в свойстве mediaTypes. В отсутствие совпадения ContentNegotiatingViewResolver попытается определить тип содержимого по заголовку Accept в запросе. За- просы, отправляемые браузером Firefox, содержат типы text/html, application/xhtml+xml, application /xml и */*. Если запрос не содержит заголовка Accept, тогда будет выбран тип text/html, согласно значе- нию свойства defaultContentType.

Изменение порядка определения типа содержимого

Порядок определения типа содержимого, описанный выше, соот- ветствует стратегии по умолчанию. Однако существуют дополни- тельные возможности, позволяющие влиять на этот порядок:

# присвоив свойству favorPathExtension значение false, можно за- ставить ContentNegotiatingViewResolver игнорировать расширение файла в URL;

# добавив фреймворк Java Activation Framework (JAF) в библио-

теку классов (classpath), можно заставить ContentNegotiating- ViewResolver обращаться к JAF за помощью в определении типа содержимого по расширению имени файла, если в свойстве mediaTypes не будет найден соответствующий элемент;

# если присвоить свойству favorParameter значение true, тип со-

держимого будет определяться путем сопоставления парамет- ра format в запросе (если присутствует) с элементами в свой- стве mediaTypes (кроме того, имя параметра можно изменить, определив свойство parameterName);

# присвоив свойству ignoreAcceptHeader значение true, можно ис-

ключить из рассмотрения заголовок Accept.

Например, допустим, что свойству favorParameter было присвоено значение true:

<property  name="favorParameter"  value="true"  />

Теперь запросы, в которых URL не содержит расширения имени файла, будут соответствовать типу содержимого application/json, ес- ли URL включает параметр запроса format со значением json.

После того как ContentNegotiatingViewResolver определит тип содер- жимого, можно приступать к поиску представления, которое сможет отобразить данные в содержимое этого типа.

Поиск представления

В отличие от других арбитров представлений, ContentNegotiating- ViewResolver не определяет представление непосредственно, а предо- ставляет другим арбитрам представлений возможность выбрать наиболее подходящее представление, соответствующее требованиям клиента. Если не оговаривается иное, он будет использовать любые арбитры представлений, имеющиеся в контексте приложения. Но имеется возможность явно перечислить арбитры представлений, ко- торые следует задействовать, перечислив их в свойстве viewResolvers.

ContentNegotiatingViewResolver  опросит все арбитры представлений,

предложив им определить представление по логическому имени, и поместит полученные представления в список кандидатов. Кроме

того, если определено свойство defaultView, представление, указанное в нем, также будет добавлено в конец списка.

После составления списка кандидатов ContentNegotiatingViewResol-

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

Если представление определить не удалось, ContentNegotiatingView- Resolver вернет пустую ссылку (null). Или, если свойство useNotAccep- tableStatusCode имеет значение true, будет возвращено представление с кодом состояния HTTP 406 (Not Acceptable).

Прием определения договоренности о формате представления ре- сурса прекрасно вписывается в схему, которая использовалась при разработке веб-интерфейса нашего приложения в главе 8. Он по- зволяет создавать новые представления вдобавок к уже имеющимся HTML-представлениям.

При определении ресурсов в стиле RESTful, потребляемых про- граммными клиентами, возможно, имеет смысл создать контроллер, который будет осведомлен, что данные потребляются как ресурс другим приложением. В этом случае можно задействовать инстру- менты преобразования HTTP-сообщений и аннотацию @ResponseBody.

Источник:   Уоллс К., Spring в действии. – М.: ДМК Пресс, 2013. – 752 с.: ил.

По теме:

  • Комментарии