1-Introduction
You’ve been developing in Java EE all this time, but you’re tired of using JSF, or perhaps even Struts, and want to move to something more modern for your front end? Angular 2 is a perfect fit, and with the recent release of Angular 2 GA, now is the ideal time to make the move! Besides being easier to develop and maintain, an Angular 2 application allows you to take advantage of the huge improvements in browser technology over the last few years, and all the goodness that the modern web brings.Broad Strokes
We will be working with two separate applications, a Java EE back-end app, and an Angular 2 front-end app, avoiding a mixing of concerns in a single project. Source for both projects is provided, so in this article we display and highlight source only for key concepts – you can download the projects to look at more detail, or run them locally.Key technologies:
- JPA: Our sample Java EE application uses JPA to access data from a database.
- REST: We expose the table data via REST web services using Jersey – the reference implementation for the JAX-RS spec.
- RxJS: Our Angular 2 app uses RxJS to communicate with the web services.
JPA
Our sample back-end application, SWBackend, uses JPA with EclipseLink as a provider, and uses an embedded Derby database. We’re initializing this database with some character information from Star Wars, so you don’t need to bother with setting up sample data for testing.We won’t delve into the JPA aspects here, but you could also follow along with your own Java EE back-end application.
2-RESTifying Your Java EE Application
Dependencies
We need to add Jersey and supporting libraries to your project – these will enable the serialization of your data and the ability to expose it using REST web services.If you are following along in MyEclipse 2017, simply bring up the context menu on your project and select Project >Configure Facets… > Install JAX-RS Facet and proceed to select version 2.0 of JAX-RS. On the next page of the wizard, ensure you select Moxy and the Server libraries too.
If you are using Maven, this doc covers the dependencies you will need to add for different use cases. Primarily though, we will need:
org.glassfish.jersey.core/jersey-client
org.glassfish.jersey.core/jersey-server
org.glassfish.jersey.containers/jersey-container-servlet
org.glassfish.jersey.media/jersey-media-moxy
If you are not using Maven, you can download the Jersey JAX-RS 2.0 RI bundle and add all the JAR files contained within to your application’s classpath.
Source
Web Deployment Descriptor (web.xml)
We’re going to modify the web.xml file to declare a Jersey servlet and a corresponding URL mapping, as well as a CORS filter. Add the following to web.xml:Notes:
- url-pattern: “/jaxrs/*”, will root our web services at the /jaxrs path
- CorsFilter
- Depending on how and where you deploy your back-end application, and what server you use, you will most likely need a variation of these settings to allow your front-end Angular application to access the services exposed by the back end. Essentially, if your client application is running on a different domain, modern browsers will restrict the call made to the domain running your back end, unless the headers in the back end indicate that this call is permitted. For more, read: HTTP access control (CORS)
- The filter provided here is specific to the Apache Tomcat server; for other servers, you will need to enable CORS differently. Note that our cors.allowed.origins parameter is excessively open, so, please, use a more restrictive pattern for your production application.
JPA Classes
In our example, we’re going to be dealing with data from a single table, the “PERSON” table. We already have a Person JPA entity to start with and it’s a POJO with JPA annotations.Person.java source:
Finally, we come to making our person data accessible via REST services. Here’s the class that exposes the REST services via JAX-RS.
PersonFacadeREST.java source:
A few key annotations and methods:
@Path(“Person”)
public class PersonFacadeREST
Our person services will be available at the JAX-RS service relative path, Person – i.e., jaxrs/Person relative to our application’s webroot.
Note: It’s inefficient to be using a method that returns a list of all people in your database, so in a practical application, you would want to limit the amount of data retrieved.
3-Building the Angular 2 Application
Over the next few steps, we’ll cover how to create the Angular application along with Angular Services and Components, as well as how you can run and test it. For convenient access to wizards and views, please, switch to the Angular 2 perspective, if you are not using this perspective already. You can switch using Window > Perspective > Open Perspective > Other > Angular 2 or from the perspective switching toolbar.Create the Project
The first step is to create a new Angular 2 project using the New Angular 2 Project wizard. To get started, select File > New > Angular 2 Project. Type in a name for the project, and then click “Finish” to accept the default settings. We create a new project using the angular-cli.Create the Person Interface
In our Person interface, we simply define different attributes of the Person we will be displaying and manipulating.
To create this, bring up the context menu on the app folder and select New > Interface. Note that we’ve added a person segment to the path so that we can group all the functionality in this single folder.
Replace the code generated in person.ts with the following:
Person.ts source:
Create the Person Service
The Person service is the crux of our Angular application; this service interacts with the REST services exposed by our Java EE back end, allowing us to ultimately read and write data from/to our database.
To create the service, bring up the context menu on the app/person folder that was created in the previous step and select New > Service. Be sure to expand the Advanced group and select “Do not create the code in its own directory” so that we don’t get another subfolder.
Replace the code generated in person.service.ts with the following:
Person.service.ts source:
Let’s review some key methods in the service:
The get method gets the details of a single Person, getAll returns a list of Persons, and the save method is used to update Person details. Each of these methods makes a simple HTTP call to the REST web services exposed by the back end, and they return an Observable. An Observable is a basic building block of reactive programming, and basically represents a pushed based collection that can change over any amount time. This helps us asynchronously receive and process data, which is key in any modern web application. For more on Observables, please see here.
We’re also dealing with JSON in all cases, either what is returned by our back end or what is being pushed to it. The toPerson method is responsible for the ultimate conversion of the received JSON to our local Person interface, and in this case, the automatic conversion suits us just fine (we’ve designed both the back end and the front end to use the same field names). In other cases, you might have to write a more detailed conversion method.
Finally, we need to register our service as a provider and we can do that in the app module – app.module.ts. We need to import the service class and list it in the providers array.
Working with Components
Now let’s move on to some visuals! We’re going to create a list of people, a person details view and a view that will allow us to make changes to our chosen person – all with Angular components. An Angular component controls a patch of screen, called a view.Create the Person List Component
From the app/person context menu, choose New > Component. Again, uncheck the “Do not create the code in its own directory” option (do this for each component you create).The component is automatically imported and declared in the app module, app.module.ts, so you don’t have to do this yourself.
On clicking finish, we will get the Personlist.component.ts class and the personlist.component.html template class. Replace the generated code with the code below.
Personlist.component.ts source:
Personlist.component.html source:
A few key points to be covered in this component:
In ngOnInit, we subscribe to the Observer returned by the PersonService’s getAll method we discussed earlier. When the list of people is obtained, it will be assigned to the people field of the component – the good part is that this is asynchronous and we won’t be blocked waiting for the list.
The rendering of this component is defined in the personlist.component.html file, where we create a table and simply iterate through the people array to create a row for each person. One column with the name of the person, the link allows viewing the person’s details, the second column contains a link allowing editing. Note that the entire table is contained within a section that has a *ngIf=”people” condition, which ensures that the table will be created only after the list of people is returned by the earlier subscription – exactly what we want, achieved without any JavaScript gymnastics!
We also make use of the routerLink directive to create links to other components, we’ll cover that in the section on routers below.
Create the Person Edit Component
Perform similar steps as above to create a component which will be used to perform some basic editing of our people. Replace generated code with the code below.
Personedit.component.ts source:
Personedit.component.html source:
Key points:
In our component’s class, notice the subscription to the route’s parameter object to get us the Id of the person being edited. We’ll cover routes in more detail later.
We’re using Angular’s bi-directional databinding capability to map fields in our class to HTML elements. This allows model data to be displayed in the field, and changes to be propagated back to the model automatically. Furthermore, we’re performing some local validation by creating a local template variable (#personname) setting to ngModel. We can then check whether there are problems with that particular field, and if there are, we display the “error” div.
We’re setting another local template variable (#personform) to the ngForm directive. This allows us to disable submission of any of the fields contains invalid data.
On submission, we call the savePersonDetails method back in the component.
Create the Person Details Component
Persondetails.component.ts source:
Persondetails.component.html source:
Setting up Routes
So we’ve created a number of components, but we haven’t actually wired them together yet. How would a user get to these views? That’s where routing comes in.Let’s jump right ahead and look at routes we define in the app.routes.ts file.
App.routes.ts source:
App.module.ts source:
Recall in personlist.component.html, we had used a routerlink directive:
<a href="#" [routerLink]="['/person/edit', person.id]">Edit<a/>
This directive binds clickable HTML elements to a route, giving the router control over these elements. This allows us to create links in our application without crafting URLs manually.
Running Your Application
Deploy the back-end application
Ensure that your back-end application is deployed and running first. If you are using the attached back-end project, SWBackend, import it from the archive and use Run As > Maven install to ensure that the dependencies are downloaded into your project prior to deployment. In MyEclipse, this step is not necessary, but you may need to wait for the build process to complete to ensure all the dependencies are downloaded.You can now deploy your application using Run As > Run on Server / MyEclipse Server Application to deploy the back end to your preferred Java EE server.
To test that the back end is running correctly, see that this URL: http://localhost:8080/SWBackend/jaxrs/Person/1 returns JSON data for Luke Skywalker. If you don’t see the output or you see errors in the console, try to resolve those before moving to the next step. Please, remember to ensure that dependencies are downloaded and the project has been fully built.
Deploy the front-end application
Import the front-end project, SWAngular and choose Run As > npm Install to ensure all the Node dependencies are downloaded into the project. You should see the npm installation process in the Terminal+ view.You can now go ahead and deploy your application, from the project’s context menu, choose Run As > Angular 2 Web Application or you can even start the application from the Servers view – SWAngular will be listed under the Angular CLI node. Again, in the Terminal+ view, you should see the output of the “ng serve” process that is deploying your application.
If you used the Run As action, chrome will automatically open with the deployed application – if not, open a browser and navigate to http://localhost:4200/ to see the front end in action.
People List
Final Thoughts
With frameworks like Angular 2, we’re able to move away from what we like to call “back-end driven” front-end applications. As you have seen, we’re able to create a front end which takes advantage of improved browser technology and provides modern interaction patterns. All this without having to write special code outside of what a framework like Struts or JSF would normally be capable of, while still maintaining a strong link with the back-end.I hope this blog has been of use to you. If you aren’t already subscribing to our blogs, now might be a good time to start. Click here. Log in to subscribe
Attached Projects
SWBackend.zip – Backend JAX-RS / JPA Java EE ProjectSWAngular.zip – Frontend Angular 2 Project
References
- Angular Architecture Overview
- Angular Routing & Navigation
- RxJS – Observables
- Getting Started With Angular 2 Step by Step
- The Star Wars API
Author
Brian Fernandes
Director of Customer Engagement - Loves technology and almost everything related to computing. Wants to help you write better software. Follow at @brianfernandes.
0 comments:
Post a Comment