Healthy Habits is a Spring application that allows users to go to a website, make an account, enter habits and behaviors they would like to track, and view those on a graph so they can see their progress over time.
My main goal with this project is to display my competence as a developer and I was looking for a realistic project I could build by myself that would combine all of what I'd been learning about programming and software. The use-case goal of this application is to help users track their behaviors in a way that is insightful and helpful for their progress as individuals. I personally use it and have found that it helps me achieve my goals faster, and motivates me in the process.
The application follows a MVC design pattern using Spring to achieve the end-goal for the application. Along with Spring, Hibernate is used to store persistent data in a MySQL database. Thymeleaf works in conjuction with the view layer to display models that are sent and received between the user's view and the server. This allows the user to generate content and visualize that content in a meaningful way.
Spring Security is used to authenticate users and BCrypt is used to encrypt passwords that are sent by the client. Spring Security allows the program to require authorization for users to access certain pages. In order to be authorized, the user must have an account and be logged in to it. If the client accessing an authorized-only web-page is not logged in to a valid account, they cannot access it.
The application is separated into 5 different sub-packages. This makes it easy to navigate and understand for both myself and any other developers who would potentially be working with it.
There are several controllers used in this program. If you want to see them all, feel free to check them out on GitHub.
The HabitsController class enables registered, logged-in users go to the "/habits" url in order to add or remove habits to their account. The class has an autowired field for CustomUserDetailsService that allows it to fetch the authorized user browsing the page, and also one for UserService so users can be saved/updated. There is a get method and a post method for this controller. The get method returns the "habitspage.html" file with two models, habit and user. The post method places the habit model returned in a try block and uses an if-statement to determine if the habit is being added or removed, then triggers the logic necessary to carry out the user's desire. After that, the user is saved and the habitspage is returned if no errors are caught.
The VisualizerController class simply obtains the information needed for two models. The user object contains all of the information needed for the visualizer view. Two models are created instead of one to separate the user and the user's habits for simplicity in the HTML file.
The RegisterController listens on the "/register" url and has a get method and a post method. The get method returns a new User model with the name "user" for Thymeleaf and the register.html page view. The post method obtains the user model that is sent when th e page is submitted. It then uses the DataValidation class to check if the username and password are valid. If they are, then the user's password is set to an encoded password by the PasswordEncoder. Then, the UserService calls the addUser method and passes the user model object. This method's code is in a try-catch block, so if it encounters an error it returns the the error page.
The UserRepository is an interface that extends Spring's CrudRepository of the object type User and id of Integer. The UserService class uses this repository to manipulate the data being stored by the application.
The ApplicationSecurityConfig class is used to configure Spring to behave how it needs to behave to meet our requirements. It customizes two aspects of Spring, the AuthenticationManagerBuilder and HttpSecurity. The AuthManagerBuilder needs to know the right UserDetailsService in order to function properly. Since a custom one is used in this application, the CustomUserDetailsService is autowired and set as the UserDetailsService.
The HttpSecurity configuration method is set to authorize requests on a certain set of pages where it's needed, like login, visualizer, habits and logout. This secures those pages so they cannot be accessed by someone who should not be able to see them.
The CustomUserDetailsService implements Spring's UserDetailsService and overrides the loadByUsername method. This is needed because the UserRepository interfaces locates users bsaed on their unique integer id, not their username. A lambda expression is used to parse through all users to find the one that matches the username that is authorized to view that page.
The UserService fetches and stores data using UserRepository interface. The UserService what is used by other classes and methods when they need to get or store user information, rather than dealing with the interface directly.
The DataValidation class is a utility for checking user-generated inputs to ensure that they meet the requirements and are not malicious, such as inputs containing special characters, or extremely long inputs that would impact server performance and user experience if it happened at a large scale.
There are two classes in the User package: Habit and User. These classes represent the data that is persisted in the application.
The User class is annotated as an Entity so that JPA knows it should be persistent. The class has 5 fields as follows: userId (int), username (String), password (String), roles (String) and habits (List
The Habit class is annotated as an Entity as well. The class has 5 fields that define the different states the habit object can have. The 5 fields are name (String), ratings (ArrayList
The styling includes a couple images to fit the theme of the application and makes the website easy to navigate and use.
Most of the HTML templates are not noteworthy other than the fact that they include Thymeleaf references which allow the view-layer to obtain and display models based on Java classes. The visualizer.html page contains a graph that models user data however, which I will explain below.
Admittedly, figuring out how to display this data in a way that Highcharts understood took a while for me since this was the first project that I dealt with displaying Java-originated objects on a website. I figured it out in the end though and achieved the desired end-result, so that's what matters!
If I were to create the same application again from scratch, it would only take a few hours. A lot of the time spent on this project was trial-and-error and the learning process, which cannot be skipped on the road to mastery. I'm grateful for the growth and understanding that occurred during the development process.