JavaEE 7教程

AngularJS +Java EE 7教程源码案例

  这是一个简单的分页列表案例,提供REST服务。技术栈如下:

该案例源码下载地址:Github

后端:JavaEE7

实体模型代码如下:

@Entity

public class Person {

    @Id

    private Long id;

 

    private String name;

 

    private String description;

 

}

@Entity是JPA元注解,进行持久化数据库使用。持久化配置如下:

<?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服务代码:

@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 对应http GET 方法调用,@Produces(MediaType.APPLICATION_JSON) 是格式化REST输出为JSON格式.

下面我们需要一个类提供批量分页查询:

public class PaginatedListWrapper<T> {

    private Integer currentPage;

    private Integer pageSize;

    private Integer totalResults;

 

    private String sortFields;

    private String sortDirections;

    private List<T> list;

}

 

UI前端AngularJS

Angular扩展了传统HTML,使用了附加的标签属性,其和模型数据绑定,以一种MVC 方式,看看我们的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也有分页功能。

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

    };

});

运行效果如下:

 

 

Angular.js

JavaEE教程

Java学习心得