Эта библиотека обеспечивает интеграцию JaxRS провайдера CXF
и моделей Spring Data Common
через автоконфигурацию Spring Boot
.
-
Автоматическое разворачивание REST сервисов (
@Path
) -
@deprecated (use feign) Автоматическое подключение REST прокси клиентов
-
Интеграция со Swagger (
@Api*
) -
Прозрачная работа с моделями Spring Data:
Page
,Pageable
,Sort
-
Обработка и возврат локализованных сообщений об ошибках клиенту в виде json
-
Логирование всех запросов / ответов (можно отключить через
jaxrs.logging-in.enabled=false
,jaxrs.logging-out.enabled=false
) -
Включение JSR303 валидаций на REST сервисах (можно отключить через
jaxrs.jsr303=false
)
Добавьте зависимость:
<dependency>
<groupId>net.n2oapp.platform</groupId>
<artifactId>n2o-platform-starter-jaxrs-server</artifactId>
</dependency>
Задаёте следующие настройки:
cxf.path=/api
cxf.jaxrs.component-scan=true
cxf.servlet.init.service-list-path=/info
Чтобы переопределить значения таймаута, задайте следующие настройки:
#Таймаут (мс) ожидания клиентом соединения с сервером. 0 - бесконечность, по умолчанию 30000мс.
cxf.jaxrs.client.connection.timeout=30000
#Таймаут (мс) ожидания клиентом ответа сервера. 0 - бесконечность, по умолчанию 60000мс.
cxf.jaxrs.client.receive.timeout=60000
Чтобы написать REST сервис, создайте интерфейс с аннотациями JaxRs:
@Path("/example")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public interface SomeRest {
...
}
Создайте класс реализующий интерфейс и добавьте его в Spring Context как bean, например, аннотацией @Controller
:
@Controller
public class SomeRestImpl implements SomeRest {
...
}
Note
|
Разделение на интерфейс и класс требуется для использования прокси клиентов. Более того, желательно чтобы интерфейсы и классы были в разных Maven модулях. |
Чтобы сервисы принимали параметры паджинации и сортировки, а возвращали одну страницу данных и общее количество записей, можно использовать классы Spring Data:
@GET
@Path("/search")
Page<SomeModel> search(@BeanParam SomeCriteria criteria);
Класс Page
возвращает список записей одной страницы (getContent
), общее количество записей (getTotalElements
)
и заданные сортировки.
Для задания сортировок и фильтров используйте классы критериев поиска (SomeCriteria
), они должны расширять класс RestCriteria
,
который в свою очередь является реализацией интерфейса Pageable
.
public class SomeCriteria extends RestCriteria {
@QueryParam("name")
private String likeName;
@QueryParam("date")
private Date dateBegin;
//getters setters
}
Чтобы проверить входные данные сервисов на валидность, удобно использовать аннотации JSR303, такие как @NotNull
, @Size
и др.
@Validated
public class SomeModel {
private Long id;
@NotBlank
private String name;
@Past
private Date date;
//getters setters
}
Для того, чтобы активировать аннотации JSR303, необходимо пометить аргументы REST метода аннотацией @Valid
:
@POST
@Path("/")
Long create(@Valid SomeModel model);
Если валидации не используются, обработчика валидаций можно отключить настройкой jaxrs.jsr303=false
.
Для возвращения всех исключений клиенту в виде json укажите настройку:
n2o.ui.message.stacktrace=true
{
"message" : "Some error",
"stackTrace":[
"...",
"\tat ...",
"\tat ...",
"\tat ...",
"\tat ..."
]
}
В поле message
попадает сообщение исключения, в поле stackTrace
весь список строк java стектрейса.
Чтобы локализовать сообщение для клиента, выбрасывайте специальное исключение UserException
:
throw new UserException("example.code")
.set("раз")
.set("два");
Подробнее о нем написано в модуле n2o-platform-i18n
.
Чтобы передать сообщение под каждое поле формы используйте JSR303 валидации.
В этом случае в json ответ добавится поле errors
:
{
"errors" : [
{
"field" : "create.arg0.name",
"message" : "не может быть пусто"
}
]
}
А http статус будет 400
.
Все запросы и ответы, и сервера, и клиента логируются по умолчанию. Для настройки параметров логирования (logging-in - входящие, logging-out - исходящие) используйте следующие настройки:
#Включить/выключить логирование. По-умолчанию true. jaxrs.logging-in.enabled = true #Размер в байтах, свыше которого сообщение будет обрезано. По-умолчанию -1, не ограничено. jaxrs.logging-in.limit = -1 #Размер в байтах, свыше которого сообщение будет записано на диск. По-умолчанию 100кб. jaxrs.logging-in.in-mem-threshold = 100 * 1024 #Форматирование сообщения jaxrs.logging-in.pretty-logging jaxrs.logging-in.log-binary jaxrs.logging-in.log-multipart
Добавьте в модуль с api
следующие зависимости:
<dependency>
<groupId>net.n2oapp.platform</groupId>
<artifactId>n2o-platform-jaxrs-commons</artifactId>
</dependency>
Для совместимости со старыми версиями платформы api
-модуль нужно собирать с указанием:
<properties>
<java.version>1.8</java.version>
</properties>
Используйте на рест сервисах аннотации @Api*
из пакета io.swagger.annotations
.
@Path("/example")
@Api("Пример документирования REST сервиса")
public interface SomeRest {
@GET
@Path("/search")
@ApiOperation("Найти что-нибудь")
@ApiResponse(code = 200, message = "Нашли что-то")
Page<SomeModel> search(@BeanParam SomeCriteria criteria);
...
}
В настройках приложения задайте путь к REST сервисам со openApi аннотациями и другие параметры:
jaxrs.openapi.enabled=true
jaxrs.openapi.title=REST сервисы для примера
jaxrs.openapi.version=1.0
jaxrs.openapi.resource-package=net.n2oapp.microservice.example
#Опционально можно указать какие протоколы (http,https,ws,wss):
jaxrs.openapi.schemes=http,https
jaxrs.openapi.auth.name=oauth2
jaxrs.openapi.auth.token-uri=http://localhost:8080/oauth/token
Note
|
Для корректной работы авторизации необходимо передать аргумент authorizations = @Authorization(value = "oauth2")
в аннотацию @Api(…) сервисов, требующих авторизации. Аргумент value должен соответствовать настройке jaxrs.swagger.auth.name .
|
Ссылка на документацию Swagger будет доступна по адресу /api/info
(cxf.path + cxf.servlet.init.service-list-path).
Для подключения REST прокси клиентов добавьте зависимость:
<dependency>
<groupId>net.n2oapp.platform</groupId>
<artifactId>n2o-platform-starter-jaxrs-client</artifactId>
</dependency>
Также вам понадобится зависимость от api
-модуля, где лежат ваши интерфейсы сервисов с аннотациями jaxrs.
Чтобы подключить REST прокси клиент, как обычный Spring бин, задайте следующие настройки:
#Включение поиска и регистрации прокси клиентов
cxf.jaxrs.client.classes-scan=true
#Пакет, в котором искать JaxRs интерфейсы
cxf.jaxrs.client.classes-scan-packages=net.n2oapp.microservice.example
#Адрес, где развернуты REST сервисы
cxf.jaxrs.client.address=http://localhost:8080/api
Добавьте аннотацию @EnableJaxRsProxyClient
в конфигурацию Spring:
import net.n2oapp.platform.jaxrs.autoconfigure.EnableJaxRsProxyClient;
...
@Configuration
@EnableJaxRsProxyClient
public class ExampleConfiguration {
...
}
В этом случае сработает автоконфигурация JaxRsClientAutoConfiguration
и создадутся прокси клиенты под каждый найденный интерфейс.
Если вам требуются сервисы развернутые на разных адресах, то нужно использовать более тонкий способ настройки с помощью аннотации @EnableJaxRsProxyClient
:
import net.n2oapp.platform.jaxrs.autoconfigure.EnableJaxRsProxyClient;
...
@Configuration
@EnableJaxRsProxyClient(
classes = SomeRest.class,
address = "${myapp.url}/example/api")
public class ExampleConfiguration {
...
}
Используйте REST прокси клиенты как обычные Spring бины:
@Service
public class ConsumerServiceImpl {
@Autowired
private SomeRest client;//REST прокси клиент
...
}
Каждый вызов метода прокси клиента будет делать http запрос к сервису.
При использовании REST прокси клиентов, исключения возникшие на сервере,
автоматически выбрасываются и на клиенте. Класс исключений: RestException
:
try {
client.create(model);
} catch (RestException e) {
e.getMessage();//Локализованное сообщение
e.getErrors();//Ошибки JSR303 валидаций
}
При этом стектрейс исключения RestException
будет содержать в себе стектрейс от сервера.
Для подключения WEB клиента, необходимо на класс конфигурации Spring повесить аннотацию @EnableJaxRsWebClient
:
@Configuration
@EnableJaxRsWebClient
public class ExampleConfiguration {
...
}
Адрес REST сервисов задаётся настройкой:
cxf.jaxrs.client.address=http://localhost:8080/api
Для выполнения запросов к REST сервисам, через аннотацию @Autowired
подключаем клиента:
@Service
public class ConsumerServiceImpl {
@Autowired
private Client client;
...
}
Методы веб-сервиса теперь можно пометить как
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) @Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
В таком случае, в зависимости от заголовков Accept и Content-Type будут приниматься и возвращаться данные в соответствующем формате.
Однако есть несколько ограничений. Самое значительное это то, что нельзя использовать примитивы в качестве body
в своих сервисах (даже обертки типа java.lang.Long
). Они обязательно должны быть обернуты в POJO объект.
И вообще желательно всегда оборачивать body запросов и ответов в POJO объекты.
Желательно также по - минимуму использовать wildcard-ы (List<?>
), вещи наподобие Map<String, Object>
и т.д.