1. Обзор
В экосистеме Java доступно множество веб-фреймворков, таких как Spring , Play и Grails . Однако ни один из них не может претендовать на то, чтобы быть полностью неизменным и объектно-ориентированным.
В этом руководстве мы рассмотрим платформу Takes и создадим простое веб-приложение, используя его общие функции, такие как маршрутизация, обработка запросов/ответов и модульное тестирование.
2. Берет
Takes — это неизменяемый веб-фреймворк Java 8, который не использует ни null
, ни общедоступные статические
методы.
Кроме того, фреймворк не поддерживает изменяемые классы, кастинг или отражение . Следовательно, это настоящая объектно-ориентированная структура.
Takes не требуют конфигурационных файлов для установки. Кроме того, он предоставляет встроенные функции, такие как ответ JSON/XML и шаблоны.
3. Настройка
Во-первых, мы добавим последнюю версию
Maven-зависимости в pom.xml
: ``
<dependency>
<groupId>org.takes</groupId>
<artifactId>takes</artifactId>
<version>1.19</version>
</dependency>
Затем создадим класс TakesHelloWorld
, реализующий интерфейс Take :
public class TakesHelloWorld implements Take {
@Override
public Response act(Request req) {
return new RsText("Hello, world!");
}
}
Интерфейс Take
обеспечивает фундаментальную функцию фреймворка. Каждый Take
служит обработчиком запроса, возвращая ответ через метод действия
.
Здесь мы использовали класс RsText
для рендеринга простого текста Hello, world!
в качестве ответа, когда делается запрос к дублю TakesHelloWorld
.
Далее мы создадим класс TakesApp
для запуска веб-приложения:
public class TakesApp {
public static void main(String... args) {
new FtBasic(new TakesHelloWorld()).start(Exit.NEVER);
}
}
Здесь мы использовали класс FtBasic
, который обеспечивает базовую реализацию интерфейса Front
для запуска веб-сервера и пересылки запроса дублю TakesHelloWorld
.
Takes реализует свой собственный веб-сервер без сохранения состояния с помощью класса ServerSocket
. По умолчанию он запускает сервер на порту 80. Однако мы можем определить порт в коде:
new FtBasic(new TakesHelloWorld(), 6060).start(Exit.NEVER);
Или мы можем передать номер порта, используя параметр командной строки –port
.
Затем давайте скомпилируем классы с помощью команды Maven: ~
~
mvn clean package
Теперь мы готовы запустить класс TakesApp
как простое Java-приложение в среде IDE.
4. Беги
Мы также можем запустить наш класс TakesApp
как отдельное приложение веб-сервера.
4.1. Командная строка Java
Во-первых, давайте скомпилируем наши классы:
javac -cp "takes.jar:." com.foreach.takes.*
Затем мы можем запустить приложение с помощью командной строки Java:
java -cp "takes.jar:." com.foreach.takes.TakesApp --port=6060
4.2. Мавен
Или мы можем использовать плагин exec-maven-
plugin , чтобы запустить его через Maven `` :
<profiles>
<profile>
<id>reload</id>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<id>start-server</id>
<phase>pre-integration-test</phase>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>com.foreach.takes.TakesApp</mainClass>
<cleanupDaemonThreads>false</cleanupDaemonThreads>
<arguments>
<argument>--port=${port}</argument>
</arguments>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
Теперь мы можем запустить наше приложение с помощью команды Maven:
mvn clean integration-test -Preload -Dport=6060
5. Маршрутизация
Фреймворк предоставляет класс TkFork
для маршрутизации запросов к разным дублям.
Например, добавим в наше приложение несколько маршрутов:
public static void main(String... args) {
new FtBasic(
new TkFork(
new FkRegex("/", new TakesHelloWorld()),
new FkRegex("/contact", new TakesContact())
), 6060
).start(Exit.NEVER);
}
Здесь мы использовали класс FkRegex
для сопоставления пути запроса.
6. Обработка запросов
Платформа предоставляет несколько классов-декораторов в пакете org.takes.rq
для обработки HTTP-запросов.
Например, мы можем использовать интерфейс RqMethod
для извлечения метода HTTP:
public class TakesHelloWorld implements Take {
@Override
public Response act(Request req) throws IOException {
String requestMethod = new RqMethod.Base(req).method();
return new RsText("Hello, world!");
}
}
Точно так же интерфейс RqHeaders
доступен для получения заголовков запроса:
Iterable<String> requestHeaders = new RqHeaders.Base(req).head();
Мы можем использовать класс RqPrint
для получения тела запроса:
String body = new RqPrint(req).printBody();
Точно так же мы можем использовать класс RqFormSmart
для доступа к параметру формы:
String username = new RqFormSmart(req).single("username");
7. Обработка ответов
Takes также предоставляет множество полезных декораторов для обработки ответа HTTP в пакете org.takes.rs
.
Декоратор ответа реализует методы head
и body
интерфейса Response .
Например, класс RsWithStatus
отображает ответ с кодом состояния:
Response resp = new RsWithStatus(200);
Вывод ответа можно проверить с помощью метода head
:
assertEquals("[HTTP/1.1 200 OK], ", resp.head().toString());
Точно так же класс RsWithType
отображает ответ с типом содержимого:
Response resp = new RsWithType(new RsEmpty(), "text/html");
Здесь класс RsEmpty
отображает пустой ответ.
Точно так же мы можем использовать класс RsWithBody
для рендеринга ответа с телом.
Итак, давайте создадим класс TakesContact
и воспользуемся обсуждаемыми декораторами для рендеринга ответа:
public class TakesContact implements Take {
@Override
public Response act(Request req) throws IOException {
return new RsWithStatus(
new RsWithType(
new RsWithBody("Contact us at https://www.foreach.com"),
"text/html"), 200);
}
}
Точно так же мы можем использовать класс RsJson
для отображения ответа JSON:
@Override
public Response act(Request req) {
JsonStructure json = Json.createObjectBuilder()
.add("id", rs.getInt("id"))
.add("user", rs.getString("user"))
.build();
return new RsJson(json);
}
8. Обработка исключений
Платформа содержит интерфейс Fallback
для обработки исключительных ситуаций. Он также предоставляет несколько реализаций для обработки резервных сценариев.
Например, давайте воспользуемся классом TkFallback
для обработки HTTP 404 и отображения сообщения пользователю:
public static void main(String... args) throws IOException, SQLException {
new FtBasic(
new TkFallback(
new TkFork(
new FkRegex("/", new TakesHelloWorld()),
// ...
),
new FbStatus(404, new RsText("Page Not Found"))), 6060
).start(Exit.NEVER);
}
Здесь мы использовали класс FbStatus
для обработки резервного варианта для определенного кода состояния.
Точно так же мы можем использовать класс FbChain
для определения комбинации запасных вариантов:
new TkFallback(
new TkFork(
// ...
),
new FbChain(
new FbStatus(404, new RsText("Page Not Found")),
new FbStatus(405, new RsText("Method Not Allowed"))
)
), 6060
).start(Exit.NEVER);
Кроме того, мы можем реализовать интерфейс Fallback
для обработки исключений:
new FbChain(
new FbStatus(404, new RsText("Page Not Found")),
new FbStatus(405, new RsText("Method Not Allowed")),
new Fallback() {
@Override
public Opt<Response> route(RqFallback req) {
return new Opt.Single<Response>(new RsText(req.throwable().getMessage()));
}
}
)
9. Шаблоны
Давайте интегрируем Apache Velocity с нашим веб-приложением Takes, чтобы обеспечить некоторые функции шаблонов.
Во- первых, мы добавим зависимость Maven от speed -engine-core :
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.2</version>
</dependency>
Затем мы будем использовать класс RsVelocity
для определения строки шаблона и параметров привязки в методе действия :
public class TakesIndex implements Take {
@Override
public Response act(Request req) throws IOException {
return new RsHtml(
new RsVelocity("${username}", new RsVelocity.Pair("username", "ForEach")));
);
}
}
Здесь мы использовали класс RsHtml
для отображения HTML-ответа.
Также мы можем использовать шаблон скорости с классом RsVelocity
:
new RsVelocity(this.getClass().getResource("/templates/index.vm"),
new RsVelocity.Pair("username", username))
);
10. Модульное тестирование
Фреймворк поддерживает модульное тестирование любого Take
, предоставляя класс RqFake
, который создает поддельный запрос:
Например, давайте напишем модульный тест для нашего класса TakesContact
, используя JUnit :
String resp = new RsPrint(new TakesContact().act(new RqFake())).printBody();
assertEquals("Contact us at https://www.foreach.com", resp);
11. Интеграционное тестирование
Мы можем протестировать все приложение с помощью JUnit и любого HTTP-клиента.
Фреймворк предоставляет класс FtRemote
, который запускает сервер на произвольном порту и обеспечивает удаленное управление выполнением Take
.
Например, давайте напишем интеграционный тест и проверим ответ класса TakesContact
:
new FtRemote(new TakesContact()).exec(
new FtRemote.Script() {
@Override
public void exec(URI home) throws IOException {
HttpClient client = HttpClientBuilder.create().build();
HttpResponse response = client.execute(new HttpGet(home));
int statusCode = response.getStatusLine().getStatusCode();
HttpEntity entity = response.getEntity();
String result = EntityUtils.toString(entity);
assertEquals(200, statusCode);
assertEquals("Contact us at https://www.foreach.com", result);
}
});
Здесь мы использовали Apache HttpClient для выполнения запросов к серверу и проверки ответа.
12. Заключение
В этом руководстве мы изучили платформу Takes, создав простое веб-приложение.
Во-первых, мы увидели быстрый способ настроить фреймворк в нашем проекте Maven и запустить наше приложение.
Затем мы рассмотрели несколько общих функций, таких как маршрутизация, обработка запросов/ответов и модульное тестирование. ``
Наконец, мы изучили поддержку модульного и интеграционного тестирования, предоставляемую фреймворком.
Как обычно, все реализации кода доступны на GitHub .