Sei sulla pagina 1di 34

TUTORIAL JHIPSTER

00. Setting up your environment


Pre-requirements
To run JHipster, you will need the following technologies.
Note that the following ones are already installed in this Cloud Shell:
1. Java 8 from the Oracle website JHipster 5.8.1 is using Java 8 and is not compatible with
other versions, JHipster 6 will be updated with Java 11.
2. Node.js from the Node.js website (please use a LTS 64-bit version, non-LTS versions are not
supported)
From here, please do follow the steps even if you are using google shell cloud.
3. NPM is installed with Node.js but you need to upgrade it:
npm install -g npm

4. Install JHipster:
npm install -g generator-jhipster

Creating a repository
To work with JHipster, we highly recommend you to use GitHub. If you are unfamiliar with how
versioning tools work, please head to the documentations.
Start by creating a folder that will contain your future application, in our case we will create an
application named BugTrackerJHipster so you can name your folder so.
mkdir ~/BugTrackerJHipster

If you're running these tutorials locally, we recommend you to use your usual workspace (and
therefore not use the absolute path to create and access your application folder).
If you're using Google Cloud Shell, please do set up your git like so :
git config --global user.name "John Doe";

git config --global user.email johndoe@example.com


After that, start by setting up your repository to make it ready to receive the generated application.
Please note that the Google Cloud Shell will persist while the session is active and will stop after an
hour of inactivity.
This is why we recommend you to use a repository to make sure that your project is not lost, even
when you are going for a lunch break !
Which type of application would you like to create?
1. Monolithic application
2. Microservice application
3. Microservice gateway
4. JHipster UAA server
• Which development database would you like to use?
1. H2, with its data stored on disk
2. H2, running in-memory
3. The same database as the one you chose for production (He marcado antes que la
de producción era SQL así que supongo que aquí sera esta opción, pero como no se
que significa lo otro dudo)
• Do you want to use the Spring cache abstraction?
1. ehcache
2. Hazelcast
3. Infinispan
4. Memcached
5. No cache, but be aware that when using a SQL database, this will disable the
Hibernate 2nd level cache.
• Which other technologies would you like to use? (Multi-respuesta)
1. Elasticsearch
2. WebSockets
3. Apache Kafka
4. API first
01. Creating your application
In this tutorial, we will create an application named BugTrackerJHipster that is inspired from the
issue tracking system from GitHub
1. First of all, go to the directory you've created in the previous tutorial
cd ~/BugTrackerJHipster

2. To generate your application, type:


jhipster

Click on the Next button at the bottom right of this window to know how to generate an application

Generating your application (1/6)


Some questions change depending on the previous choices you have made. For example, you won't
need to configure an Hibernate cache if you didn't select a SQL database

1. May JHipster anonymously report usage statistics to improve the tool over time?
This is a feature to help us track statistics so we can know on which technologies we have to focus
on developping. We highly recommend you to choose yes on this first question. Note that this
question will only be asked once.

2. Which type of application would you like to create ?


Your type of application depends on whether you wish to use a microservices architecture or not. A
full explanation on microservices is available here, if unsure use the default Monolithic application.
That is what we are doing in this tutorial.
For your future projects, you can either use:
• Monolithic application: that is a classical, one-size-fits-all application. It's easier to use and
develop, and is our recommended default.
• Microservice application: in a microservices architecture, this is one of the services.

• Microservice gateway: in a microservices architecture, this is an edge server that routes and
secures requests.
• JHipster UAA server: in a microservices architecture, this is an OAuth2 authentication
server that secures microservices. Refer to the Jhipster UAA documentation for more
information.

Generating your application (2/6)


3. What is the base name of your application?
That is the name of your application. By default, it has the same name as the directory you are in. In
our case, it displays BugTrackerJHipster, press Enter to validate it.

4. What is your default Java package name?


Your Java application will use this as its root package. This value is stored by Yeoman so that the
next time you run the generator the last value will become default. Of course, you can override it by
providing a new value. For this tutorial, let's go with com.mycompany.bugtracker

5. Do you want to use the JHipster Registry to configure, monitor and scale your application?
The JHipster registry is an Open Source tool used to manage your application at runtime. It is
required when using a microservices architecture (this is why this question is only asked when
generating a monolith, like in our case). Choose Yes at this question.

6. Which type of database would you like to use?


You can choose between:
• a SQL database (H2, MySQL, MariaDB, PostgreSQL, MSSQL, Oracle), which you will
access with Spring Data JPA
• MongoDB

• Cassandra

• Couchbase

• No database (only available when using a microservice application with JWT


authentication)
For BugTracker, let's go with an SQL database.

Generating your application (3/6)


7. Which production database would you like to use?
• MySQL

• MariaDB

• PostgreSQL

• Oracle (Please follow our documentation to use the Oracle proprietary driver)

• Microsoft SQL server

Take MySQL for this question.


If you want to use Oracle, you will need to install the Oracle JDBC driver manually
8. Which development database would you like to use?
• H2, with its data stored on disk. This is a better option than running in-memory, as you won't
lose your data upon application restart.
• H2, running in-memory. This is the easiest way to use JHipster, but your data will be lost
when you restart your server.
• The same database as the one you chose for production: a bit more complex to set up, but
working on the same database as the one you will use in production should be better at the
end. This is also the best way to use liquibase-hibernate as described in the development
guide.
Take the data-stored-on-disk-based H2 stored one.

9. Do you want to use the Spring cache abstraction?


The spring cache abstraction allows to use different cache implementations:
• ehcache (local cache)

• Hazelcast (distributed cache)

• Infinispan (another distributed cache).

• Memcached (yet another distributed cache)

• No cache, but be aware that when using a SQL database, this will disable the Hibernate 2nd
level cache.
Let's take ehcache for our BugTracker.
Also, this can have a very positive impact on your application's performance. Hence, it is a
recommended option.

Generating your application (4/6)


10.Do you want to use Hibernate 2nd level cache?
This option will only be available if you chose a SQL database (as JHipster will use Spring Data
JPA to access it) and a cache provider in the previous question.
Hibernate is the JPA provider used by JHipster, and it can use a cache provider to greatly improve
its performance. As a result, we highly recommend you to use this option, and to tune your cache
implementation according to your application's needs: Yes.

11.Would you like to use Maven or Gradle for building the backend?
You can build your generated Java application with either Maven or Gradle. Maven is more stable
and more mature. Gradle is more flexible, easier to extend and more hype.
For this one, let's go with Maven.

12.Which other technologies would you like to use?


This is a multiple choice answers, to add one or several other technologies to the application. Here,
you have to press space to select, a to toggle everything and i if you want to invert selection. The
available technologies are:
• Search engine using Elasticsearch. Elasticsearch will be configured using Spring Data
Elasticsearch, you can find more information on our ElasticSearch guide.
• WebSockets using Spring Websocket. Websockets can be enabled using Spring Websocket.
We also provide a complete sample to show you how to use the framework efficiently.
• Asynchronous messages using Apache Kafka. Use Apache Kafka as a publish/subscribe
message broker.
• API first development using OpenAPI-generator. This option lets you do API-first
development for your application by integrating the Swagger-Codegen into the the build.
In our case, we'd like to keep it as simple as possible so we are not going to choose any of them and
just press Enter.

Generating your application (5/6)


13.Which Framework would you like to use for the client?
• Angular

• React

Because we have to choose, let's take Angular

14.Would you like to use a Bootswatch theme (https://bootswatch.com/)?


Here again, we want to keep it simple: let's take Default JHipster

15.Would you like to enable internationalization support?


By default JHipster provides an excellent internationalization support, both on the client side and on
the server side. However, internationalization adds a little overhead, and is a little bit more complex
to manage, so you can choose not to install this feature.
Please note that JHipster covers only UI internationalization. For data internationalization, you will
need to code it yourself in JPA/Hibernate layer.
We are going to say Yes for educational purpose here but don't worry, as we will only touch the
english part of the server.

16.Please choose the native language of the application


This is the main language of your application: you are free to choose anything but for this tutorial,
let's go with English

Generating your application (6/6)


17.Please choose additional languages to install.
Like earlier, this is a multiple-choice question so the commands are the same. But then again, let's
say we will support French language in BugTracker.

18.Besides JUnit and Jest, which testing frameworks would you like to use?
By default, JHipster provide Java Unit/integration testing (using Spring's JUnit support) and
JavaScript unit testing (using Jest). As an option, you can also add support for:
• Performance tests using Gatling

• Behaviour tests using Cucumber

• Angular integration tests with Protractor

Later in the tutorial, we will learn how to test our application. For now, press A to select all of them
and press Enter.

19.Would you like to install other generators from the JHipster Marketplace?
The JHipster Marketplace is where you can install additional modules, written by third-party
developers, to add non-official features to your project.
We won't be using any of these in this tutorial, hence we will choose No.

JHipster should start generating the files: here are some tips in the meanwhile.
You can also use the Yeoman command-line options, like --force to automatically overwrite
existing files. So if you want to regenerate your whole application, including its entities, you can
run
jhipster --force --with-entities
02. Continuous Integration
Setting up Continuous Integration (CI) for a JHipster application is harder than for a classic typical
Spring MVC application because of the complexity associated with maintaining a build composed
of 2 software stacks:
• the Java back-end code with Maven or Gradle

• the JavaScript front-end with NodeJS, NPM or Yarn

Each stack comes with its own dependency management (Maven artifacts, NPM packages) with
potential conflicts to solve.
JHipster should support the following CI systems out of the box:
• Jenkins (Jenkins 1 and Jenkins 2)

• Travis

• GitLab CI

• Azure Pipelines

A more detailed guide for continuous integration is available on the official jhipster website.
In this tutorial we will focus on Travis CI.

Generate the configuration file


To generate these config files, run the following command in your projet folder:
jhipster ci-cd

What CI/CD pipeline do you want to generate?


• Jenkins pipeline

• Azure Pipelines

• GitLab CI

• Travis CI

In this tutorial we will choose Travis CI.

What tasks/integrations do you want to include?


• Analyze your code with *Sonar* (requires SONAR_TOKEN set on CI service)

• Deploy to *Heroku* (requires HEROKU_API_KEY set on CI service)


In this tutorial we won't use Sonar or Heroku, juste press Enter to skip it.
The JHipster sub-generator will generate a yaml configuration file for travis in the root project.

GitHub
In this section, we will show you how to configure a remote repository with git on GitHub.
1. Create an account or signin on GitHub
2. Create a new public repository named BugTrackerJHipster
Now, go on the BugTracker folder:
cd ~/BugTrackerJHipster

and execute the following command:


git remote add origin https://github.com/YOUR_GITHUB/BugTrackerJHipster

Now commit the file generated with the sub-generator for continuous integration:
git add .git commit -m "initial commit"

You can now push all the changes in the remote repository with the following command:
git push --set-upstream origin master

Travis CI
Travis CI is a service to build and test software hosted on GitHub. When activated on a particular
repository, any push or pull request will trigger the build and tests using the configuration file. This
is what we are going to do for the BugTracker project.
1. Sign in to Travis CI website with your GitHub account
2. Go to your repository list
3. Activate Travis CI for the BugTrackerJHipster repository
Travis CI is now installed on your BugTracker repository. You can commit and push a change to see
Travis build and run the tests.
03. JHipster App
Running the application
You have now a fully functional application built with JHipster. This tutorial will show you the
features offered by JHipster.
Once the application is generated, you can launch it with the following Maven command:
./mvnw

or on Windows :
mvnw.cmd

The application will be accessible locally on the port 8080. Luckily, Cloud Shell provides a web
preview functionality that allows you to run web applications on the virtual machine instance. Click

on icon and select the port 8080. You can check all the common ports available here.

File organization
Let's take a look at the project generated by JHipster. Below is a short description of its content.

Back-end
• The java code is located in src/main/java

• Unit and integration tests are located in src/test/java

• Gatling tests are located in src/test/gatling

Front-end
• The front-end is located in src/main/webapp

• The folder app contains the Angular modules

• i18n contains files for internationalization

Security
To use Spring Security in a Single Web Page Application, like those generated by JHipster, you
need Ajax login/logout/error views. JHipster has already configured Spring Security in order to use
those views correctly.
By default, JHipster comes with 4 different users:
• "system": for automatic processes, mainly used for our audit logs

• "anonymousUser": given to anonymous users when they do an action

• "user": a basic user with the authorization "ROLE_USER". His default password is "admin"

• "admin": an admin user with the authorizations "ROLE_USER" and "ROLE_ADMIN". His
default password is "admin"
The two authorizations “ROLE_USER” and “ROLE_ADMIN” provide the same access to the
entities which means that a “user” is authorized to perform the same CRUD operations as an
“admin”. This behavior can be an issue when the application runs in production because a “user”
can for example delete any entities. See more here.

Administration dashboard (1/2)


The following parts are available for admin users only, on the menu Administration.
The JHipster Registry provides administration dashboards, which are used for all application types.
As soon as an application registers on the Eureka server, it will become available on the dashboards.

Metrics dashboard
The metrics dashboard uses Micrometer to give a detailed view of the application performance. It
gives metrics on:
• the JVM

• HTTP requests

• cache usage

• database connection pool

By clicking on the Expand button next to the JVM thread metrics you will get a stacktrace of the
running application, which is very useful to find out blocked threads.

The health dashboard


The health dashboard uses Spring Boot Actuator’s health endpoint to give health information on
various parts of the application. Many health checks are provided out-of-the-box by Spring Boot
Actuator, and it’s also very easy to add application-specific health checks.

Administration dashboard (2/2)

The configuration dashboard


The configuration dashboard uses Spring Boot Actuator’s configuration endpoint to give a full view
of the Spring configuration of the current application.
The logs dashboard
The logs dashboard allows to manage at runtime the Logback configuration of the running
application. Changing the log level of a Java package is as simple as clicking on a button, which is
very convenient in both development and production environments.
04. Creating entities with JDL Studio
Introduction
Now that your application is up and running, you will soon need to create entities, and so you will
need:
• A database table

• A Liquibase change set

• A JPA Entity

• A Spring Data JPA Repository

• A Spring MVC REST Controller, which has the basic CRUD operations

• An Angular router, a component and a service

• An HTML view

• Integration tests to validate everything works as expected

• Performance tests, to see if everything works smoothly

If you have several entities, you will likely want to have relationships between them. For this, you
will need:
• A database foreign key

• Specific JavaScript and HTML code to manage this relationship

Thankfully, the "entity" sub-generator will help you create all the required files, and provide a
CRUD front-end for each entity (see Angular project structure).

JDL Studio
You can use a graphical tool to create your entities. In this case, we advise you to use JDL Studio,
our online tool to create entities and relationships using our domain-specific language JDL.
After clicking on the first link, the JDL Studio opens on a window. You can now start writing your
first entity.
The entity declaration is done as follows:
entity <entity name> {
<field name> <type> [<validation> *]
}

• <entity name> is the name of the entity

• <field name> the name of one field of the entity


• <type> the JHipster supported type of the field,

• and as an option <validation> the validations for the field

The possible types and validations are those described here. If the validation requires a value,
simply add (<value>) right after the name of the validation.

Here's an example of a JDL code:


entity A
entity B
entity C
entity D {
name String required
address String required maxlength(100)
age Integer required min(18)
}

Regexes are a bit special as they are used like this (from v1.3.6):
entity A {
myString String required minlength(1) maxlength(42) pattern(/[A-Z]+/)
}

Because the JDL was made to be simple to use and read, if your entity is empty (no field), you can
just declare an entity with entity A instead of entity A {}.

Note that JHipster adds a default id field so that you needn't worry about it.

In the JDL Studio, declare the following entities:


Project
• has a name of type String

Label
• has a label of type String that is at least 3 characters long

Ticket
• has a title of type String that is required

• has a description of type String

• has a dueDate of type LocalDate

• has a done of type Boolean

If you've declared them properly, you should see the graphical tool updating itself in real time while
you are done creating your entities. To know more about entity fields, click on the Next button
down there.

Entity fields and field types


For each entity, you can add as many fields as you want. You will need to add their name and type
and JHipster will generate for you all the required code and configuration, from the Angular HTML
view to the Liquibase changelog.
Those fields cannot contain reserved keywords in the technologies you are using. For example, if
you use a MySQL database :
• You cannot use Java reserved keywords (as your code will not compile)

• You cannot use MySQL reserved keywords (as your database schema update will fail)

JHipster supports many field types. This support depends on your database backend, so we use Java
types to describe them; a Java String will be stored differently in Oracle or Cassandra, and it is
one of JHipster's strengths to generate database access code for you.
• String: A Java String. Its default size depends on the underlying backend (if you use JPA,
it's 255 by default), but you can change it using the validation rules (putting a max size of
1024, for example).
• Integer: A Java Integer.

• Long: A Java Long.

• Float: A Java Float.

• Double: A Java Double

• BigDecimal: A java.math.BigDecimal object, used when you want exact mathematic


calculations (often used for financial operations).
• LocalDate: A java.time.LocalDate object, used to correctly manage dates in Java.

• Instant: A java.time.Instant object, used to represent a timestamp, an instantaneous point


on the time-line.
• ZonedDateTime: A java.time.ZonedDateTime object, used to represent a local date-time
in a given timezone (typically a calendar appointment). Note that time zones are neither
supported by the REST nor by the persistence layers so you should most probably use
Instant instead.

• Boolean: A Java Boolean.

• Enumeration: A Java Enumeration object. When this type is selected, the sub-generator
will ask you what values you want in your enumeration and it will create a specific enum
class to store them.
• Blob: A Blob object, used to store some binary data. When this type is selected, the sub-
generator will ask you if you want to store generic binary data, an image object, or a
CLOB(long text). Images will be handled specifically on the Angular side, so they can be
displayed to the end user.
Validation
Validation can be set up for each field. Depending on the field type, different validation options will
be available.
Validation will be automatically generated on:
• the HTML views, using the Angular or React validation mechanism

• the Java domain objects, using Bean Validation

Bean validation will then be used to automatically validate domain objects when they are used in:
• Spring MVC/REST controllers (using the @Valid annotation)

• Hibernate/JPA (entities are automatically validated before being saved)

Validation information will also be used to generate more precise database column metadata:
• Required fields will be marked non-nullable

• Unique fields will create a unique constraint

• Fields which have a maximum length will have the same column length

Validation has a few limitations:


• We don't support all validation options from Angular, React and Bean Validation, as we only
support those which are common to both client and server APIs
• Regular Expression patterns don't work the same in JavaScript and in Java, so if you
configure one, you might need to tweak one of the generated patterns
• JHipster generates unit tests that work for generic entities, without knowing your validation
rules: it is possible that the generated tests do not pass the validation rules. In that case, you
will need to update the sample values used in your unit tests, so that they pass the validation
rules

Relationships
Now that you have created your initial entities, you will need to declare your relationships. Entity
relationships are only available for SQL databases. It is a fairly complex subject, which has its own
documentation page: Managing relationships. The relationships declaration is done as follows:
relationship (OneToMany | ManyToOne | OneToOne | ManyToMany) {
<from entity>[{<relationship name>[(<display field>)]}] to <to
entity>[{<relationship name>[(<display field>)]}]
}

• ( OneToMany | ManyToOne | OneToOne | ManyToMany ) is the type of your


relationship
• <from entity> is the name of the entity owner of the relationship: the source

• <to entity> is the name of the entity where the relationship goes: the destination
• <relationship name> is the name of the field having the other end as type

• <display field> is the name of the field that should show up in select boxes (default:
id)

• required whether the injected field is required

• with jpaDerivedIdentifier whether @MapsId is used for the association


(applicapble only for one-to-one)
Append these to your .jh file:
relationship ManyToMany {
Ticket{label(label)} to Label{ticket}
}

relationship ManyToOne {
Ticket{project(name)} to Project,
Ticket{assignedTo(login)} to User{ticket}
}

We just declared that:


• A ticket can have many labels attached to it and labels can be attached to many tickets

• A ticket is attached to a single project but a project can be attached to many tickets

• A ticket is assigned to a single user, referred to as his login, but a user can be attached to
many tickets
Finally, let's add a pagination for our tickets, add this to your file:
paginate Ticket with pagination

Please note that pagination is not available if you created your application with Cassandra. Of
course, this will be added in a future release.
Pagination uses the Link Header, as in the GitHub API, JHipster provides a custom implementation
of this specification on both the server (Spring MVC REST) and the client (Angular in our case)
sides.
If you look in the res folder, you will see a file named jhipster-jdl.jh that is the .jh file that should
be exported when you click on the top right button "Download text file of this JDL". If you open it,
you will see that it is what you've written before.

Importing the .jh file


After creating the .jh file, you can now generate entities from the JDL file using the import-jdl
sub-generator, by running jhipster import-jdl your-jdl-file.jh

Go to your project directory and type:


jhipster import-jdl ~/jhipster-guides/res/jhipster-jdl.jh

Run the generated test suite, with


mvn test

Launch the application (for example with mvn), log in and click on "Entities" in the menu. You
should see the entities you have created with the JDL Studio.
05. Updating your back-end
Ordered tickets
Right now, our tickets are not ordered, unless you click on the column header to sort them manually.
We want to change that as we want to have the most urgent tickets on top of the list.
First, head to the TicketRepository.java file in the back end part of your application and add the
following method:
Page<Ticket> findAllByOrderByDueDateAsc(Pageable pageable);

Spring Data JPA will deduce its associated query by parsing the method name, so that you do not
have to implement anything else.
Now, head to the file TicketResource.java and change the function getAllTickets to use our
new function instead.
@GetMapping("/tickets")
public ResponseEntity<List<Ticket>> getAllTickets(Pageable pageable,
@RequestParam MultiValueMap<String, String> queryParams,
UriComponentsBuilder uriBuilder, @RequestParam(required = false,
defaultValue = "false") boolean eagerload) {
log.debug("REST request to get a page of Tickets");
Page<Ticket> page;
if (eagerload) {
page = ticketRepository.findAllWithEagerRelationships(pageable);
} else {
//page = ticketRepository.findAll(pageable);
page = ticketRepository.findAllByOrderByDueDateAsc(pageable);
}
HttpHeaders headers =
PaginationUtil.generatePaginationHttpHeaders(uriBuilder.queryParams(queryP
arams), page);
return ResponseEntity.ok().headers(headers).body(page.getContent());
}

If you start your server again, you should see that the tickets are automatically ordered by the due
date.

Assigned tickets
Let's now add up a new API to our server: you want to show your end users only their assigned
tickets. For that, let's start by creating a new mapping, add this to the file TicketResource.java:
@GetMapping("/tickets/self")
public ResponseEntity<List<Ticket>> getAllSelfTickets(@ApiParam Pageable
pageable, @RequestParam(required = false, defaultValue = "false") boolean
eagerload){
log.debug("REST request to get a page of user's Tickets");
Page<Ticket> page;
if (eagerload) {
page = ticketRepository.findAllWithEagerRelationships(pageable);
} else {
page = new
PageImpl<>(ticketRepository.findByAssignedToIsCurrentUser());
}
HttpHeaders headers =
PaginationUtil.generatePaginationHttpHeaders(uriBuilder.queryParams(queryP
arams), page);
return ResponseEntity.ok().headers(headers).body(page.getContent());
}

If you check the file TicketRepository.java, you will see that the method has been already
implemented, that is why this time you don't need to modify anything.
With the previous code added, we've supplemented our API with a new mapping: to see if the
endpoint works as intended, start up your application and log in as an admin.
Click on the Administration menu and then API. Show the Ticket Resource API and you should
see that a GET /api/tickets/self has been added on the list.
Show the hidden contents by clicking on it and click on the Try it out! button. You will see that the
server works fine and answers with a JSON.

Securing our back-end


Right now, anyone can delete a ticket, even a normal user. We want to ensure that only an admin
can delete a ticket.
JHipster is using Spring Security to manage authentication and authorization in your application.
To ensure that only an admin can delete a ticket, head to the file TicketResource.java again and add
the following annotation on the method deleteTicket:
@DeleteMapping("/tickets/{id}")
@Secured(AuthoritiesConstants.ADMIN)
public ResponseEntity<Void> deleteTicket(@PathVariable Long id) {
...
}

If you're using the google cloud shell to edit files, remember to add the import:
import org.springframework.security.access.annotation.Secured;
import com.mycompany.bugtracker.security.AuthoritiesConstants;
import io.swagger.annotations.ApiParam;
import org.springframework.data.domain.PageImpl;

And that's about it !


07. Editing the front end (Angular)
In this guide, we will make our own Angular component in order to display the logged user's
tickets.

Tooling
Angular is using TypeScript instead of JavaScript, and as a result a specific tooling is necessary to
work efficiently with it. Our development workflow for an Angular application is as below:
1. When you generate an application, the files are created and then the command npm install
is executed.
2. Once the previous command is completed, the script postinstall in package.json is executed
triggering the task webpack:build.
3. Now you should have all the files generated and compiled into the folder www inside the
target or build folder based on the build tool (Maven or Gradle) selected.
4. Now run ./mvnw to launch the application server and it should be available at
localhost:8080. This will also serve the client side code compiled from the above steps.
./mvnw

or on Windows :
mvnw.cmd

5. Now run npm start in a new terminal to launch the Webpack dev-server with BrowserSync.
This will automatically compile your TypeScript code and reload your browser on change.
npm start

6. Click on and watch the port 9000. Now any change on your front end will be reflected
here.
If you start making changes to the client side code without having npm start running, nothing will
be reflected as the changes are not compiled. So you need to either run npm run webpack:build
manually after changes or have npm start running.
More at the JHipster website.
Editing the front end (Angular)
In this guide, we will make our own Angular component in order to display the logged user's
tickets.

Tooling
Angular is using TypeScript instead of JavaScript, and as a result a specific tooling is necessary to
work efficiently with it. Our development workflow for an Angular application is as below:
1. When you generate an application, the files are created and then the command npm install
is executed.
2. Once the previous command is completed, the script postinstall in package.json is executed
triggering the task webpack:build.
3. Now you should have all the files generated and compiled into the folder www inside the
target or build folder based on the build tool (Maven or Gradle) selected.
4. Now run ./mvnw to launch the application server and it should be available at
localhost:8080. This will also serve the client side code compiled from the above steps.
./mvnw

or on Windows :
mvnw.cmd

5. Now run npm start in a new terminal to launch the Webpack dev-server with BrowserSync.
This will automatically compile your TypeScript code and reload your browser on change.
npm start

6. Click on and watch the port 9000. Now any change on your front end will be reflected
here.
If you start making changes to the client side code without having npm start running, nothing will
be reflected as the changes are not compiled. So you need to either run npm run webpack:build
manually after changes or have npm start running.
More at the JHipster website.

Updating the service


Now that we have installed the environment for Angular development, we will update the default
TicketService generated by JHipster and add a new method that call and retrieve the query we made
earlier with Spring Data in the back end.
1. Open ticket.service.ts
2. Add the following method.
queryMyTickets(): Observable<EntityArrayResponseType> {
const options = createRequestOption();
return this.http
.get<ITicket[]>(this.resourceUrl + '/self', { params: options,
observe: 'response' })
.pipe(map((res: EntityArrayResponseType) =>
this.convertDateArrayFromServer(res)));
}

Calling queryMyTickets() will send a HTTP request to the Rest Controller and will return all
the tickets associated to the connected user.

Adding our new components (1/3)


Let's create a new Angular component called mytickets.
1. Install the command-line interface tool Angular CLI
npm install -g @angular/cli

2. Be sure to be inside the JHipster project


cd ~/BugTrackerJHipster

3. Generate the new component mytickets


ng generate component mytickets

4. Go to the generated component which should be located in the following folder


src/main/webapp/app/
cd src/main/webapp/app/mytickets

5. Replace mytickets.component.html with the following content.


<h2 id="page-heading">
<span>Assigned tickets</span>
</h2>
<jhi-alert></jhi-alert>
<br/>
<div class="table-responsive" *ngIf="tickets">
<table class="table table-striped">
<thead>
<tr jhiSort [(predicate)]="predicate" [(ascending)]="reverse">
<th jhiSortBy="id"><span
jhiTranslate="global.field.id">ID</span>
<fa-icon [icon]="'sort'"></fa-icon>
</th>
<th jhiSortBy="title"><span
jhiTranslate="bugTrackerJHipsterApp.ticket.title">Title</span>
<fa-icon [icon]="'sort'"></fa-icon>
</th>
<th jhiSortBy="description"><span
jhiTranslate="bugTrackerJHipsterApp.ticket.description">Description</span>
<fa-icon [icon]="'sort'"></fa-icon>
</th>
<th jhiSortBy="dueDate"><span
jhiTranslate="bugTrackerJHipsterApp.ticket.dueDate">Due Date</span>
<fa-icon [icon]="'sort'"></fa-icon>
</th>
<th jhiSortBy="done"><span
jhiTranslate="bugTrackerJHipsterApp.ticket.done">Done</span>
<fa-icon [icon]="'sort'"></fa-icon>
</th>
<th jhiSortBy="project.name"><span

jhiTranslate="bugTrackerJHipsterApp.ticket.project">Project</span>
<fa-icon [icon]="'sort'"></fa-icon>
</th>
<th jhiSortBy="assignedTo.login"><span
jhiTranslate="bugTrackerJHipsterApp.ticket.assignedTo">Assigned To</span>
<fa-icon [icon]="'sort'"></fa-icon>
</th>
<th></th>
</tr>
</thead>
<tbody>
<tr *ngFor="let ticket of tickets">
<td><a [routerLink]="['/ticket', ticket.id,
'view' ]">{{ticket.id}}</a></td>
<td>{{ticket.title}}</td>
<td>{{ticket.description}}</td>
<td>{{ticket.dueDate | date:'mediumDate'}}</td>
<td>{{ticket.done}}</td>
<td>
<div *ngIf="ticket.project">
<a [routerLink]="['../project', ticket.project?.id,
'view' ]">{{ticket.project?.name}}</a>
</div>
</td>
<td>
{{ticket.assignedTo?.login}}
</td>
<td class="text-right">
<div class="btn-group flex-btn-group-container">
<button type="submit"
[routerLink]="['/ticket', ticket.id, 'view' ]"
class="btn btn-info btn-sm">
<fa-icon [icon]="'eye'"></fa-icon>
<span class="d-none d-md-inline"
jhiTranslate="entity.action.view">View</span>
</button>
<button type="submit"
[routerLink]="['/ticket', ticket.id, 'edit']"
class="btn btn-primary btn-sm">
<fa-icon [icon]="'pencil-alt'"></fa-icon>
<span class="d-none d-md-inline"
jhiTranslate="entity.action.edit">Edit</span>
</button>
</div>
</td>
</tr>
</tbody>
</table>
</div>

Adding our new components (2/3)


6. Replace mytickets.component.ts with the following content.
import { Component, OnInit } from '@angular/core';
import { ITicket } from 'app/shared/model/ticket.model';
import { Subscription } from 'rxjs';
import { TicketService } from 'app/entities/ticket';
import { JhiAlertService, JhiEventManager, JhiParseLinks } from 'ng-
jhipster';
import { AccountService } from 'app/core';
import { HttpErrorResponse, HttpHeaders, HttpResponse } from
'@angular/common/http';
@Component({
selector: 'jhi-mytickets',
templateUrl: './mytickets.component.html',
styles: []
})
export class MyticketsComponent implements OnInit {
tickets: ITicket[];
account: Account;
eventSubscriber: Subscription;
predicate: any;
reverse: any;
links: any;
totalItems: any;
constructor(
private accountService: AccountService,
private ticketService: TicketService,
private jhiAlertService: JhiAlertService,
private eventManager: JhiEventManager,
private parseLinks: JhiParseLinks
) {}
ngOnInit() {
this.loadSelf();
this.accountService.identity().then((account: Account) => {
this.account = account;
});
this.registerChangeInTickets();
}
loadSelf() {
this.ticketService
.queryMyTickets()
.subscribe(
(res: HttpResponse<ITicket[]>) =>
this.paginateTickets(res.body, res.headers),
(res: HttpErrorResponse) => this.onError(res.message)
);
}
sort() {
const result = [this.predicate + ',' + (this.reverse ? 'asc' :
'desc')];
if (this.predicate !== 'id') {
result.push('id');
}
return result;
}
protected paginateTickets(data: ITicket[], headers: HttpHeaders) {
this.links = this.parseLinks.parse(headers.get('link'));
this.totalItems = parseInt(headers.get('X-Total-Count'), 10);
this.tickets = data;
}
protected onError(errorMessage: string) {
this.jhiAlertService.error(errorMessage, null, null);
}
registerChangeInTickets() {
this.eventSubscriber =
this.eventManager.subscribe('ticketListModification', response =>
this.loadSelf());
}
}

Adding our new component (3/3)


Now, let's add the new component to the navigation bar so the users can access it.
1. Open navbar.component.html.
2. Add the following content right after the "home" button code.
<li class="nav-item" routerLinkActive="active"
[routerLinkActiveOptions]="{exact: true}" *ngSwitchCase="true">
<a class="nav-link" routerLink="jhi-mytickets"
(click)="collapseNavbar()">
<span>
<fa-icon icon="th-list"></fa-icon>
<span>MyTickets</span>
</span>
</a>
</li>

Finally, we have to configure the route for our new component.


1. Open app-routing.module.ts.
2. Add the new component in the router module.
{
path: 'jhi-mytickets',
component: MyticketsComponent
}

Do not forget to import MyTicketsComponent in the app-routing.module.ts file.


import { MyticketsComponent } from 'app/mytickets/mytickets.component';

The file should look like this:


import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { errorRoute, navbarRoute } from './layouts';
import { DEBUG_INFO_ENABLED } from 'app/app.constants';
import { MyticketsComponent } from 'app/mytickets/mytickets.component';
const LAYOUT_ROUTES = [navbarRoute, ...errorRoute];
@NgModule({
imports: [
RouterModule.forRoot(
[
{
path: 'jhi-mytickets',
component: MyticketsComponent
},
{
path: 'admin',
loadChildren:
'./admin/admin.module#BugTrackerJHipsterAdminModule'
},
...LAYOUT_ROUTES
],
{ useHash: true, enableTracing: DEBUG_INFO_ENABLED }
)
],
exports: [RouterModule]
})
export class BugTrackerJHipsterAppRoutingModule {}

Checking out the result


Let's check our new component.
1. Log as Administrator (login="admin" and password="admin"), you should be able to see
"MyTickets".
2. Click on MyTickets and there you have your component ! However this should be empty
since we have not yet created any entities.
3. Create a Project and 2 Tickets: one assigned to the Administrator and one to the User.
4. Click on MyTickets, you should then see the ticket assigned to the Administrator.
07. Testing your application
Introduction
JHipster comes with an extensive set of tests, and each generated application has:
• Integration tests using the Spring Test Context framework.

• UI tests with Jest.

Optionally, JHipster can also generate:


• Performance tests with Gatling.

• Behaviour-driven tests with Cucumber

• Angular/React integration tests with Protractor.

We have two goals in generating those tests:


• Help every JHipster user follow best practices, as we believe tests are a very important part
of an application
• Validate that what is being generated is correct. So even if you don't plan to use those tests at
all, doing just a ./mvnw clean test and npm test after generating your application
is a good way to know if everything is fine. You are then free to ignore them if you think
that testing is a waste of time!
All those tests will be generated in the standard Maven folder src/test.

Integration tests
Integration tests are done with the Spring Test Context framework, and are located in the folder
src/test/java. JHipster will launch a specific Spring test context, which will be re-used along
all tests, as:
• Your Spring beans should be stateless and thread-safe, and thus can be re-used across your
different tests suites.
• Launching just one Spring context for all the tests if a lot faster than launching a new Spring
context for each test.
This Spring test context will use a specific test database for the execution of the tests:
• If you use a SQL database, JHipster will launch an in-memory H2 instance in order to use a
temporary database for its integration tests. Liquibase will be run automatically, and will
generate the database schema.
• If you use Cassandra, JHipster will launch an in-memory Cassandra instance using
CassandraUnit.
• If you use MongoDB, JHipster will launch an in-memory MongoDB instance using
de.flapdoodle.embed.mongo.
• If you use Elasticsearch, JHipster will launch an in-memory Elasticsearch instance using
Spring Data Elasticsearch.
• If you use Couchbase, JHipster will launch a containerized version of Couchbase with
Docker using Couchbase TestContainers.
Those tests can be run directly in your IDE, by right-clicking on each test class, or by running
./mvnw clean test (or ./gradlew test if you run Gradle).

In our case and especially if you are using Google Cloud Shell, run the command in your
application folder:
./mvnw clean test

Limitations: if the generated entities have some validations, JHipster will not be able to generate
the correct values depending on the validation rules because the rules can be complex (i.e. regex
pattern). In this case, the tests will fail and you will have to change the values manually to make the
tests pass.
Note that the Behaviour-driven development (BDD) is available using Cucumber, with its JVM
implementation. Gherkin features will have to be written in your src/test/features
directory.
That means Cucumber, being a JUnit extension, will be ran along your ./mvnw clean test
command.

Performance tests
Performance tests are done with Gatling, and are located in the folder src/test/gatling. They
are generated for each entity, and allows to test each of them with a lot of concurrent user requests.
To run Gatling tests, you must first install Gatling: please go to the Gatling download page and
follow the instructions there. Please note we do not allow to run Gatling from Maven or Gradle, as
it causes some classpath issues with other plugins (mainly because of the use of Scala).
NOTE We currently support Gatling 2.x only. You can download the latest 2.x version directly from
maven central.
Warning! At the moment, those tests do not take into account the validation rules you may have
enforced on your entities. Also tests for creating entities that have a required relationship with
another entity will fail out of the box. You will anyway need to change those tests, according to
your business rules, so here are few tips to improve your tests:
• On your running application, go to the Administration > Logs screen, and put
org.springframework in debug mode. You will see the validation errors, for
example.
• Use the application normally and open the Chrome console log: you will be able to see
the REST requests with all their parameters, including the HTTP headers.
For running Gatling tests on a microservice application, you have to:
• Run a registry

• Run a gateway

• Run the microservice application

• Then, you can run Gatling tests

In this tutorial, we've given you an installation script for Gatling. Run the following command to
install it:
~/jhipster-guides/utils/install-gatling.sh

To run the Gatling test, head to:


cd ~/BugTrackerJHipster/src/test/gatling

and run:
~/jhipster-guides/gatling/bin/gatling.sh

Let's stress test our Project API, so choose 1. You don't especially need to give a simulation id nor a
description so you can just skip these parts.
When the test ends, gatling generates an html file that allows you to check the results: feel free to
visit the html page!

UI tests
UI tests come in two flavors with JHipster: unit tests with Jest, and integration tests with Protractor.
Only Jest is provided by default, but if you want to have a good test coverage of your application,
we recommend that you use both tools together.

Jest
UI unit tests are located in the folder src/test/javascript/spec. They use Jest.

Those tests will mock up the access to the application's REST endpoints, so you can test your UI
layer without having to launch the Java back-end.
• Those tests can be run using npm test.

• Tip: if you want to focus on a single test then change the module description from
describe('...', function() { to fdescribe('...', function() { and
Jest will run this test only.
cd ~/BugTrackerJHipster;npm test
Protractor
UI integration tests are done with Protractor, and are located in the folder
src/test/javascript/e2e.

Those tests will launch a Web browser and use the application like a real user would do, so you
need to have a real application running, with its database set-up.
Those tests can be run using npm run e2e.

Please note that Protractor test needs a browser to run the protractor tests. If you are using Google
Cloud Shell, you will not be able to run Protractor test. If you have set up a repository for your
project, you can run them locally after cloning it on your computer.
08. Deploying your app
Testing a production package
This allows to test a production build from Maven, without building a real package. To use JHipster
in “production” mode, use the pre-configured prod profile. With Maven, please run:
./mvnw -Pprod

This profile will compile, test and package your application with all productions settings.
If you want more information on the available profiles, please go the section titled Development
and Production profiles.
Next we will deploy our application using Docker, however if you want to build and execute WAR
file, you can check it out on JHipster website.

Deploying with docker


JHipster provides a complete Docker support, in order to:
• Facilitate development, as you can start a full infrastructure very easily, even when using a
complex microservice architecture
• Deploy directly in production if you use Docker Swarm, as it uses the same Docker
Compose configuration
One great feature of using Docker Compose is that you can easily scale your containers, using the
docker-compose scale command. This is very interesting if you use JHipster with a microservice
architecture.
When generating your application, JHipster generates for you:
• A Dockerfile for building a Docker image and running your application inside a container

• Several Docker Compose configurations to help you run your application with third-party
services, for example a database
Those files are located in the folder src/main/docker/.

Prerequisites
You have to install :
• Docker

• Docker Compose
Luckily, you do not need to install it with Google Cloud Shell.
Build and running a Docker image of your application
To create a Docker image of your application, and push it into your Docker registry:
./mvnw package -Pprod verify jib:dockerBuild

This process takes some time to complete (about 15 minutes with the boost mode on).
To run this image, use the Docker Compose configuration located in the src/main/docker folder of
your application:
docker-compose -f src/main/docker/app.yml up

Potrebbero piacerti anche