介紹如何使用Java EE 7和Angular JS來構建一個非常簡單的應用

jopen 10年前發布 | 58K 次閱讀 Java開發 Angular JS

今天這篇文章將會向你介紹如何使用Java EE 7Angular JS來構建一個非常簡單的應用。在此之前,先給大家講一個故事。

我必須承認,我從來都不是一個Javascript的超級粉絲,但我始終記得我第一使用它的情景。我不太記得確切的年份,不過大概是90年代的中期。我的一個頁面里有3個frame(是的,frame!記得這個東西嗎?那個時候非常流行的),而我想做的是在點擊了第3個frame上的一個鏈接時,能夠重新加載前兩個frame。那個時候,Javascript是用來在頁面上做一些花哨的東西的。不是所有的瀏覽器都支持,有些瀏覽器甚至需要你手動打開。時至今日,這個情景已經有了顯著變化,Javascript成為一門全棧的開發語言。你甚至可以僅僅用Javascript就能開發出一個完整的應用。但對于我來說,有時我還是會回想到90年代的情形,很難給予Javascript足夠的信任,所以這是我為了更好的了解Javascript所做出的嘗試。

為什么用Java EE 7?

好吧,我喜歡Java,并且新的Java EE版本非常好用,配合Wildfly或Glassfish使得它簡潔而且運行快速。Java EE7的規范可以滿足你所有需求,是Java編程中的標準。

為什么用Angular JS?

這里我大概是追隨了Angular JS的熱潮。因為我在Javascript方面沒有太多的經驗,不太了解各類的JS庫,所以這里只是采納了一些朋友的建議。而且我也注意到了在最近一次Devoxx大會上對于Angular得到了廣泛的接納,關于Angular的演講的每一個房間都爆滿。所以我想用它嘗試一下,也給我自己一個認識的機會。

關于應用

這個應用是一個簡單的包含分頁的列表,以及一個REST服務用于提供列表中的數據。每當我開始一個新的企業級應用的時候,這通常是我們開始編碼時所做的第一件事:創建一張表,存入一些數據,然后列出一些隨機數據,所以我認為這個應用是非常合適的。

配置

代碼(終于到代碼部分了!)

后端-Java EE 7

從后端開始,讓我們定義一個簡單的Entity類(為了簡潔省略了部分代碼):

Persion.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 POJP,但是使用了Java EE的注解來增強行為。@ApplicationPath("/resources")@Path("persons")會通過yourdomain/resources/personsurl來暴露REST服務,@GET標志了這個邏輯通過http的GET方法調用,@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遵循了MVC模式,通過添加一些自定義的標簽屬性來綁定數據和Javascript中出現的變量,從而擴展了傳統的HTML。那么, 讓我們來看看我們的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"/>
    <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其實同樣包含了分頁的組件,但是我更喜歡UI Bootstrap提供的組件。
這里還缺少了一個文件——一個js文件來是實現功能:

persion.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服務來刷新列表,以及監控表格中的數據來刷新視圖。這是最終的結果:

下一步

這個系列的下一篇文章中,我打算:

  • 實現攔截
  • 實現詳細視圖
  • 實現下一個/上一個瀏覽導航
  • 在云上部署
  • 管理Javascript依賴

資源

你可以從我的github庫中clone一個完整的拷貝,然后部署到Wildfly上,關于如何部署,也可以在上面找到指導,同樣,它也應該能在Glassfish上運行。Java EE – Angular JS Source

更新

同時,我還根據管理Javascript依賴一文來更新了我的源碼,請通過 release 1.0來下載源碼,同樣可以clone這個repo,并使用git checkout 1.0命令來下載release 1.0版本的源碼。

原文鏈接: javacodegeeks 翻譯: ImportNew.com - xiafei
譯文鏈接: http://www.importnew.com/13195.html

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!