Статьи

Java EE 7 с Angular JS — Часть 1

Сегодняшний пост покажет вам, как создать очень простое приложение, используя Java EE 7 и Angular JS . Прежде чем идти туда, позвольте мне рассказать вам короткую историю:

Я должен признаться, что я никогда не был большим поклонником Javascript, но я все еще помню первый раз, когда я использовал его. Я точно не помню год, но, вероятно, около середины 90-х годов. У меня была страница с 3 фреймами (да, фреймы! Помните те? Очень популярная в то время), и я хотел перезагрузить 2 фрейма, когда щелкнул ссылку на 3-м фрейме. В то время Javascript использовался для создания каких-то необычных вещей на веб-страницах, не у каждого браузера была поддержка Javascript, а некоторые даже требовали, чтобы вы включили его. Перенесемся в сегодняшнюю обстановку и изменили ландшафт. Javascript — это полный стек разработки, и вы можете разрабатывать целые приложения, написанные только на Javascript. К сожалению для меня, иногда я все еще думаю, что вернулся в 90-е и не уделяю должного внимания Javascript, так что это моя попытка лучше узнать Javascript.

Почему Java EE 7?

Ну, я люблю Java, и новая версия Java EE довольно хороша. Менее многословный и очень быстрый, используя Wildfly или Glassfish . Он предоставляет вам большой набор спецификаций для удовлетворения ваших потребностей, и это стандарт в мире Java.

Почему Angular JS?

Я, вероятно, следую за большой шумихой вокруг Angular здесь. Поскольку у меня нет большого опыта работы с Javascript, я не очень хорошо знаю предложения, поэтому я просто следую советам некоторых друзей и также заметил большое признание Angular в последнем Devoxx. Каждая комната с разговором на английском была переполнена, поэтому я хотел попробовать и выяснить это для себя.

Приложение

Для приложения это простой список с нумерацией страниц и службой REST, которая передает данные списка. Каждый раз, когда я запускаю новый корпоративный проект, обычно первое, что мы кодируем: создаем таблицу, храним некоторые данные и перечисляем некоторые случайные данные, так что я думаю, что это уместно.

Настройка

Кодекс (наконец-то!)

Бэкэнд — Java EE 7

Начиная с серверной части, давайте определим очень простой класс Entity (некоторый код опущен для простоты):

Person.java

01
02
03
04
05
06
07
08
09
10
@Entity
public class Person {
    @Id
    private Long id;
 
    private String name;
 
    private String description;
 
}

Если вы не знакомы со спецификацией Java EE JPA, это позволит смоделировать класс объекта в таблицу базы данных с помощью аннотации @Entity для подключения к таблице базы данных с тем же именем и аннотации @Id для идентификации первичной таблицы. ключ.

Далее следует persistence.xml :

persistence.xml

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1"
             xmlns="http://xmlns.jcp.org/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    <persistence-unit name="myPU" transaction-type="JTA">
        <properties>
            <property name="javax.persistence.schema-generation.database.action" value="drop-and-create"/>
            <property name="javax.persistence.schema-generation.create-source" value="script"/>
            <property name="javax.persistence.schema-generation.drop-source" value="script"/>
            <property name="javax.persistence.schema-generation.create-script-source" value="sql/create.sql"/>
            <property name="javax.persistence.schema-generation.drop-script-source" value="sql/drop.sql"/>
            <property name="javax.persistence.sql-load-script-source" value="sql/load.sql"/>
        </properties>
    </persistence-unit>
</persistence>

Две из моих любимых новых функций в Java EE 7: теперь вы можете запускать sql стандартным способом, используя свойства javax.persistence.schema-generation.* И он также привязывает вас к источнику данных по умолчанию, если вы его не предоставите. Так что для этого случая он будет использовать внутреннюю базу данных Wildfly H2 для нашего приложения.

Наконец, для предоставления списка данных нам нужно запросить базу данных и представить ее как службу REST:

PersonResource.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
@Stateless
@ApplicationPath("/resources")
@Path("persons")
public class PersonResource extends Application {
    @PersistenceContext
    private EntityManager entityManager;
 
    private Integer countPersons() {
        Query query = entityManager.createQuery("SELECT COUNT(p.id) FROM Person p");
        return ((Long) query.getSingleResult()).intValue();
    }
 
    @SuppressWarnings("unchecked")
    private List<Person> findPersons(int startPosition, int maxResults, String sortFields, String sortDirections) {
        Query query = entityManager.createQuery("SELECT p FROM Person p ORDER BY " + sortFields + " " + sortDirections);
        query.setFirstResult(startPosition);
        query.setMaxResults(maxResults);
        return query.getResultList();
    }
 
    public PaginatedListWrapper<Person> findPersons(PaginatedListWrapper<Person> wrapper) {
        wrapper.setTotalResults(countPersons());
        int start = (wrapper.getCurrentPage() - 1) * wrapper.getPageSize();
        wrapper.setList(findPersons(start,
                                    wrapper.getPageSize(),
                                    wrapper.getSortFields(),
                                    wrapper.getSortDirections()));
        return wrapper;
    }
 
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public PaginatedListWrapper<Person> listPersons(@DefaultValue("1")
                                                    @QueryParam("page")
                                                    Integer page,
                                                    @DefaultValue("id")
                                                    @QueryParam("sortFields")
                                                    String sortFields,
                                                    @DefaultValue("asc")
                                                    @QueryParam("sortDirections")
                                                    String sortDirections) {
        PaginatedListWrapper<Person> paginatedListWrapper = new PaginatedListWrapper<>();
        paginatedListWrapper.setCurrentPage(page);
        paginatedListWrapper.setSortFields(sortFields);
        paginatedListWrapper.setSortDirections(sortDirections);
        paginatedListWrapper.setPageSize(5);
        return findPersons(paginatedListWrapper);
    }
}

Код точно такой же, как обычный Java POJO, но использует аннотации Java EE для улучшения поведения. @ApplicationPath("/resources") и @Path("persons") будут предоставлять службу REST по URL-адресу yourdomain/resources/persons @GET , @GET обозначает логику, которая будет вызываться методом http GET, и @Produces(MediaType.APPLICATION_JSON) форматирует ответ REST в формате JSON. Довольно круто только с несколькими аннотациями.

Чтобы облегчить обмен необходимой информацией для разбитого на страницы списка, я также создал следующий класс-оболочку:

PaginatedListWrapper.java

1
2
3
4
5
6
7
8
9
public class PaginatedListWrapper<T> {
    private Integer currentPage;
    private Integer pageSize;
    private Integer totalResults;
 
    private String sortFields;
    private String sortDirections;
    private List<T> list;
}

И мы закончили с бэкэндом.

UI — угловой JS

Для отображения данных мы будем использовать Angular JS. Angular расширяет традиционный HTML дополнительными настраиваемыми атрибутами тегов для привязки данных, представленных в переменных Javascript, следуя подходу MVC. Итак, давайте посмотрим на нашу HTML-страницу:

index.html

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<!DOCTYPE html>
<!-- Declares the root element that allows behaviour to be modified through Angular custom HTML tags. -->
<html ng-app="persons">
<head>
    <title></title>
    <script src="lib/angular.min.js"></script>
    <script src="lib/jquery-1.9.1.js"></script>
    <script src="lib/ui-bootstrap-0.10.0.min.js"></script>
    <script src="lib/ng-grid.min.js"></script>
 
    <script src="script/person.js"></script>
 
    <link rel="stylesheet" type="text/css" href="lib/bootstrap.min.css"/>
    <link rel="stylesheet" type="text/css" href="lib/ng-grid.min.css"/>
    <link rel="stylesheet" type="text/css" href="css/style.css"/>
</head>
 
<body>
 
<br>
 
<div class="grid">
    <!-- Specify a JavaScript controller script that binds Javascript variables to the HTML.-->
    <div ng-controller="personsList">
        <!-- Binds the grid component to be displayed. -->
        <div class="gridStyle" ng-grid="gridOptions"></div>
 
        <!--  Bind the pagination component to be displayed. -->
        <pagination direction-links="true" boundary-links="true"
                    total-items="persons.totalResults" page="persons.currentPage" items-per-page="persons.pageSize"
                    on-select-page="refreshGrid(page)">
        </pagination>
    </div>
</div>
 
</body>
</html>

Помимо деклараций Javascript и CSS, там очень мало кода. Очень впечатляюще. Angular также имеет широкий спектр готовых к использованию компонентов, поэтому я использую ng-grid для отображения данных и UI Bootstrap, который предоставляет компонент разбиения на страницы. В ng-grid также есть компонент разбивки на страницы, но мне больше понравился компонент разбивки на страницы пользовательского интерфейса Bootstrap.

Что-то все еще не хватает. Файл Javascript, где все происходит:

person.js

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
var app = angular.module('persons', ['ngGrid', 'ui.bootstrap']);
// Create a controller with name personsList to bind to the html page.
app.controller('personsList', function ($scope, $http) {
    // Makes the REST request to get the data to populate the grid.
    $scope.refreshGrid = function (page) {
        $http({
            url: 'resources/persons',
            method: 'GET',
            params: {
                page: page,
                sortFields: $scope.sortInfo.fields[0],
                sortDirections: $scope.sortInfo.directions[0]
            }
        }).success(function (data) {
            $scope.persons = data;
        });
    };
 
    // Do something when the grid is sorted.
    // The grid throws the ngGridEventSorted that gets picked up here and assigns the sortInfo to the scope.
    // This will allow to watch the sortInfo in the scope for changed and refresh the grid.
    $scope.$on('ngGridEventSorted', function (event, sortInfo) {
        $scope.sortInfo = sortInfo;
    });
 
    // Watch the sortInfo variable. If changes are detected than we need to refresh the grid.
    // This also works for the first page access, since we assign the initial sorting in the initialize section.
    $scope.$watch('sortInfo', function () {
        $scope.refreshGrid($scope.persons.currentPage);
    }, true);
 
    // Initialize required information: sorting, the first page to show and the grid options.
    $scope.sortInfo = {fields: ['id'], directions: ['asc']};
    $scope.persons = {currentPage : 1};
    $scope.gridOptions = {
        data: 'persons.list',
        useExternalSorting: true,
        sortInfo: $scope.sortInfo
    };
});

Код Javascript очень чистый и организованный. Обратите внимание, как все добавляется к контроллеру приложения, что позволяет вам разделить задачи по своей бизнес-логике. Чтобы реализовать требуемое поведение, нам просто нужно добавить несколько функций для обновления списка, вызвав нашу службу REST и отслеживая данные сетки, чтобы обновить представление. Это конечный результат:

javaee7-угловой список

Следующие шаги:

Для следующих постов, связанных с этими сериями, я планирую:

Ресурсы

Вы можете клонировать полную рабочую копию из моего репозитория github и развернуть ее в Wildfly. Вы можете найти там инструкции по его развертыванию. Также должен работать на Glassfish.

Java EE — угловой источник JS

Обновить

Тем временем я обновил оригинальный код постом об управлении зависимостями Javascript . Пожалуйста, загрузите оригинальный источник этого поста с версии 1.0 . Вы также можете клонировать репозиторий и извлечь тег из выпуска 1.0 с помощью следующей команды: git checkout 1.0 .

Надеюсь, вам понравился пост! Дайте мне знать, если у вас есть какие-либо комментарии по этому поводу.

Ссылка: Java EE 7 с Angular JS — часть 1 от нашего партнера по JCG Роберто Кортеса в блоге