Java EE 7与Angular JS(1)

今天这篇文章将会向你介绍如何使用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

1
2
3
4
5
6
7
8
9
10
@Entity
public class Person {
     @Id
     private Long id;
 
     private String name;
 
     private String description;
 
}

如果你不是很熟悉Java EE的JPA规范,这里就稍作解释。这段代码使用了@Entity注解,从而使一个对象类连接到数据库中同名的表,并产生映射关系,注解@Id用于定义表中的主键。

接下来是persistence.xml文件:

persistence.xml

1
2
3
4
5
6
7
8
9
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"
              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

1
2
3
4
5
6
7
8
9
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 POJP,但是使用了Java EE的注解来增强行为。@ApplicationPath("/resources")@Path("persons")会通过yourdomain/resources/personsurl来暴露REST服务,@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-Angular JS

我们使用Angular JS来展示数据。Angular遵循了MVC模式,通过添加一些自定义的标签属性来绑定数据和Javascript中出现的变量,从而扩展了传统的HTML。那么, 让我们来看看我们的html页面:

index.html

1
2
3
4
5
6
7
8
9
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 >
 
 
 
< 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

1
2
3
4
5
6
7
8
9
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服务来刷新列表,以及监控表格中的数据来刷新视图。这是最终的结果:

下一步

这个系列的下一篇文章中,我打算:

资源

你可以从我的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

[ 转载请保留原文出处、译者和译文链接。]


转载自:http://www.importnew.com/13195.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
The demand for modern and high performing web enterprise applications is growing rapidly. No more is a basic HTML frontend enough to meet customer demands. This book will be your one-stop guide to build outstanding enterprise web applications with Java EE and Angular. It will teach you how to harness the power of Java EE to build sturdy backends while applying Angular on the frontend. Your journey to building modern web enterprise applications starts here! The book starts with a brief introduction to the fundamentals of Java EE and all the new APIs offered in the latest release. Armed with the knowledge of Java EE 8, you will go over what it's like to build an end-to-end application, configure database connection for JPA, and build scalable microservices using RESTful APIs running in Docker containers. Taking advantage of the Payara Micro capabilities, you will build an Issue Management System, which will have various features exposed as services using the Java EE backend. With a detailed coverage of Angular fundamentals, the book will expand the Issue Management System by building a modern single page application frontend. Moving forward, you will learn to fit both the pieces together, that is, the frontend Angular application with the backend Java EE microservices. As each unit in a microservice promotes high cohesion, you will learn different ways in which independent units can be tested efficiently. Finishing off with concepts on securing your enterprise applications, this book is a hands-on guide for building modern web applications.

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值