Building an Application with Spring Boot | PART 2

In The previous post Getting Started · Building an Application with Spring Boot  We have already created a basic spring-boot application. Now here we will re-factor the code step by step to create a more concise application. 

In our previous example we have created a simple StudentAPI Rest Controller, which is responsible for creating the student dummy database, initialize our spring-boot application and also searching for the Student Object. But in real life example, The structure of an application will be different. 

The Controller should be responsible for handling the HTTP Requests and generating the Response. Where as the Search activity from a database should be performed by a service. Initializing the spring-boot application should be a responsibility of an Application level class. Please remember your Application level class should be at the top level package. Thus it can scan all the annotations below. Other wise you need to mention the component scan packages name manually to allow spring to read the annotations from the location. The following diagram is showing our updated package structure.

Our Application level class StudentSearchApplication is in package com.tuturself.spring.boot. And all the Controllers and Services are one level below. 

  • Controllers are in com.tuturself.spring.boot.api
  • Services are in com.tuturself.spring.boot.service

For this spring will automatically read the @RestController or @Service annotations defined in Controller and Service Classes.

It is also considered best practice to put exposed beans in configuration classes, which are logically grouped.For example, you might have several configuration classes with a number of beans contained within each. Here we create the bean in Main application class just for simplicity.

Now following is our Application level class, which is initializing the spring-boot application and also registering a bean.

package com.tuturself.spring.boot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

import com.tuturself.spring.boot.service.StudentService;

@SpringBootApplication
public class StudentSearchApplication {

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

	/**
	 * It is generally considered best practice to put exposed beans in
	 * configuration classes, which are logically grouped.
	 * 
	 * For example, you might have several configuration classes with a number
	 * of beans contained within each. Here we create the bean in Main class
	 * just for simplicity
	 */
	@Bean
	public StudentService studentService() {
		return new StudentService();
	}
}

Following is the @RestController. Here in this Controller we are Autowiring the StudentService which we have created in our Application level class StudentSearchApplication

package com.tuturself.spring.boot.api;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.tuturself.spring.boot.model.Student;
import com.tuturself.spring.boot.service.StudentService;

@RestController
public class StudentAPI {

	@Autowired
	private StudentService studentService;

	@RequestMapping("/students")
	public Student searchStudent(@RequestParam(name = "studentId", required = true) 
                Integer studentId) {
		Student student = studentService.getStudentById(studentId);
		return student;
	}
}

Now let us check the service, which is searching for the Student Object from the database. Here we have used Fairy , which is a fake data generator service in Java to create some dummy Student Objects. To read more about Fairy click here. At @PostConstruct the dummy Student database will be populated.  @PostConstruct get called automatically when the bean initialization completed. To read more about spring lifecycle callbacks like @PostConstruct read here.

package com.tuturself.spring.boot.service;

import com.tuturself.spring.boot.model.Student;
import org.jfairy.Fairy;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.Map;

@Service
public class StudentService {

	private static Map<Integer, Student> studentDB;

	private Fairy fairy = Fairy.create();

	@PostConstruct
	public void init() throws Exception {
		studentDB = new HashMap<>();
		for (int i = 0; i < 100; i++) {
			Student student = new Student(i,fairy.person());
			studentDB.put(new Integer(i), student);
		}
	}

	public Student getStudentById(Integer studentId) {
		return studentDB.get(studentId);
	}
}

Following is our Student representation POJO class:

package com.tuturself.spring.boot.model;

import org.jfairy.producer.person.Address;
import org.jfairy.producer.person.Person;
import org.jfairy.producer.person.Person.Sex;
import org.joda.time.DateTime;

public class Student {

	private Integer studentId;
	private Address address;
	private String firstName;
	private String middleName;
	private String lastName;
	private String email;
	private Sex sex;
	private String telephoneNumber;
	private DateTime dateOfBirth;
	private Integer age;
	private String companyEmail;
	private String nationalIdentityCardNumber;
	private String nationalIdentificationNumber;

	public Student(int studentId, Person p) {
		this.studentId = studentId;
		this.nationalIdentityCardNumber = p.nationalIdentificationNumber();
		this.address = p.getAddress();
		this.firstName = p.firstName();
		this.middleName = p.middleName();
		this.lastName = p.lastName();
		this.email = p.email();
		this.sex = p.sex();
		this.telephoneNumber = p.telephoneNumber();
		this.dateOfBirth = p.dateOfBirth();
		this.age = p.age();
		this.nationalIdentificationNumber = p.nationalIdentificationNumber();
		this.companyEmail = p.companyEmail();
	}

	public Integer getStudentId() {
		return studentId;
	}

	public Address getAddress() {
		return address;
	}

	public String getFirstName() {
		return firstName;
	}

	public String getMiddleName() {
		return middleName;
	}

	public String getLastName() {
		return lastName;
	}

	public String getEmail() {
		return email;
	}

	public Sex getSex() {
		return sex;
	}

	public String getTelephoneNumber() {
		return telephoneNumber;
	}

	public DateTime getDateOfBirth() {
		return dateOfBirth;
	}

	public Integer getAge() {
		return age;
	}

	public String getCompanyEmail() {
		return companyEmail;
	}

	public String getNationalIdentityCardNumber() {
		return nationalIdentityCardNumber;
	}

	public String getNationalIdentificationNumber() {
		return nationalIdentificationNumber;
	}
}

And After adding all the required dependency following is the updated pom.xml file.

<?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.tuturself</groupId>
    <artifactId>spring.boot</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.1.RELEASE</version>
    </parent>

    <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>
        <dependency>
            <groupId>com.jayway.jsonpath</groupId>
            <artifactId>json-path</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.jfairy</groupId>
            <artifactId>jfairy</artifactId>
            <version>0.3.0</version>
        </dependency>
    </dependencies>

    <properties>
        <java.version>1.8</java.version>
    </properties>


    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

    <repositories>
        <repository>
            <id>spring-releases</id>
            <url>https://repo.spring.io/libs-release</url>
        </repository>
    </repositories>
    <pluginRepositories>
        <pluginRepository>
            <id>spring-releases</id>
            <url>https://repo.spring.io/libs-release</url>
        </pluginRepository>
    </pluginRepositories>

</project>

Now the spring-boot application looks more real. And extendable. We will extend it further to explain several annotations, interceptors, filters, real life databases connection, property files, yml files, service discovery by spring cloud one by one. Be with us for more tutorial and Happy learning.

To download the complete code from GitHub Click Here

spring 12 spring-social 12

FOLLOW US ON LinkedIn



Explore Tutu'rself