Spring Boot @RestController
last modified July 18, 2023
Spring Boot @RestController tutorial shows how to use the
@RestController
annotation in a Spring application to build a
Restful controller.
Spring is a popular Java application framework and Spring Boot is an evolution of Spring that helps create stand-alone, production-grade Spring based applications easily.
Spring MVC
Spring MVC is the primary web framework built on the Servlet API. It is build on the popular MVC design pattern. MVC (Model-View-Controller) is a software architecture pattern, which separates application into three areas: model, view, and controller. The model represents a Java object carrying data. The view represents the visualization of the data that the model contains. The controller controls the data flow into model object and updates the view when the data changes. It separates the view and model.
Spring Framework 5.0 introduced a parallel reactive stack web framework called Spring WebFlux.
@RestController
@RestController
is a convenience annotation for creating Restful
controllers. It is a specialization of @Component
and is
autodetected through classpath scanning. It adds the @Controller
and @ResponseBody
annotations. It converts the response to JSON or
XML. It does not work with the view technology, so the methods cannot return
ModelAndView
. It is typically used in combination with annotated
handler methods based on the @RequestMapping
annotation.
The ResponseEntity
class represents an HTTP response, including
headers, body, and status. It is used to return data.
The @Controller
annotation is used with the view technology.
Restful application
A RESTFul application follows the REST architectural style, which is used for designing networked applications. RESTful applications generate HTTP requests performing CRUD (Create/Read/Update/Delete) operations on resources. RESTFul applications typically return data in JSON or XML format.
Spring Boot @RestController example
In the following application, we demonstrate the usage of
@RestController
. The application returns a list of cities as JSON
data.
build.gradle ... src ├── main │ ├── java │ │ └── com │ │ └── zetcode │ │ ├── Application.java │ │ ├── controller │ │ │ └── MyController.java │ │ ├── model │ │ │ └── City.java │ │ └── service │ │ ├── CityService.java │ │ └── ICityService.java │ └── resources │ └── application.properties └── test
This is the project structure.
plugins { id 'org.springframework.boot' version '3.1.1' id 'io.spring.dependency-management' version '1.1.0' id 'java' } group = 'com.zetcode' version = '0.0.1-SNAPSHOT' sourceCompatibility = '17' repositories { mavenCentral() } dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' }
This is the Gradle build file. The spring-boot-starter-web
is a
starter for building web, including RESTful, applications using Spring MVC.
spring.main.banner-mode=off
This is the main properties file.
package com.zetcode.model; public record City(Long id, String name, Integer population) {}
This is a City
bean. It has id
, name
, and
population
attributes.
package com.zetcode.controller; import com.zetcode.model.City; import com.zetcode.service.ICityService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; import java.util.List; @RestController public class MyController { private final ICityService cityService; @Autowired public MyController(ICityService cityService) { this.cityService = cityService; } @GetMapping(value = "/cities") public ResponseEntity<List<City>> getCities() { return cityService.findAll(); } @GetMapping(value = "/cities/{id}") public ResponseEntity<City> getCity(@PathVariable("id") int id) { return cityService.findById(id); } }
This is MyController
. It returns a list of cities in JSON format.
@RestController public class MyController {
MyController
is annotated with the @RestController
annotation.
private final ICityService cityService; @Autowired public MyController(ICityService cityService) { this.cityService = cityService; }
We inject the CityService
into the cityService
field.
@GetMapping(value = "/cities") public ResponseEntity<List<City>> getCities() { return cityService.findAll(); }
The getCities
method is mapped to the /cities
URL
pattern; it returns a list of cities, which is converted to JSON by a message
converter.
@GetMapping(value = "/cities/{id}") public ResponseEntity<City> getCity(@PathVariable("id") int id) { return cityService.findById(id); }
The getCity
method returns a single city.
package com.zetcode.service; import java.util.List; import com.zetcode.model.City; import org.springframework.http.ResponseEntity; public interface ICityService { ResponseEntity<List<City>> findAll(); ResponseEntity<City> findById(int id); }
The ICityService
contains the findAll
and
findById
contract methods.
package com.zetcode.service; import com.zetcode.model.City; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.List; @Service public class CityService implements ICityService { private final List<City> cities = new ArrayList<>(); public CityService() { cities.add(new City(1L, "Bratislava", 432000)); cities.add(new City(2L, "Budapest", 1759000)); cities.add(new City(3L, "Prague", 1280000)); cities.add(new City(4L, "Warsaw", 1748000)); cities.add(new City(5L, "Los Angeles", 3971000)); cities.add(new City(6L, "New York", 8550000)); cities.add(new City(7L, "Edinburgh", 464000)); cities.add(new City(8L, "Berlin", 3671000)); } @Override public ResponseEntity<List<City>> findAll() { return ResponseEntity.ok(cities); } public ResponseEntity<City> findById(int id) { if (id < 0 || id >= cities.size()) { return ResponseEntity.notFound().build(); } return ResponseEntity.ok(cities.get(id)); } }
The CityService
contains the implementation of the
findAll
and findById
methods.
package com.zetcode; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
Application
is the entry point which sets up Spring Boot
application.
$ ./gradlew bootRun
We run the application.
$ curl localhost:8080/cities/2 -i HTTP/1.1 200 Content-Type: application/json Transfer-Encoding: chunked Date: Wed, 19 Jul 2023 14:25:22 GMT {"id":3,"name":"Prague","population":1280000}
$ curl localhost:8080/cities [{"id":1,"name":"Bratislava","population":432000},{"id":2,"name":"Budapest","population":1759000}, {"id":3,"name":"Prague","population":1280000},{"id":4,"name":"Warsaw","population":1748000}, {"id":5,"name":"Los Angeles","population":3971000},{"id":6,"name":"New York","population":8550000}, {"id":7,"name":"Edinburgh","population":464000},{"id":8,"name":"Berlin","population":3671000}]
$ curl localhost:8080/cities/26 -i HTTP/1.1 404 Content-Length: 0 Date: Wed, 19 Jul 2023 14:26:24 GMT