Главная » Spring » Обработка  адресов  URL в архитектуре RESTful Spring

0

Адреса URL – это первое, о чем думает большинство людей, на- чиная работать с архитектурой REST. В конце концов, все, что де- лается в архитектуре REST, делается через URL. Самое забавное, что многие адреса URL обычно делают совсем не то, для чего они предназначены.

URL – это аббревиатура от Uniform Resource Locator (унифициро-

ванный указатель ресурсов). Согласно этому названию, URL должен служить ссылкой на ресурс. Более того, все адреса URL являются также идентификаторами URI, или Uniform Resource Identifiers (уни- фицированные идентификаторы ресурсов). Если это так, тогда от конкретного URL можно ожидать, что он не только является ссыл- кой на ресурс, но является еще и его идентификатором.

Тот факт, что URL определяет местоположение ресурса, выгля- дит вполне естественным. В конце концов, в течение многих лет мы привыкли вводить адреса URL в адресную строку браузера, чтобы отыскать требуемую информацию в Интернете. Но мы не привык- ли считать, что URL является также уникальным идентификатором ресурса. Никакие два ресурса не могут размещаться по одному и тому же адресу URL, поэтому URL можно считать средством иден- тификации ресурса1.

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

1 Хоть это и выходит за рамки книги, тем не менее семантика Веб исполь- зует идентификационную природу адресов URL для создания связанной сети ссылок на ресурсы.

Например, на рис. 12.1 изображен пример URL, обрабатываемого методом  displaySpittle()   контроллера  DisplaySpittleController.

Рис. 12.1. URL, противоречащий архитектуре REST, ориентированный на выполнение операции,

а также не ссылающийся и не идентифицирующий ресурс

Как показано на рис. 12.1, этот URL не ссылается и не иденти- фицирует какой-либо ресурс. Он требует, чтобы сервер отобразил объект Spittle. Единственный фрагмент URL, который хоть что-то идентифицирует, – это параметр запроса id. Базовая часть URL – глагол, выражающий требование. Все это говорит, что данный URL противоречит архитектуре REST.

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

Характеристики URL, соответствующих архитектуре REST

В противоположность адресам URL, противоречащим архитекту- ре REST, адреса URL, соответствующие ей, целиком и полностью признают, что протокол HTTP предназначен для передачи ресурсов. Например, на рис. 12.2 показано, как мог бы выглядеть предыдущий URL после приведения его в согласие с архитектурой REST.

Единственное, что остается неясным в этом URL, – что он делает. Это обусловлено тем, что он ничего не делает. Он идентифицирует

Рис. 12.2. URL, указывающий на ресурс и идентифицирующий его

ресурс. В частности, он ссылается на ресурс, представляющий объ- ект Spittle. Что будет делаться с этим ресурсом, это уже отдельная тема, зависящая от типа HTTP-запроса (о чем подробнее рассказы- вается в разделе 12.2.3).

Этот URL не только ссылается на ресурс, но и уникально иденти- фицирует его. Он в равной степени является адресом URL и иденти- фикатором URI. Для полной идентификации ресурса используется весь URL, а не параметр запроса.

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

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

# http://localhost:8080 – определяет доменное имя и порт. Хотя

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

# http://localhost:8080/Spitter – определяет контекст сервлета

приложения. Данный URL является более специализирован- ным – он определяет приложение, выполняющееся на сервере.

# http://localhost:8080/Spitter/spittles   –   определяет   ресурс,

представляющий список объектов Spittle внутри приложения Spitter.

#  http://localhost:8080/Spitter/spittles/123 – наиболее специали-

зированный URL, определяющий конкретный ресурс Spittle. Самая интересная особенность адресов URL в стиле RESTful за-

ключается в том, что пути в них являются параметризованными.

В то время как URL, противоречащие архитектуре REST, несут входные данные в виде параметров запроса, адреса URL в стиле RESTful несут эти же данные внутри пути в URL. Для обработки запросов с такими URL необходимо иметь возможность, позволяю- щую методам-обработчикам контроллеров извлекать входные дан- ные из пути URL.

Встраивание параметров в адреса URL

Для поддержки параметризованных путей в адресах URL в вер- сию Spring 3.0 была добавлена новая аннотация @PathVariable. Чтобы познакомиться с ней в действии, рассмотрим класс SpittleController, новый контроллер Spring MVC, реализующий подход, ориентиро- ванный на ресурсы, и обрабатывающий запросы на получение объ- ектов  Spittle.

Листинг 12.2. SpittleController – контроллер, поддерживающий архитектуру REST

package  com.habuma.spitter.mvc; import    javax.inject.Inject; import  javax.validation.Valid;

import    org.springframework.stereotype.Controller; import org.springframework.ui.Model;

import       org.springframework.web.bind.annotation.PathVariable; import    org.springframework.web.bind.annotation.RequestMapping; import    org.springframework.web.bind.annotation.RequestMethod; import      com.habuma.spitter.domain.Spittle;

import com.habuma.spitter.service.SpitterService;

@Controller

@RequestMapping("/spittles")  // Обрабатывает запросы к URL /spittles public  class  SpittleController  {

private SpitterService spitterService;

@Inject

public   SpittleController(SpitterService   spitterService)   { this.spitterService   =   spitterService;

}

@RequestMapping(value="/{id}",  //  Используется  переменная-заполнитель method=RequestMethod.GET)

public String getSpittle(@PathVariable("id") long id,

Model model) { model.addAttribute(spitterService.getSpittleById(id)); return     "spittles/view";

}

}

Как показано в листинге 12.1, класс SpittleController  снабжен ан- нотацией @RequestMapping, указывающей, что данный контроллер бу-

дет обрабатывать запросы на получение ресурсов Spittle – запросов с адресами URL, начинающимися со строки /spittles.

Пока существует только один метод-обработчик, getSpittle(). Ан- нотация @RequestMapping, которой отмечен этот метод, в паре с анно- тацией @RequestMapping на уровне класса превращает его в обработчик запросов типа GET с адресами URL вида /spittles/{id}.

Возможно, вас заинтересовали странные фигурные скобки в шаб- лоне URL. Конструкция {id} – это переменная-заполнитель, посред- ством которой изменяющаяся часть URL передается методу. Она соответствует аннотации @PathVariable, которой отмечен параметр id метода.

Таким образом, если приложение получит запрос GET с URL http://localhost:8080/Spitter/spittles/123, метод getSpittle() будет вызван со значением 123 в параметре id. Затем объект отыщет со- ответствующий параметру объект Spittle и поместит его в модель.

Возможно, вы заметили, что имя id трижды используется в сиг- натуре метода. Оно используется не только как имя переменой-за- полнителя в шаблоне URL и как параметр аннотации @PathVariable, оно также используется как имя фактического параметра метода. В данном случае это всего лишь совпадение. Однако если имя пара- метра метода совпадает с именем переменной-заполнителя в шабло- не URL (я не вижу причин, препятствующих такому совпадению), тогда можно воспользоваться преимуществом наличия принятых соглашений и опустить параметр аннотации @PathVariable. Например:

@RequestMapping(value="/{id}", method=RequestMethod.GET)

public String getSpittle(@PathVariable long id, Model model) { model.addAttribute(spitterService.getSpittleById(id)); return     "spittles/view";

}

Когда аннотация @PathVariable указывается без параметра, ее пара- метром становится имя аннотированного параметра метода1.

Независимо от того, как будет определяться имя переменной-за- полнителя, явно или неявно, аннотация @PathVariable позволяет пи-

1 Предполагается, что класс контроллера скомпилирован с сохранением от- ладочной информации. В противном случае имя параметра метода будет недоступно во время выполнения и аннотация @PathVariable не сможет определить имя соответствующей переменной-заполнителя в шаблоне URL.

сать методы контроллеров для обработки запросов, в которых адреса URL идентифицируют ресурс, а не описывают некоторую операцию. С другой стороны, запросы в стиле RESTful – это методы HTTP, кото- рые применяются к адресам URL. Посмотрим, как методы HTTP мо- гут играть роль глаголов, описывающих действия, в запросах REST.

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

По теме:

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