天天看点

带有Angular JS的Java EE 7 –第1部分

今天的帖子将向您展示如何使用Java EE 7和Angular JS构建非常简单的应用程序。 在去那里之前,让我告诉您一个简短的故事:

我不得不承认,我从来都不是Java语言的忠实拥护者,但是我仍然记得我第一次使用它。 我不记得确切的年份,但大概是90年代中期。 我的页面上有3帧(是的帧!还记得吗?那段时间很受欢迎),当我单击第3帧上的链接时,我想重新加载2帧。 当时,Javascript被用来在网页上做一些花哨的事情,并不是每个浏览器都支持Javascript,甚至有些浏览器甚至要求您打开它。 快速发展到今天,景观发生了巨大变化。 Javascript现在是完整的开发堆栈,您可以开发仅使用Javascript编写的整个应用程序。 对于我来说不幸的是,有时我仍然认为我回到了90年代,并且对Javascript的评价不高,因此这是我尝试更好地了解Javascript的尝试。

为什么选择Java EE 7?

好吧,我喜欢Java,而新的Java EE版本非常不错。 使用Wildfly或Glassfish时 不会太详细,速度很快。 它为您提供了满足您需求的大量规范,这是Java世界的标准。

为什么选择Angular JS?

我可能在这里关注有关Angular的大肆宣传。 由于我对Javascript的经验不足,所以我不太了解这些提议,因此我只是听从一些朋友的建议,并且我也注意到上一个Devoxx对Angular的广泛接受。 每个进行Angular演讲的房间都坐满了,所以我想尝试一下,自己找个机会。

应用程序

对于应用程序,这是一个带有分页的简单列表,以及一个提供列表数据的REST服务。 每次我开始一个新的企业项目时,通常通常是我们编写代码的第一件事:创建表,存储一些数据并列出一些随机数据,所以我认为这是适当的。

设置

  • Java EE 7
  • 角JS
  • ng-grid
  • UI引导程序
  • 野蝇

代码(最终!)

后端– Java EE 7

从后端开始,让我们定义一个非常简单的Entity类(为简单起见,省略了一些代码):

人.java

@Entity
public class Person {
    @Id
    private Long id;

    private String name;

    private String description;

}
           

如果您不熟悉Java EE JPA规范,则可以通过使用注释

@Entity

连接到具有相同名称的数据库表和使用注释

@Id

标识表主数据库来将对象类建模到数据库表中键。

接下来是

persistence.xml

persistence.xml

<?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"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
    <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上最喜欢的两个新功能:现在,您可以使用属性

javax.persistence.schema-generation.*

以标准方式运行sql,并且如果您不提供默认数据源,它还将您绑定到默认数据源。 因此,对于这种情况,它将为我们的应用程序使用内部Wildfly H2数据库。

最后,要提供列表数据,我们需要查询数据库并将其公开为REST服务:

PersonResource.java

@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")

将在url

yourdomain/resources/persons

处公开REST服务,

@GET

标记将由http GET方法和

@Produces(MediaType.APPLICATION_JSON)

调用)的逻辑

@Produces(MediaType.APPLICATION_JSON)

将REST响应格式化为JSON格式。 只需几个注释就可以了。

为了使为分页列表交换所需的信息更加容易,我还创建了以下包装器类:

PaginatedListWrapper.java

public class PaginatedListWrapper<T> {
    private Integer currentPage;
    private Integer pageSize;
    private Integer totalResults;

    private String sortFields;
    private String sortDirections;
    private List<T> list;
}
           

我们已经完成了后端工作。

UI – Angular JS

为了显示数据,我们将使用Angular JS。 Angular通过附加的自定义标签属性扩展了传统HTML,以遵循MVC方法绑定Javascript变量中表示的数据。 因此,让我们看一下我们的html页面:

index.html

<!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" target="_blank" rel="external nofollow" />
    <link rel="stylesheet" type="text/css" href="lib/ng-grid.min.css" target="_blank" rel="external nofollow" />
    <link rel="stylesheet" type="text/css" href="css/style.css" target="_blank" rel="external nofollow" />
</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也具有分页组件,但是我更喜欢UI Bootstrap分页组件。

仍然缺少一些东西。 一切发生的Javascript文件:

person.js

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服务来刷新列表,并监视网格数据以刷新视图。 这是最终结果:

带有Angular JS的Java EE 7 –第1部分

下一步:

对于与这些系列相关的以下帖子,我打算:

  • 实施过滤
  • 实施细节视图
  • 实施下一个/上一个浏览
  • 在云端部署
  • 管理Javascript依赖项

资源资源

您可以从我的github存储库中克隆完整的工作副本,然后将其部署到Wildfly。 您可以在此处找到说明进行部署。 也应该在Glassfish上工作。

Java EE – Angular JS源

更新资料

同时,我用有关“ 管理Javascript依赖项”的帖子更新了原始代码。 请从1.0版中下载此帖子的原始源。 您还可以克隆存储库,并使用以下命令从发行版1.0中检出标记:

git checkout 1.0

希望您喜欢这个帖子! 让我知道您是否对此有任何评论。

翻译自: https://www.javacodegeeks.com/2014/07/java-ee-7-with-angular-js-part-1.html