Level 7 - Milestone 5

Milestone 5 - The Service Layer

This milestone is dedicated to the service package, and adding a service layer class for our application

Before completion of this milestone, students will:

  • Add a service-layer class for their application
  • Add a method that is called from the controller class

Add a Service Class

Create a packaged named "service" at the same level as the presentation package. Service-layer classes contain all of the "business logic" of the application. Perhaps one of the best ways to describe what the service layer contains, is by describing what it doesn't do. Remember that the controller classes are used to simply map request URLs to the method that we want called when they are hit, and the repository layer is responsible for simply retrieving a piece of data; all other code belongs in the service layer.

The @Service is a stereotype annotation for @Component. @Service tells us humans that this class is a service-layer class, but is functionally the same as @Component: it allows Spring to recognize this class during component scanning, and therefore handle the instantiation of this class for us.

For now, we will just move the simple functionality from our controller class down into the service layer. Having done this, your service class will look similar to this:

package org.jointheleague.api.cheetah.Cheetah_Search.service;

import org.springframework.stereotype.Service;

@Service
public class LocService {

    public String getResults(String query){
        return "Searching for books related to " + query;
    }

}

Connecting the Controller and Service class

We now need to have the method in our controller class call the method in our service class. Remember that the big picture is our controller class receives a request which is passed to the service layer. The service layer will, in turn, call a method in a repository-layer class to retrieve the relevant data, which will then be returned all the back up through the classes to the user.

Before we can call the method in our service layer, we need to give the controller class an instance of the service class to work with. Luckily Spring makes this easy for us. Because of the Spring's dependency injection, we will not use the "new" keyword to instantiate any of our controller, service, or repository layer classes, Spring handles that for us. In this case, all we need to do is add field for the service class in the controller, and provide a constructor that takes that service class as a parameter. Again, Spring will take it from there and actually supply the controller class with an instance of the service class when the controller class itself is automatically instantiated by Spring.

Your controller class should now look something like this:

package org.jointheleague.api.cheetah.Cheetah_Search.presentation;

import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import org.jointheleague.api.cheetah.Cheetah_Search.service.LocService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class LocController {

    private final LocService locService;

    public LocController(LocService locService) {
        this.locService = locService;
    }

    @GetMapping("/searchLocResults")
    @ApiOperation(value = "Searches for articles matching the search term",
            notes = "Response may include multiple Result values.",
            response = String.class)
    @ApiResponses(value = {
            @ApiResponse(code = 200, message = "Result(s) found"),
            @ApiResponse(code = 404, message = "Result(s) not found")
    })
    public String getResults(@RequestParam(value="q") String query){
        return locService.getResults(query);
    }

}

Our Use of the Service Layer

Given the desired functionality of our application, our service class will remain rather sparse. However, if we wanted to manipulate data or process it in any way, we would add code to handle that within the service layer. Another common scenario handled by the service layer is converting our data into a specific "domain object" that we intend to return to our user in a certain format. Domain objects are especially useful when combining information from multiple sources into a singular format, which allows us to return a uniform set of data to the user.

Summary of Code Changes for this Milestone

    Cheetah-Search
    • src
      • main
        • java
    • build.gradle