Вступление
Я создал небольшой пример запуска отдельного Java-приложения, которое обслуживает статический HTML, JavaScript, CSS-контент, а также публикует веб-сервис REST. В примере используются Джерси и Причал. Этот пример, вероятно, заслуживает нескольких публикаций, чтобы дать достаточно времени, чтобы объяснить, как эти части сочетаются друг с другом, поэтому я начну с основных частей Java, которые составляют приложение JAX-RS.
Пару лет назад, когда я работал над некоторыми слайдами, чтобы преподавать класс Java (в основном Java EE и Spring), я создал веб-сервис REST с использованием Spring WebMVC. Я написал несколько постов (начиная здесь ) о том, как это работает.
Недавно я снова преподавал этот класс, обновляя до более поздних версий Java и более поздних версий библиотек. Когда я добрался до класса Spring WebMVC, я хотел научить его, потому что я все еще думаю, что это хороший выбор для приложения, использующего среду Spring (потому что оно интегрируется с внедрением зависимостей Spring). Но, конечно, теперь у нас есть Java API для RESTful Web Services (JAX-RS) в качестве опции.
Поэтому я адаптировал предыдущий пример к JAX-RS. К счастью, некоторые из маленьких хитростей, используемых с приложением Spring WebMVC, все еще применяются.
Класс провайдера
JAX-RS делит работу веб-службы REST на один или несколько классов провайдеров. Каждый класс провайдера обрабатывает набор путей во всем приложении, и каждый класс провайдера может иметь несколько методов, которые обрабатывают определенные пути и методы HTTP.
Классы провайдеров — это простые старые объекты Java (POJO), использующие аннотации для указания параметров JAX-RS. Вот класс провайдера для этого приложения.
@Path("/calculator")
public class Calculator {
@GET
@Path("/calc/{op}/{left}/{right}")
public Calculation calculate(@PathParam("op") String op, @PathParam("left") Integer left,
@PathParam("right") Integer right) {
Calculation result = new Calculation();
result.setOperation(op);
result.setLeft(left);
result.setRight(right);
return doCalc(result);
}
@POST
@Path("/calc2")
public Calculation calculate(Calculation calc) {
return doCalc(calc);
}
private Calculation doCalc(Calculation c) {
String op = c.getOperation();
int left = c.getLeft();
int right = c.getRight();
if (op.equalsIgnoreCase("subtract")) {
c.setResult(left - right);
} else if (op.equalsIgnoreCase("multiply")) {
c.setResult(left * right);
} else if (op.equalsIgnoreCase("divide")) {
c.setResult(left / right);
} else {
c.setResult(left + right);
}
return c;
}
}
В этом примере проиллюстрированы методы как HTTP, так GET
и POST
HTTP, а также передача параметров либо через компоненты URL, либо через тело запроса.
Ключевые аннотации, используемые выше:
@Path
: Добавляет компонент пути для сопоставления входящего URL. Компоненты пути являются кумулятивными, поэтому аннотация класса и аннотация метода работают вместе. Путь может содержать шаблоны, используемые для предоставления параметров.@GET
: Указывает метод, который обрабатывает запросы HTTP GET.@POST
: Указывает метод, который обрабатывает запросы HTTP POST.@PathParam
: Связывает шаблон в URL с параметром метода.
В этом примере не показано @QueryParam
, что работает аналогично, @PathParam
но вместо этого соответствует вводу формы (либо закодированному в URL-адресе в виде ?name1=value1&name2=value2
пар, либо в name=value
списке с переносами строк в теле запроса).
Для тех, кто знаком с Spring WebMVC, обратите внимание, что аннотации довольно похожи. Также обратите внимание, что некоторые аннотации, такие как @RequestBody
и @ResponseBody
для указания того, что тело запроса должно быть преобразовано в параметр, или возвращенный объект Java должен стать телом ответа, предполагаются, а не указываются.
Приложение JAX-RS
Класс приложения JAX-RS позволяет, помимо прочего, настраивать, какие пакеты проверяются на наличие поставщиков.
public class CalculatorApp extends ResourceConfig {
public CalculatorApp() {
packages("org.anvard.jaxrs");
}
}
ResourceConfig
класс Джерси, который выходит за пределы стандартного Application
класса JAX-RS и обеспечивает сканирование пакетов и другие вспомогательные приложения. Это также обеспечивает реализацию стандарта getClasses()
и getSingletons()
методов, которые мы должны были бы предоставить сами.
web.xml
Хотя Servlet 3.0 позволяет развертывать приложения без использования дескриптора развертывания, он облегчает соединение Jetty с Джерси при использовании плагина Maven Jetty.
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<servlet>
<servlet-name>Calculator</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>org.anvard.jaxrs.server.CalculatorApp</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>Calculator</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
</web-app>
Эта конфигурация использует сервлет, предоставленный Джерси, для делегирования классу приложения JAX-RS, который мы определили ранее. Это также позволяет нам указать первый компонент пути для служб JAX-RS (чтобы они отличались от статических файлов, которые мы также хотим обслуживать).
Развертывание и запуск
Файл Maven POM обрабатывает создание JAR (для автономного приложения, обсуждаемого в следующем посте) и WAR (для развертывания в контейнере сервлетов). Он также включает в себя плагин Maven Jetty, позволяющий запускать приложение из командной строки с помощью mvn jetty:run
.
Требования к клиенту
Пример включает в себя как JavaScript, так и Java-клиенты, о которых я расскажу в другом посте. Разумеется, можно использовать любой веб-клиент, но обратите внимание, что эта служба REST тщательно реагирует на запросы клиентов.
Мы перечисляем зависимость от плагина Джерси для Джексона, чтобы мы могли перемещаться между Java и JSON. Однако клиент должен указать заголовок Accept: application/json
; в противном случае сервер по умолчанию использует XML. Кроме того, при подаче данных на сервер для запроса POST клиент также должен указать Content-Type: application/json
заголовок.
Следующие шаги
В следующем посте будет подробно рассказано о запуске службы в обычном приложении Java с использованием встроенного сервера Jetty.