«1. Обзор

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

Так же, как и Spring — он сильно зависит от аннотаций и отлично работает с Hibernate.

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

Итак, давайте изучим различные компоненты VRaptor и создадим пример проекта.

2. Зависимости и установка Maven

Один из быстрых способов приступить к работе — загрузить дистрибутив vraptor-blank-project-distribution из официального репозитория.

Пустой проект — это всего лишь скелет, который можно превратить в полноценное веб-приложение.

Скачав и разархивировав проект, давайте переименуем директорию в vraptor (или любое другое имя).

Каталог должен содержать:

    src/pom.xml и README.md

Проект основан на Maven и поставляется с плагином tomcat7 Maven, который предоставляет контейнер сервлетов для запуска приложения.

Он также поставляется с IndexController по умолчанию, который имеет только один метод – index().

По умолчанию представление, отображаемое этим методом, находится в файле webapp/WEB-INF/jsp/index/index.jsp — это соответствует соглашению WEB-INF/jsp/имя_контроллера/имя_метода.

Чтобы запустить сервер, мы выполним команду mvn tomcat7:run из корня проекта.

В случае успеха, если мы посетим http://localhost:8080, браузер отобразит «Это работает!! VRaptor!».

Если мы столкнулись с «java.lang.LinkageError: нарушение ограничения загрузчика», то мы должны изменить следующие зависимости в pom.xml:

<dependency>
    <groupId>org.jboss.weld.servlet</groupId>
    <artifactId>weld-servlet-core</artifactId>
    <version>2.1.2.Final</version>
    <exclusions>
        <exclusion>
	    <groupId>org.jboss.spec.javax.el</groupId>
	    <artifactId>jboss-el-api_3.0_spec</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.jboss.weld</groupId>
    <artifactId>weld-core-impl</artifactId>
    <version>2.1.2.Final</version>
    <exclusions>
       <exclusion>
          <groupId>org.jboss.spec.javax.el</groupId>
  	  <artifactId>jboss-el-api_3.0_spec</artifactId>
       </exclusion>
    </exclusions>
</dependency>

Виновником является включенный el-api в Weld-Servlet-Core и Weld-Core-Impl с областью компиляции; это приводит к конфликту зависимостей.

Следующие зависимости потребуются вдоль линии, поэтому давайте включим их в pom.xml:

<dependency>
    <groupId>br.com.caelum.vraptor</groupId>
    <artifactId>vraptor-freemarker</artifactId>
    <version>4.1.0-RC3</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.8-dmr</version>
</dependency>

<dependency>
    <groupId>org.freemarker</groupId>
    <artifactId>freemarker</artifactId>
    <version>2.3.27-incubating</version>
</dependency>

Последняя версия артефактов vraptor-freemarker, mysql-connector-java и freemarker может быть можно найти в Maven Central.

Теперь, когда все готово, давайте создадим простой блог-сайт.

3. Поддержка Hibernate

VRaptor предоставляет различные плагины для взаимодействия с базами данных, один из них vraptor-hibernate, который работает с Hibernate 4.

Плагин делает компонент Hibernate SessionFactory доступным во время выполнения через CDI.

После установки плагина нам понадобится стандартный файл конфигурации Hibernate — пример можно найти в репозитории.

VRaptor использует технику под названием Producers, чтобы сделать объекты доступными для управления DI. Подробнее об этом здесь.

4. Определение веб-маршрутов в VRaptor

В VRaptor определения маршрутов находятся в контроллерах, которые представляют собой просто аннотированные @Controller Java-объекты — точно так же, как в Spring.

Аннотации @Path используются для сопоставления пути запроса с конкретным контроллером, а аннотации @Get, @Post, @Put, @Delete и @Patch используются для указания типов HTTP-запросов.

Конфигурация сопоставления маршрутов похожа на JAX-RS, но официально не реализует стандарт.

@Get("/posts/{id}")

Кроме того, при определении пути можно указать переменную пути в фигурных скобках:

@Get("/posts/{id}")
public void view(int id) {
    // ...
}

Доступ к значению id можно получить внутри метода контроллера:

Когда форма отправленные на определенный маршрут, VRaptor может автоматически заполнить объект отправленными данными формы.

Давайте посмотрим на это в действии в следующем разделе статьи.

5. Представления и механизм шаблонов

По умолчанию представления могут быть реализованы с использованием JSP. Однако можно использовать и другие шаблонизаторы — в этой статье мы будем работать с Freemarker.

<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>VRaptor Blank Project</title>
</head>
<body>
It works!! ${variable}
</body>
</html>

Давайте начнем с создания index.ftl и сохранения его в каталоге представления по умолчанию (src/main/resources/templates):

@Path("/")
public void index() {
    result.include("variable", "VRaptor!");
    result.use(FreemarkerView.class).withTemplate("index");
}

Теперь мы можем использовать определенное представление с классом FreemarkerView для рендеринга представления:

Объект Result содержит состояние модели – у него есть методы для перенаправления на другую страницу, URL или метод контроллера; его можно ввести в контроллер с помощью CDI.

«В нашем примере переменная разрешается Freemarker. Таким образом, заполнитель ${variable} в index.ftl заменяется на «VRaptor!».

Здесь задокументировано более продвинутое использование.

6. Пример обработки отправки формы

@Post("/post/add")
public void add(Post post) {
    post.setAuthor(userInfo.getUser());
    validator.validate(post);
    if(validator.hasErrors()) {
        result.include("errors", validator.getErrors());
    }
    validator.onErrorRedirectTo(this).addForm();
  
    Object id = postDao.add(post);
  
    if(Objects.nonNull(id)) {
       result.include("status", "Post Added Successfully");
         result.redirectTo(IndexController.class).index();
    } else {
        result.include(
          "error", "There was an error creating the post. Try Again");
        result.redirectTo(this).addForm();
    }
}

Давайте посмотрим, как мы можем обрабатывать отправку формы с проверкой:

Объект Post сначала проверяется с помощью проверки Java-бина, а затем сохраняется в базе данных с помощью postDao.add( ).

Поля объекта Post заполняются автоматически из значений отправленных данных формы, которые соответствуют полям ввода формы в файле представления.

Обратите внимание, что имя поля ввода должно начинаться с имени объекта в нижнем регистре.

<input type="text" class="form-control" placeholder="Title" 
  id="title" name="post.title" required />

<textarea rows="10" class="form-control" placeholder="Post" 
  id="post" name="post.post" required></textarea>

Например, представление, отвечающее за добавление новой записи, имеет поля ввода: post.title и post.post, которые соответствуют полям title и post в Post.java соответственно:

Полный add.ftl файл можно найти в исходном коде.

if(validator.hasErrors()) {
    result.include("errors", validator.getErrors());
}
validator.onErrorRedirectTo(this).addForm();

Если есть ошибка при отправке формы, сообщение об ошибке включается и пользователь перенаправляется к тому же методу add():

7. Заключение

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

Документация содержит более подробную информацию о фреймворке, а также о доступных плагинах.