Creating a Simple Web
App With Java 8, Spring Boot, and Angular
Pre-Requisites
for Getting Started
·
Java 8 is installed.
·
Any Java IDE (preferably STS or IntelliJ IDEA).
·
Basic understanding of Java and Spring-based web development and
UI development using HTML, CSS, and JavaScript.
Pre-Requisites
for Getting Started
·
Java 8 is installed.
·
Any Java IDE (preferably STS or IntelliJ IDEA).
·
Basic understanding of Java and Spring-based web development and
UI development using HTML, CSS, and JavaScript.
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>bootdemo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>bootDemo</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.3.RELEASE</version>
<relativePath />
<!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.restdocs</groupId>
<artifactId>spring-restdocs-mockmvc</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
In
the UI part, I have used AngularJS and BootStrap CSS along with basic JS,
CSS, and HTML.
I
tried to follow the coding guidelines as much as I could, but all suggestions
are welcome.
This
is a very simple project which can be useful for creating an end-to-end
web application.
Package Structure


Implementation
Let's
start with the SpringBootApplication class.
public class BootDemoApplication {
UserRepository userRepository;
public static void main(String[] args) {
SpringApplication.run(BootDemoApplication.class, args);
}
}
Let's
create Controllers now.
public class HomeController {
("/home")
public String home() {
return "index";
}
}
This
will act as the homepage for our SPA. Now we create a Controller to handle some
REST calls.
("/user")
public class UserController {
UserService userService;
(Constants.GET_USER_BY_ID)
public UserDto getUserById( Integer userId) {
return userService.getUserById(userId);
}
(Constants.GET_ALL_USERS)
public List < UserDto > getAllUsers() {
return userService.getAllUsers();
}
(value = Constants.SAVE_USER, method = RequestMethod.POST)
public void saveUser( UserDto userDto) {
userService.saveUser(userDto);
}
}
Here
we have different methods to handle different test calls from the client side.
I
have Autowired a Service class, UserService,
in the Controller.
public interface UserService {
UserDto getUserById(Integer userId);
void saveUser(UserDto userDto);
List < UserDto > getAllUsers();
}
@Service
public class UserServiceimpl implements UserService {
UserRepository userRepository;
public UserDto getUserById(Integer userId) {
return UserConverter.entityToDto(userRepository.getOne(userId));
}
public void saveUser(UserDto userDto) {
userRepository.save(UserConverter.dtoToEntity(userDto));
}
public List < UserDto > getAllUsers() {
return userRepository.findAll().stream().map(UserConverter::entityToDto).collect(Collectors.toList());
}
}
In
a typical web application, there are generally two types of data objects: DTO
(to communicate through the client) and Entity (to communicate through the DB).
DTO
public class UserDto {
Integer userId;
String userName;
List<SkillDto> skillDtos= new ArrayList<>();
public UserDto(Integer userId, String userName, List<SkillDto> skillDtos) {
this.userId = userId;
this.userName = userName;
this.skillDtos = skillDtos;
}
public UserDto() {
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public List<SkillDto> getSkillDtos() {
return skillDtos;
}
public void setSkillDtos(List<SkillDto> skillDtos) {
this.skillDtos = skillDtos;
}
}
public class SkillDto {
Integer skillId;
String SkillName;
public SkillDto(Integer skillId, String skillName) {
this.skillId = skillId;
SkillName = skillName;
}
public SkillDto() {
}
public Integer getSkillId() {
return skillId;
}
public void setSkillId(Integer skillId) {
this.skillId = skillId;
}
public String getSkillName() {
return SkillName;
}
public void setSkillName(String skillName) {
SkillName = skillName;
}
}
Entity
public class User implements Serializable{
private static final long serialVersionUID = 0x62A6DA99AABDA8A8L;
(strategy = GenerationType.AUTO)
private Integer userId;
private String userName;
(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private List<Skill> skills= new LinkedList<>();
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public List<Skill> getSkills() {
return skills;
}
public void setSkills(List<Skill> skills) {
this.skills = skills;
}
public User() {
}
public User(String userName, List<Skill> skills) {
this.userName = userName;
this.skills = skills;
}
}
public class Skill {
(strategy = GenerationType.AUTO)
private Integer skillId;
private String skillName;
private User user;
public Skill(String skillName) {
this.skillName = skillName;
}
public Integer getSkillId() {
return skillId;
}
public void setSkillId(Integer skillId) {
this.skillId = skillId;
}
public String getSkillName() {
return skillName;
}
public void setSkillName(String skillName) {
this.skillName = skillName;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Skill() {
}
public Skill(String skillName, User user) {
this.skillName = skillName;
this.user = user;
}
}
For
DB operations, we use SpringData JPA:
public interface UserRepository extends JpaRepository<User, Integer>{
}
public interface SkillRepository extends JpaRepository<Skill, Integer>{
}
Extending
JpaRepository
provides
a lot of CRUD operations by default, and one can use it to create their
own query methods as well. Please read more about this here.
To
convert DTO -> Entity and Entity -> DTO, I created some basic converter
classes.
public class UserConverter {
public static User dtoToEntity(UserDto userDto) {
User user = new User(userDto.getUserName(), null);
user.setUserId(userDto.getUserId());
user.setSkills(userDto.getSkillDtos().stream().map(SkillConverter::dtoToEntity).collect(Collectors.toList()));
return user;
}
public static UserDto entityToDto(User user) {
UserDto userDto = new UserDto(user.getUserId(), user.getUserName(), null);
userDto.setSkillDtos(user.getSkills().stream().map(SkillConverter::entityToDto).collect(Collectors.toList()));
return userDto;
}
}
public class SkillConverter {
public static Skill dtoToEntity(SkillDto SkillDto) {
Skill Skill = new Skill(SkillDto.getSkillName(), null);
Skill.setSkillId(SkillDto.getSkillId());
return Skill;
}
public static SkillDto entityToDto(Skill skill) {
return new SkillDto(skill.getSkillId(), skill.getSkillName());
}
}
Let's
focus on the UI part now.
While
using Angular, there are certain guidelines we need to follow.
index.html
<html>
<head>
<meta charset="ISO-8859-1">
<title>Main Page</title>
</head>
<body ng-app="demo">
<hr/>
<div class="container" ng-controller="UserController">
<div class="row">
<label>User</label> <input type="text" ng-model="userDto.userName" class="input-sm spacing"/>
<label>Skills</label> <input type="text" ng-model="skills" ng-list class="input-sm custom-width spacing"
placeholder="use comma to separate skills"/>
<button ng-click="saveUser()" class="btn btn-sm btn-info">Save User</button>
</div>
<hr/>
<div class="row">
<p>{{allUsers | json}}</p>
</div>
<hr/>
<div class="row" ng-repeat="user in allUsers">
<div class="">
<h3>{{user.userName}}</h3>
<span ng-repeat="skill in user.skillDtos" class="spacing">{{skill.skillName}}</span>
</div>
</div>
</div>
</body>
<script src="js/lib/angular.min.js"></script>
<script src="js/lib/ui-bootstrap-tpls-2.5.0.min.js"></script>
<script src="js/app/app.js"></script>
<script src="js/app/UserController.js"></script>
<script src="js/app/UserService.js"></script>
<link rel="stylesheet" href="css/lib/bootstrap.min.css"/>
<link rel="stylesheet" href="css/app/app.css"/>
</html>
While
creating the HTML, don't forget to import the required JS and CSS
files.

app.js
'use strict'
var demoApp = angular.module('demo', ['ui.bootstrap', 'demo.controllers',
'demo.services'
]);
demoApp.constant("CONSTANTS", {
getUserByIdUrl: "/user/getUser/",
getAllUsers: "/user/getAllUsers",
saveUser: "/user/saveUser"
});
UserController.js
'use strict'
var module = angular.module('demo.controllers', []);
module.controller("UserController", ["$scope", "UserService",
function($scope, UserService) {
$scope.userDto = {
userId: null,
userName: null,
skillDtos: []
};
$scope.skills = [];
UserService.getUserById(1).then(function(value) {
console.log(value.data);
}, function(reason) {
console.log("error occured");
}, function(value) {
console.log("no callback");
});
$scope.saveUser = function() {
$scope.userDto.skillDtos = $scope.skills.map(skill => {
return {
skillId: null,
skillName: skill
};
});
UserService.saveUser($scope.userDto).then(function() {
console.log("works");
UserService.getAllUsers().then(function(value) {
$scope.allUsers = value.data;
}, function(reason) {
console.log("error occured");
}, function(value) {
console.log("no callback");
});
$scope.skills = [];
$scope.userDto = {
userId: null,
userName: null,
skillDtos: []
};
}, function(reason) {
console.log("error occured");
}, function(value) {
console.log("no callback");
});
}
}
]);
UserService.js
'use strict'
angular.module('demo.services', []).factory('UserService', ["$http", "CONSTANTS", function($http, CONSTANTS) {
var service = {};
service.getUserById = function(userId) {
var url = CONSTANTS.getUserByIdUrl + userId;
return $http.get(url);
}
service.getAllUsers = function() {
return $http.get(CONSTANTS.getAllUsers);
}
service.saveUser = function(userDto) {
return $http.post(CONSTANTS.saveUser, userDto);
}
return service;
}]);
app.css
body{
background-color: #efefef;
}
span.spacing{
margin-right: 10px;
}
input.custom-width{
width: 200px;
}
input.spacing{
margin-right: 5px;
}
The
application can be built using:
mvn clean
install
then run as a runnable jar file by usingjava -jar
bootdemo-0.0.1-SNAPSHOT.jar
or running the main file
directly.
Open the browser and hit http://localhost:8080/home
One simple page will open. Enter
the name and skills and the entered data will be persisted in the DB.

In the
application.properties files, two configurations are to be added.
spring.mvc.view.prefix = /views/
spring.mvc.view.suffix = .html
The
source code can be cloned or downloaded from here.
Thanks for sharing this informative content , Great work
ReplyDeleteLeanpitch provides online training in Agile coach during this lockdown period everyone can use it wisely.
Certified agile coaching Bangalore
Thanks for sharing this informative content , Great work
ReplyDeleteCreative Thinking for creating an impact!
Product Thinking Community introduces PT Labs powered by Leanpitch
Product thinking conference
Thanks for sharing this informative content , Great work
ReplyDeleteLeanpitch provides online training in advanced scrum master during this lockdown period everyone can use it wisely.
Advanced CSM training online
Thanks for sharing this informative content , Great work
ReplyDeleteTo crack Scrum master interview : Scrum Master Interview Questions