Controllers and Services with Spring Boot

In this article I will show:

  • The Controllers and Services with Spring Boot
  • The dependency injection with Spring Boot
  • And the 3-tiers architecture explained

Check the following video for more details.

All the code of this article is available in the following repository.

In a previous article, I’ve already created this Spring Boot application from scratch. Now I will add some endpoints and services to handle the requests.

The 3-tiers architecture

Let’s start with the 3-tiers architecture. What’s the 3-tires architecture? We divided our application into 3-tiers, 3 layers: 

  • the presentation layer; 
  • the logic layer;
  • and the data layer. 

The presentation layer

The presentation layer will have the data to be shown. As we divided the website into frontend and backend application, the frontend belongs to the presentational, but in the backend application we can also prepare the data to be sent to the frontend this part is the controller’s part.

The controller have the endpoints to call from the frontend. And we call the different services to build the expected result for the fronted application. 

The logic layer

The logic layer, by its name, contains the logic of the application. The business logic. This part has the services. In our case, for a social network website, it contains the logic to fetch the adequate messages to be displayed to a user, the images to be displayed, how to create the connections when adding a new friend, or posting a message. 

The data layer

And finally the data layer which contains the structure of the data. How the data will be stored in the database and how the data will be fetched from the database. This is called the data part. 

The Controllers and Services

Let’s go now with the controller. As I sad in the beginning, the application I’m building is the backend of a social network. So, I will create two controllers. The community controller, for the community information, which is handling the messages and images, and posting the messages and images. And the user controller which handles the users.
To search the users, displaying a user profile, add friend requests. And now, how do I tell Spring that those are controllers. With a single annotation.

@RestController
@RequestMapping("/v1/community")
public class CommunityController {

Nothing more. I could have added the annotation @Controller, but this one also has the @RequestBody annotation, which tells that all the endpoints will have a response body. As I have separated the backend and the frontend application, the frontend will contain all the displayed information, the HTML, Javascript and CSS. And the backend, the business information. 

The backend will feed the frontend with compressed information, not with HTML. The responses from the backend will be sent in JSON. With the @ResponseBody annotation, Spring understands that all the end points will return the data in a JSON format. Only a single annotation, the @RestController to configure all of this.

Next step, make the controller to accept HTTP requests. The frontend requests will enter into the backend application, search for requested information and return the expected result. Let’s use an example. When loading the home page of the social network, I want all the messages of the community to be displayed. I want that when the frontend code gets all messages, all the community messages will be returned. 

Why /v1?

This will be useful with different versions of a mobile application.

As this controller will handle all the entry points for the community requests, I start with the annotation the @RequestMapping with the prefix v1. Then specify the end at each entry point. The first one get the community messages. I can use @RequestMapping again with the method I want, GET, or @GetMapping directly. The second one, for the community images.

@GetMapping("/messages")
public ResponseEntity<List<MessageDto>> getCommunityMessages(
        @RequestParam(value = "page", defaultValue = "0") int page) {
    return ResponseEntity.ok(communityService.getCommunityMessages(page));
}

@GetMapping("/images")
public ResponseEntity<List<ImageDto>> getCommunityImages(
        @RequestParam(value = "page", defaultValue = "0") int page) {
    return ResponseEntity.ok(communityService.getCommunityImages(page));
}

@PostMapping("/messages")
public ResponseEntity<MessageDto> postMessage(@RequestBody MessageDto messageDto) {
    return ResponseEntity.created(URI.create("/v1/community/messages"))
            .body(communityService.postMessage(messageDto));
}

@PostMapping("/images")
public ResponseEntity<ImageDto> postImage(@RequestParam MultipartFile file,
                                          @RequestParam(value = "title") String title) {
    return ResponseEntity.created(URI.create("/v1/community/images"))
            .body(communityService.postImage(file, title));
}

Then, post a message and finally post an image. The same will be done for the user controller. You can check the result in the Github project.

Ok I have the HTTP request which enters in my application but I need to return something. But what’s the ResponseEntity? It takes as generic the class which will be returned,  and contains also the status of the HTTP response, and some other informations.

I created all of those classes into a package dto, which means Data Transfer Object. Those are classes used to send and receive information. This way, I separate the presentation object, in the DTO package, and the database structure, in the data package. It’s a security layer to hide information, to avoid publishing critical information from the data layer.

And how do I accept incoming parameters in those entry points?

For the first and second entry point, I want the information about the page. I don’t want to load all the messages of the database. Because it could be thousands and thousands of elements. So, the frontend has to say which page it want, the first, the second, etc.

So I use the annotation @RequestParam.

And for the third, I need a more complex object as I want a message to be stored in the database. And in the last one, I want an image to be uploaded, with the title of the image. I will use @RequestBody

Now I will create this services.

Same question, how do i identify that those are services? With the annotation @Service, nothing more. 

@Servicepublic class CommunityService {

Let’s start with community service.

public List<MessageDto> getCommunityMessages(int page) {
    return Arrays.asList(new MessageDto(1L, "First message"),
            new MessageDto(2L, "Second message"));
}

public List<ImageDto> getCommunityImages(int page) {
    return Arrays.asList(new ImageDto(1L, "First title", null),
            new ImageDto(2L, "Second title", null));
}

public MessageDto postMessage(MessageDto messageDto) {
    return new MessageDto(3L, "New message");
}

public ImageDto postImage(MultipartFile file, String title) {
    return new ImageDto(3L, "New Title", null);
}

I will leave them empty for now. As I need to search in the database the data. But I haven’t configured yet the database. So I will going to answer some hardcoded response.

The dependency injection

Okay, both controllers and services ready. How do I make the connection? How to use the dependency injection?

If take a look at the @Service annotation it inherits from @Component. The same for the @Controller annotation, it inherits from @Component. Spring will look for all those classes annotated with the @Component annotation and register them. This is done in the main class because of the @SpringBootApplication annotation. Having both the controllers and the services in this internal list of Spring, how do I use them?

We need the CommunityService to be used in the CommunityController. Create the constructor with the service as a mandatory field.

private final CommunityService communityService;

public CommunityController(CommunityService communityService) {
    this.communityService = communityService;
}

This will set the instance of the service and that’s all. Spring, when building the controller, will take a look at the input parameters, search for this class in the internal list, and inject it. That’s all! I only need the @Component annotation and the constructor. That’s how the dependency injection works. 

That’s all for this article. I will continue with the authentication and the several filters in the next article.

You can find the code in the following link. And feel free to follow me in the social networks.

All the code of the article is available in the following repository.


Never Miss Another Tech Innovation

Concrete insights and actionable resources delivered straight to your inbox to boost your developer career.

My New ebook, Best Practices To Create A Backend With Spring Boot 3, is available now.

Best practices to create a backend with Spring Boot 3

One response to “Controllers and Services with Spring Boot”

  1. […] a previous article, I’ve already added some controllers and services. But the are unprotected. Now, I need to […]

    Like

Leave a reply to Spring Security and JWT – The Dev World – by Sergio Lema Cancel reply

Discover more from The Dev World - Sergio Lema

Subscribe now to keep reading and get access to the full archive.

Continue reading