Get familiar with the Spring Initializr interface by creating a simple Spring Boot Web application.

Time: 25 minutes.

Directory Web App

  1. Open a browser and hit the url: http://start.spring.io

  2. Click the Switch to the full version link.

  3. Fill out the Directory Web App Project metadata with (See Figure 1.0):

    Table 1. Directory Web App - metadata
    Property Value

    Group:

    io.pivotal.workshop

    Artifact:

    directory-web

    Name:

    directory-web

    Package Name:

    io.pivotal.workshop.directory

    Dependencies:

    Web

    Spring Boot:

    2.0.0.M7

    Figure 1.0: Spring Initializr - http://start.spring.io

    SpringInitializr

    Tip
    You can choose either Maven or Gradle project types.
  4. Type Web in the Dependencies field and press Enter.

  5. Click the Generate Project button.

  6. Unzip the file in any directory you want.

  7. Import your project in any IDE you want.

  8. Once imported, review the pom.xml file (or build.gradle).

    maven - 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>io.pivotal.workshop</groupId>
            <artifactId>directory-web-app</artifactId>
            <version>0.0.1-SNAPSHOT</version>
            <packaging>jar</packaging>
    
            <name>directory-web-app</name>
            <description>Demo project for Spring Boot</description>
    
            <parent>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-parent</artifactId>
                    <version>2.0.0.RC1</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-web</artifactId>
                    </dependency>
    
                    <dependency>
                            <groupId>org.springframework.boot</groupId>
                            <artifactId>spring-boot-starter-test</artifactId>
                            <scope>test</scope>
                    </dependency>
            </dependencies>
    
            <build>
                    <plugins>
                            <plugin>
                                    <groupId>org.springframework.boot</groupId>
                                    <artifactId>spring-boot-maven-plugin</artifactId>
                            </plugin>
                    </plugins>
            </build>
    
        <repositories>
                    <repository>
                            <id>spring-milestones</id>
                            <name>Spring Milestones</name>
                            <url>https://repo.spring.io/libs-milestone</url>
                            <snapshots>
                                    <enabled>false</enabled>
                            </snapshots>
                    </repository>
            </repositories>
    
    </project>

    Remember the Spring Boot components:

    • spring-boot-starter-parent

    • dependencies: spring-boot-starter-web

    • plugin: spring-boot-maven-plugin

    gradle - build.gradle
    buildscript {
            ext {
                    springBootVersion = '2.0.0.RC1'
            }
            repositories {
                    mavenCentral()
            maven { url "https://repo.spring.io/snapshot" }
                    maven { url "https://repo.spring.io/milestone" }
            }
            dependencies {
                    classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
            }
    }
    
    apply plugin: 'java'
    apply plugin: 'eclipse'
    apply plugin: 'org.springframework.boot'
    apply plugin: 'io.spring.dependency-management'
    
    version = '0.0.1-SNAPSHOT'
    sourceCompatibility = 1.8
    
    repositories {
            mavenCentral()
        maven { url "https://repo.spring.io/snapshot" }
            maven { url "https://repo.spring.io/milestone" }
    }
    
    
    dependencies {
            compile('org.springframework.boot:spring-boot-starter-web')
            testCompile('org.springframework.boot:spring-boot-starter-test')
    }
  9. Create the domain io.pivotal.workshop.directory.domain.Person class.

    io.pivotal.workshop.directory.domain.Person.java
    package io.pivotal.workshop.directory.domain;
    
    import java.text.ParseException;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.UUID;
    
    import javax.validation.constraints.NotNull;
    
    public class Person {
    
            private SimpleDateFormat date = new SimpleDateFormat("yyyy-MM-dd");
    
            private String id;
    
            @NotNull
            private String email;
            @NotNull
            private String name;
            @NotNull
            private String password;
            private Date birthday;
            private Date created;
            private Date modified;
    
            public Person(){
                    this.id = UUID.randomUUID().toString().replaceAll("-", "");
                    this.created = new Date();
                    this.modified = new Date();
            }
    
            public Person(String email, String name, String password, String birthday) {
                    this();
                    this.email = email;
                    this.name = name;
                    this.password = password;
    
                    try {
                            this.birthday = date.parse(birthday);
                    } catch (ParseException e) {
                            this.birthday = null;
                    }
            }
    
            public Person(String email, String name, String password, Date birthday) {
                    this();
                    this.email = email;
                    this.name = name;
                    this.password = password;
                    this.birthday = birthday;
            }
    
            public String getId() {
                    return id;
            }
    
            public void setId(String id) {
                    this.id = id;
            }
    
            public String getEmail() {
                    return email;
            }
    
            public void setEmail(String email) {
                    this.email = email;
            }
    
            public String getName() {
                    return name;
            }
    
            public void setName(String name) {
                    this.name = name;
            }
    
            public String getPassword() {
                    return password;
            }
    
            public void setPassword(String password) {
                    this.password = password;
            }
    
            public Date getBirthday() {
                    return birthday;
            }
    
            public void setBirthday(Date birthday) {
                    this.birthday = birthday;
            }
    
            public Date getCreated() {
                    return created;
            }
    
            public void setCreated(Date created) {
                    this.created = created;
            }
    
            public Date getModified() {
                    return modified;
            }
    
            public void setModified(Date modified) {
                    this.modified = modified;
            }
    
    }
  10. Create the io.pivotal.workshop.directory.repository.DirectoryRepository class. This is you in-memory persistence.

    io.pivotal.workshop.directory.repository.DirectoryRepository.java
    package io.pivotal.workshop.directory.repository;
    
    import java.util.ArrayList;
    import java.util.List;
    
    import org.springframework.stereotype.Repository;
    
    import io.pivotal.workshop.directory.domain.Person;
    
    @Repository
    public class DirectoryRepository {
    
    
            @SuppressWarnings("serial")
            private List<Person> directory = new ArrayList<Person>(){{
            add(new Person("john@email.com","John S","password","1985-11-10"));
                    add(new Person("mike@email.com","Mike H","password","1984-12-02"));
                    add(new Person("dan@email.com","Dan B","password","1983-03-07"));
                    add(new Person("bill@email.com","Bill G","password","1983-06-12"));
                    add(new Person("mark@email.com","Mark S","password","1986-02-22"));
            }};
    
            public Iterable<Person> findAll(){
                    return this.directory;
            }
    
    }
  11. Create the io.pivotal.workshop.directory.controller.DirectoryController class. This will handle your REST API.

    io.pivotal.workshop.directory.controller.DirectoryController.java
    package io.pivotal.workshop.directory.controller;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import io.pivotal.workshop.directory.domain.Person;
    import io.pivotal.workshop.directory.repository.DirectoryRepository;
    
    @RestController
    public class DirectoryController {
    
            private DirectoryRepository repo;
    
            @Autowired
            public DirectoryController(DirectoryRepository repo){
                    this.repo = repo;
            }
    
            @RequestMapping("/directory")
            public ResponseEntity<Iterable<Person>> findAll(){
                    return ResponseEntity.ok(this.repo.findAll());
            }
    
    
    }
  12. Run your application and test the /directory endpoint by open a browser and hit: http://localhost:8080/directory

Tip
If you are not using any IDE, then you can run your application with maven: ./mvnw spring-boot:run or if you are using gradle: ./gradlew bootRun

Challenges

So far this is a very simple application, but still missing some of the HTTP request methods:

  • Add a index.html page to be render as Home page (tip: src/main/resources/static).

  • Add the POST method for adding a new person (tip: Use the @RequestBody annotation).

  • Add the PUT method for updating a new person (tip: Use the @RequestBody annotation).

  • Add the DELETE method for removing a person by id (tip: Use the @PathVariable annotation).

  • Add a GET method for search by email (tip: Use the @RequestParam annotation).

  • Add a GET method for finding by Id (tip: Use the @PathVariable annotation).

do any necessary changes to the classes.

[EXTRA - OPTIONAL] Challenges

  • Mask the password when getting a directory JSON object.

  • The /directory endpoint response as a JSON object and the dates are show as a long type. Modify it to get a formatted 'yyyy-MM-dd' date.

  • By default Spring Boot serialize automatically a JSON object, add a XML serialization too.

HOMEWORK

  • Add validation to the Person object when doing POST or UPDATE.