First app

First app

Spring Initializr is recommended to generate a Spring Boot app.

start spring io first app 01
  1. Go to Spring Initializr.

  2. Select Gradle - Kotlin for the project.

  3. Select Java for the language.

  4. Set the group and artifact.

  5. Add the Spring Web dependency.

  6. Click the Generate button and download the zip file.

  7. Unzip the zip file on your computer.

  8. Open the project with your IDE.

Notice the @SpringBootApplication-annotated class in src/main/java. Since it contains the static method main, your IDE can run the class.

 1package com.example.demo;
 2
 3import org.springframework.boot.SpringApplication;
 4import org.springframework.boot.autoconfigure.SpringBootApplication;
 5
 6@SpringBootApplication
 7public class DemoApplication {
 8
 9	public static void main(String[] args) {
10		SpringApplication.run(DemoApplication.class, args);
11	}
12
13}

To get a feel for how the Spring Boot programming model works, let’s create a REST controller.

 1package com.example.demo;
 2
 3import org.springframework.web.bind.annotation.GetMapping;
 4import org.springframework.web.bind.annotation.RequestMapping;
 5import org.springframework.web.bind.annotation.RestController;
 6
 7@RestController
 8@RequestMapping("/api/hello")
 9class HelloController {
10
11    @GetMapping
12    String sayHello() {
13        return "Hello, World!";
14    }
15
16}
  • @RestController tells Spring Boot this class will handle HTTP requests.

  • @RequestMapping maps the controller to a URL. Since Spring Boot apps listen to port 8080 by default, the controller is mapped to http://localhost:8080/api/hello.

  • @GetMapping is a specialization of @RequestMapping. It indicates that the method following it with respond to HTTP GET.

Using cURL or your browser, check that everything is working properly.

$ curl -X GET http://localhost:8080/api/hello
Hello, World!

To match part of the URL to a function parameter, use the @PathVariable annotation.

1    @GetMapping("/{name}")
2    String sayHello(@PathVariable("name") String name) {
3        return String.format("Hello, %s!", name);
4    }
$ curl -X GET http://localhost:8080/api/hello/Oscar
Hello, Oscar!

Spring Boot can serialize Java objects over the wire. Let’s create a plain old Java object to illustrate this.

 1package com.example.demo;
 2
 3import java.util.Date;
 4import java.util.UUID;
 5
 6public class Event {
 7
 8    private final UUID id;
 9
10    private final Date creationDate;
11
12    public Event(UUID id, Date creationDate) {
13        this.id = id;
14        this.creationDate = creationDate;
15    }
16
17    public UUID getId() {
18        return id;
19    }
20
21    public Date getCreationDate() {
22        return creationDate;
23    }
24
25}

Let’s add a new method to the controller:

1    @GetMapping("/event")
2    Event getEvent() {
3        return new Event(UUID.randomUUID(), new Date());
4    }
$ curl -X GET http://localhost:8080/api/hello/event
{"id":"ef1e0ace-c476-462e-a82b-676e566997a1","creationDate":"2025-09-16T13:57:38.298+00:00"}

By default, Spring Boot converts Java objects to JSON. However, Spring Boot supports many media types, including XML.

Let’s add the jackson-dataformat-xml dependency in build.gradle.kts:

1implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-xml")

Let’s change the annotation to produce XML instead of JSON:

1    @GetMapping(value = "/event", produces = MediaType.APPLICATION_XML_VALUE)
2    Event getEvent() {
3        return new Event(UUID.randomUUID(), new Date());
4    }
$ curl -X GET http://localhost:8080/api/hello/event
<Event><id>970030e8-52eb-4dcb-b83d-342b70f8960e</id><creationDate>2025-09-16T14:00:57.496+00:00</creationDate></Event>
Note
If com.fasterxml.jackson.dataformat:jackson-dataformat-xml is present in the dependencies set in file build.gradle.kts, then by default the values sent to the client will be serialized in XML.

To create a resource in the system, we should POST to the collection endpoint. If the creation was a success, the server should send the HTTP code 201 and the Location header set to the URL of the created resource.

 1import org.springframework.http.HttpStatus;
 2import org.springframework.http.ResponseEntity;
 3import org.springframework.web.bind.annotation.GetMapping;
 4import org.springframework.web.bind.annotation.PathVariable;
 5import org.springframework.web.bind.annotation.PostMapping;
 6import org.springframework.web.bind.annotation.RequestBody;
 7import org.springframework.web.bind.annotation.RequestMapping;
 8import org.springframework.web.bind.annotation.RestController;
 9import org.springframework.web.server.ResponseStatusException;
10import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
11
12import java.net.URI;
13import java.util.List;
14
15@RestController
16@RequestMapping("/api/products")
17public class ProductController {
18
19    private final ProductRepository productRepository;
20
21    public ProductController(ProductRepository productRepository) {
22        this.productRepository = productRepository;
23    }
24
25    @GetMapping
26    public List<Product> getProducts() {
27        return productRepository.findAll();
28    }
29
30    @GetMapping("/{id}")
31    public Product getProduct(@PathVariable("id") Long id) {
32        return productRepository.findById(id)
33                .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND));
34    }
35
36    @PostMapping
37    public ResponseEntity<?> createProduct(@RequestBody Product product) {
38        Product result = productRepository.save(product);
39        URI location = ServletUriComponentsBuilder
40                .fromCurrentRequest().path("/{id}")
41                .buildAndExpand(result.getId()).toUri();
42        return ResponseEntity.created(location).build();
43    }
44
45}
Note
Repositories will be seen in a later session.