Who says you can’t do rapid application development in Java? Part Three: Customizing the user experience

Our pet food reviews app is now working perfectly well for an admin user who knows what data is in the database, but we could improve the browsing, creating, and editing process for a regular end-user. In this part, I’ll walk you through some customizations you can do on the Angular front-end and the Spring Boot RESTful API, to make sure that our data is human-readable, and that users can navigate and submit reviews in the exact places they may expect.

If  you haven’t already, make sure to run the API with “./mvnw” and run the front end Webpack development server with “yarn start”. If all goes well, you’ll be able to visit the client-side application at localhost:9000. Because it’s using Webpack hot-module reloading under the hood, any changes you make to the front-end app will show up in your browser, without you having to hit refresh.

To edit the front-end code, open up src/main/webapp. You’ll see a full Angular 6+ web app here, with the features organized into multiple Angular modules. The front-end representation of the entities we generated in Part 2 will be in a module you can find at src/main/webapp/app/entities. Each entity has its own module within the entities module. So, for example, you’ll see the Food module at src/main/webapp/app/entities/food.module.ts, with a route file for that module at src/main/webapp/app/entities/food.route.ts. Alongside those files, you’ll see the TypeScript and HTML files for the basic CRUD components: index (food.component.ts + food.component.html), detail, edit/update, create (shared with food-update.component.ts), and delete. When starting out on a JHipster project, these files will get you a lot of bang for your buck — editing, reusing, or copying them with small tweaks will cover 90% of your CRUD use cases, so that you can spend most of your remaining time on things that are unique to your project.

But for now, let’s start with some simple changes in wording and branding. You’ll notice that the navbar has a dropdown for “entities” — let’s change that to something that’ll let end-users know that this is the place to go to interact with most of our core features. Open up src/main/webapp/app/layouts/navbar/navbar.component.html. Find the <span> element that contains the text “Entities” and change it to “Browse”. Within the “ul” with the class “dropdown-menu”, find the “span” element that says “Pet” and change it to “Pets”. Do the same for “Food”, but change it to “Food Options”, and change “Food Review” to “Food Reviews”. Once you’ve completed these small changes, you’ll see  that the navbar has a dropdown that lets you “browse pets” or “browse food options” or “browse food reviews.” Of course, the sky’s the limit for any further UX improvements you want to do, but at this stage we’ve at least made our navbar read like plain English, which means we’re further along to an MVP.

Let’s now take a look at our core feature: the Food Review. Make sure you’ve populated the database with some pets and foods before you do this step, so that the food review form actually has some options to work with. Open up the form component at src/main/webapp/app/entities/food-review/food-review-update.component.html. Inside the <option> element with the text {[foodOption.id}}, change the text to {{foodOption.name}}. Do the same for the <option> element with the text {{petOption.id}}. Then, for the <option> element with the text {{userOption.id}}, change it to {{userOption.firstName}} {{userOption.lastName}}. These small changes in display names will now allow end-users to see meaningful names for each associated field, instead of id fields that don’t mean anything outside of the database records.

You  may also notice that the “body” field for food reviews is just one line long. Let’s change it to a text area with a few rows, since it’s the core content we want users to submit. Find the <input> element with an [(ngModel)] of “foodReview.body”, and change it to a <textarea> with all the same properties. Make sure to add an ending </textarea> tag. You’ll immediately see the input expand, and you can add a rows=”(number)” attribute if you want it to be even bigger.

From there, the only remaining cosmetic change is to open up src/main/webapp/app/home/home.component.html, and change the text to match your website’s theme. With these small cosmetic changes, our app is now usable for a regular visitor. We didn’t even have to modify the backend API, but now we have a perfectly usable MVP!

Stay tuned for Part Four, where we’ll define a custom use case that allows us to define which pets line up with and can eat which foods.

Who says you can’t do rapid application development in Java? Part Two: Creating our entities, migrating the database, and allowing users to add reviews

In Part One of this tutorial, I covered  how to install JHipster and  use it to generate a Monolithic Spring Boot API with an Angular front end. The app that JHipster generated already includes a lot of great authentication and authorization features, but now it’s time to add the entities that will make our app unique.

JHipster uses Liquibase to manage database migrations, so feel free to add a migration and entity manually if you feel comfortable doing  so. But to follow our theme of rapid application prototyping, we will use JDL Studio, a web application that lets you visualize your database schema and then import it into JHipster. The CLI for JHipster will then allow you to generate the appropriate migrations, entities, JPA repositories, AND front-end components.

The purpose of our application is to create, read, edit, and delete information about pets, pet foods, and reviews of how well each food works for each pet. So let’s start with three basic entities:

entity Pet {
name String
description String
slug String
}

entity Food {
name String
description String
}

entity FoodReview {
title String
body String
rating FoodRating
}

In other words, we create an entity by typing “entity <EntityName>”, and then we add some curly braces to define the entity’s fields. Each field is defined by writing a lowercase field name, followed by an upper-CamelCase field type. You may notice that one of our field types is an undefined FoodRating. Add that as an enum below:

enum FoodRating {

ONE, TWO, THREE, FOUR, FIVE

}

Our application will need some relationships between our entities if we want to have any meaningful way of browsing reviews for a particular pet and food. Create them with this snippet:

relationship ManyToOne {
FoodReview{author} to User,
FoodReview{food} to Food{review},
FoodReview{pet} to Pet{foodReview}
}

As you can see, we define all our relationships in one place. JDL Studio works best with ManyToOne relationships, but feel free to create join tables any time you need to simulate a ManyToMany relationship. We define each relationship by typing <EntityName for the “many” side>{<alias for the owning entity>} to <EntityName for the owning entity>. For our use case, we only needed three relationships to start:

  1. A user can have many food reviews, and is referred to as the reviews’ author. So we type: FoodReview{author} to User
  2. A food can have many reviews. So we type: FoodReview{food} to Food{review}
  3. A pet can have many food reviews. So we type FoodReview{pet} to Pet{foodReview}

You may have noticed that we haven’t set up any association between pets and foods. That means we won’t yet be able to query for all the reviews associated with the foods that a particular pet ate. Sure, we can use FoodReview as a join-table between pets and foods, but what if we want to specify additional data about the pet-food relationship, without depending on a user’s review? Use your judgment here, but I consider this use-case complex enough, and important enough, that it deserves to be programmed at a more-granular level in a later blog post. For now, we’ll start with an MVP that can get some reviews, foods, and pets onto the page.

Once you’ve typed out your entities and relationships, you can specify the types of Java service classes and pagination we want each entity to use:

service all with serviceImpl

paginate Food, FoodReview with pagination
paginate Pet with infinite-scroll

When you’re done, download this JDL file into a new directory called “src/main/scripts”. Then run this command to import the JDL file:

jhipster import-jdl src/main/scripts/jhipster-jdl.jh

You will be prompted about some file conflicts, such as in the liquibase migration config, the Angular front end navbar component, and the Angular entity module file. To keep things simple, say yes to all of these prompts.

Open up your web application again, log in as an admin user, and check out the “entity” dropdown in the navbar: you now have CRUD pages for food, pets, and food reviews, with all the associations available in the forms!

Try creating some food and pet entities, and then head over to the Food Review form. So far so good, but you’ll see that in the pet and food dropdowns, you’ll only see id numbers, not the names of the pets and foods you can select. Not to mention that you’ll probably want to just browse to a food or pet’s page and be able to add a review right there, and have the association filled in automatically.

In other words, our app is perfectly functional for a savvy admin, but we have some work to do to improve the experience for an end user. It’s time to roll up our sleeves and start coding some TypeScript and Java. Stay tuned for Part Three:

Who says you can’t do rapid application development in Java? Part One: Project setup

When I started my web development career, I often heard that you had to use dynamic languages like Ruby or Python to prototype your ideas, and then, once your product became popular, you’d simply have to port it over to a battle-tested, compiled language like Java. Plenty of people have rebutted that last point by talking about how you can scale apps written in Rails, Django, or Laravel, and that many popular sites such as Github, Shopify, and Instagram have managed to do just that. It turns out, if your dynamic-language monolith takes off, you aren’t doomed to do a full rewrite. But I’d like to tackle the choice-of-language issue from a different angle: did you have to write that MVP in a dynamic language to begin with?

Like most popular languages, Java is no longer the same beast that it was when the Rails and Django community fled its over-engineered ecosystem in the mid-2000s. With robust IDE intellisense, along with tools such as Spring Boot to generate and autoconfigure a backend web application, and JHipster to add front-end single-page-app generation to the mix, Java can get your project up and running even faster than some of the dynamic language frameworks.

In this series, I’ll walk through the process of creating an application for keeping track of foods  that different pets can eat. The app will have admins and regular users, who can all create pet categories, food records, and reviews for each type of food. For example, a user can create a pet called “guinea pig,” a food record called “Oxbox pellets,” and a review that describes how much their guinea pigs liked this food, and how nutritious it is for them. Admins will be able to do several things on top of this core functionality. For example, an admin user will be able to set other users’ permission levels and see monitoring dashboards for the app’s performance and memory usage.

From a tech perspective, this app will be based on a Spring Boot RESTful API talking to a MySQL database, with Angular 6 on the front end. It will automatically be  configured with Liquibase to keep track of database migrations, and it will have a CLI for generating additional database-backed entities.

Right off the bat, this should strike you as a more extensive feature set than you would normally get in Rails or Django or Laravel. Over the next couple of posts, I’ll write about how to build these features in JHipster, a code-generation package that you can install as a Yeoman generator. That feature-richness is, of course, both a blessing and a curse. You can get an app up-and-running in minutes, but it does admittedly generate a huge  amount of code and consume a lot of memory on your development machine. Still, I feel that JHipster is very useful for prototyping  applications in Java + Angular, and that the  code may be verbose, but it’s also so explicit and readable that you can use it to learn a lot of programming  best practices.

Getting Started

Because JHipster is a Yeoman  generator, you’ll first need to ensure that you have Yeoman  installed. From your terminal, you can install it with npm or yarn. I’ll use yarn:

yarn global add yo

Once you have Yeoman installed, you can  install the JHipster code generator:

yarn global add generator-jhipster

Now you’ll need a directory for your application code. Create one, change into it, and run the JHipster generator.

mkdir petfood-info

cd petfood-info

jhipster

The JHipster generator will then prompt you for a few questions. When it asks what *type* of application you  want to create, choose “Monolithic application.” When it asks for the base name of your application, type what you want,but make sure not to use special characters or spaces. I’ll use “mypetfooddb”. Type a unique Java package name for yourself. I’ll use “com.vinvasir.mypetfooddb”. Select “JWT Authentication” when it asks what *type* of authentication you’d like to use. Select “SQL” for your type of database. Select “MySQL” for the *production* database and the *development* database. Select Maven as the build tool. Finally, select Angular 6 (or whatever the latest version available to you is) as your frontend framework, and SASS as a CSS pre-processor.

Once the CLI lets you know that it’s finished installing  all the dependencies, open up the project in your favorite IDE. Open up src/main/resources/config/application-dev.yml and take a look at the properties nested under “datasource.” You should see a username of “root” and a blank password. You will probably have to change these values. For example, if your local MySQL user is name “user” and the password is “password,” you should  enter those values here.

You should also make sure that database name, which is “mypetfooddb” in the datasourc.url property, actually exists on your local machine. Open up the MySQL CLI with the command below. Make sure to substitute in a valid username:

sudo -u <your username> mysql -p

You may then be prompted for your Unix user’s password. Make sure to enter that in correctly. Eventually, you’ll be prompted for the MySQL user’s password. Enter in the correct value, and you’ll  see the CLI start up. You can then create your database with this command:

CREATE DATABASE IF NOT EXISTS mypetfooddb;

Verify that the database exists with this command:

SHOW DATABASES;

You may then exit the MySQL CLI by pressing ctrl + D, or cmd + D on a Mac.

With your database settings ready to go, start up your application by running “./mvnw”. In a separate terminal, start up the front-end Webpack hot reload development server with “yarn start”. If all went well, you’ll now see a landing page with the title “Welcome, Java Hipster!”

Your application already has a users table with some authorization roles set up. In the upper right portion of the navbar, click “sign in,” and then enter in the username “admin” and the password “admin”. You’ll now be able to a blank navbar area for “Entities,” and a feature-rich area for “administration.” Under “administration,” you can click on “user management” to change other users’ roles. This is great for when you start registering real accounts and don’t want to use the built-in admin and user accounts with their easily guessable passwords.

At this point, you’ve already come a long way! You’ve created a robust single-page web application with user authentication and authorization, monitoring, audits, logs, and swagger-based API documentation. Feel free to explore the app and take it all in, as we prepare for Part Two, where we’ll add the Entities and CRUD features that will make this app unique!