Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Creating a Simple Web App With Java 8, Spring Boot, and Angular

DZone's Guide to

Creating a Simple Web App With Java 8, Spring Boot, and Angular

In this tutorial, we'll look at how developers can combine multiple technologies to make a web application. Read on to get started!

· Web Dev Zone ·
Free Resource

Deploy code to production now. Release to users when ready. Learn how to separate code deployment from user-facing feature releases with LaunchDarkly.

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.

Backdrop

In this article, I will try to create a small end-to-end web application using Java 8 and SpringBoot.

I have chosen SpringBoot because it is much easier to configure and plays well with other tech stacks. I have also used a REST API and SpringData JPA with an H2 database.

I used Spring Initializer to add all the dependencies and create a blank working project with all my configurations.

I have used Maven as the build tool, though Gradle can also be used.

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<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

package structure

package structure contd.

Implementation

Let's start with the SpringBootApplication class.

@SpringBootApplication
public class BootDemoApplication {
 @Autowired
 UserRepository userRepository;

 public static void main(String[] args) {
  SpringApplication.run(BootDemoApplication.class, args);
 }
}

Let's create Controllers now. 

@Controller
public class HomeController {
 @RequestMapping("/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.

@RequestMapping("/user")
@RestController
public class UserController {
 @Autowired
 UserService userService;

 @RequestMapping(Constants.GET_USER_BY_ID)
 public UserDto getUserById(@PathVariable Integer userId) {
  return userService.getUserById(userId);
 }

 @RequestMapping(Constants.GET_ALL_USERS)
 public List < UserDto > getAllUsers() {
  return userService.getAllUsers();
 }

 @RequestMapping(value = Constants.SAVE_USER, method = RequestMethod.POST)
 public void saveUser(@RequestBody 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 {
 @Autowired
 UserRepository userRepository;

 @Override
 public UserDto getUserById(Integer userId) {
  return UserConverter.entityToDto(userRepository.getOne(userId));
 }

 @Override
 public void saveUser(UserDto userDto) {
  userRepository.save(UserConverter.dtoToEntity(userDto));
 }

 @Override
 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

@Entity
public class User implements Serializable{

    private static final long serialVersionUID = 0x62A6DA99AABDA8A8L;

@Column
@GeneratedValue(strategy = GenerationType.AUTO)
@Id
private Integer userId;
    @Column
    private String userName;
    @OneToMany(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;
    }
}

@Entity
public class Skill {
    @Column
@GeneratedValue(strategy = GenerationType.AUTO)
@Id
private Integer skillId;
    @Column
    private String skillName;
    @ManyToOne
    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:

@Repository
public interface UserRepository extends JpaRepository<User, Integer>{
}

@Repository
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

<!DOCTYPE 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.

Image title

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 using

java -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.

Image title

 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.

Deploy code to production now. Release to users when ready. Learn how to separate code deployment from user-facing feature releases with LaunchDarkly.

Topics:
java 8 ,springboot ,bootstrap 3 ,web dev ,angular js

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}