How Do I Start Spring Boot for Backend Development?
Purpose
I wanted to start building Java backends, but I wasn’t sure where to begin. Spring Boot is the industry-standard framework for Java backend development - most Java backend positions require it. In this post, I’ll show you how to get started by building a simple REST API.
Environment
- Java 17 (LTS version)
- IntelliJ IDEA Community (free) or VS Code
- Maven 3.9+
- Spring Boot 3.x
Why Spring Boot?
Spring Boot simplifies Java backend development. It handles the complexity of setting up a Spring application, letting you focus on writing business logic.
Key benefits:
- Auto-configuration reduces boilerplate
- Embedded server (Tomcat) - no deployment needed
- Production-ready features built-in
- Massive ecosystem and community support
Prerequisites
Before starting with Spring Boot, you should know:
- Basic Java syntax (variables, methods, classes)
- Object-oriented programming concepts
- Basic HTTP and REST concepts
Tools to install:
- JDK 17 or later
- An IDE (IntelliJ IDEA Community or VS Code)
- Maven or Gradle (included in most IDEs)
Step 1: Create Your First Project
The easiest way to create a Spring Boot project is using Spring Initializr.
Go to start.spring.io and configure:
Project: MavenLanguage: JavaSpring Boot: 3.2.x (latest stable)Packaging: JarJava: 17
Dependencies to add:- Spring Web (build REST APIs)- Spring Data JPA (database access)- H2 Database (in-memory for development)- Validation (input validation)- Lombok (reduce boilerplate code)Click “Generate” to download the project, then extract and open it in your IDE.
The project structure looks like:
my-project/├── src/│ ├── main/│ │ ├── java/com/example/myproject/│ │ │ └── MyProjectApplication.java│ │ └── resources/│ │ └── application.properties│ └── test/└── pom.xmlStep 2: Build a REST Controller
A REST controller handles HTTP requests and returns JSON responses.
I created a simple controller:
package com.example.demo;
import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RestController;
@RestControllerpublic class HelloController {
@GetMapping("/hello") public String hello() { return "Hello, Spring Boot!"; }}Run the application:
./mvnw spring-boot:runThen visit http://localhost:8080/hello in your browser. You should see:
Hello, Spring Boot!The @RestController annotation tells Spring this class handles web requests. The @GetMapping annotation maps HTTP GET requests to the /hello path.
Step 3: Connect to a Database
Now I’ll add database persistence using Spring Data JPA.
First, create an entity class:
package com.example.demo;
import jakarta.persistence.*;import jakarta.validation.constraints.NotBlank;
@Entity@Table(name = "movies")public class Movie {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id;
@NotBlank private String title;
private Integer releaseYear;
private String genre;
// Default constructor required by JPA public Movie() {}
public Movie(String title, Integer releaseYear, String genre) { this.title = title; this.releaseYear = releaseYear; this.genre = genre; }
// Getters and setters public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public Integer getReleaseYear() { return releaseYear; } public void setReleaseYear(Integer releaseYear) { this.releaseYear = releaseYear; } public String getGenre() { return genre; } public void setGenre(String genre) { this.genre = genre; }}Next, create a repository interface:
package com.example.demo;
import org.springframework.data.jpa.repository.JpaRepository;import java.util.List;
public interface MovieRepository extends JpaRepository<Movie, Long> { // Spring Data automatically implements these query methods List<Movie> findByGenre(String genre); List<Movie> findByReleaseYear(Integer year); List<Movie> findByTitleContainingIgnoreCase(String title);}Spring Data JPA generates the implementation automatically. I just define the interface, and Spring handles the SQL queries behind the scenes.
Configure H2 database in application.properties:
spring.datasource.url=jdbc:h2:mem:testdbspring.datasource.driverClassName=org.h2.Driverspring.datasource.username=saspring.datasource.password=spring.h2.console.enabled=truespring.jpa.database-platform=org.hibernate.dialect.H2Dialectspring.jpa.hibernate.ddl-auto=create-dropH2 is an in-memory database - great for learning. Data is lost when you restart the application.
Step 4: Implement CRUD Operations
Now I’ll create a full REST controller with CRUD operations:
package com.example.demo;
import org.springframework.http.HttpStatus;import org.springframework.http.ResponseEntity;import org.springframework.web.bind.annotation.*;
import jakarta.validation.Valid;import java.util.List;
@RestController@RequestMapping("/api/movies")public class MovieController {
private final MovieRepository movieRepository;
public MovieController(MovieRepository movieRepository) { this.movieRepository = movieRepository; }
// GET all movies @GetMapping public List<Movie> getAllMovies() { return movieRepository.findAll(); }
// GET single movie by ID @GetMapping("/{id}") public ResponseEntity<Movie> getMovieById(@PathVariable Long id) { return movieRepository.findById(id) .map(ResponseEntity::ok) .orElse(ResponseEntity.notFound().build()); }
// POST - create new movie @PostMapping public ResponseEntity<Movie> createMovie(@Valid @RequestBody Movie movie) { Movie savedMovie = movieRepository.save(movie); return ResponseEntity.status(HttpStatus.CREATED).body(savedMovie); }
// PUT - update existing movie @PutMapping("/{id}") public ResponseEntity<Movie> updateMovie( @PathVariable Long id, @Valid @RequestBody Movie movieDetails) { return movieRepository.findById(id) .map(movie -> { movie.setTitle(movieDetails.getTitle()); movie.setReleaseYear(movieDetails.getReleaseYear()); movie.setGenre(movieDetails.getGenre()); return ResponseEntity.ok(movieRepository.save(movie)); }) .orElse(ResponseEntity.notFound().build()); }
// DELETE - remove movie @DeleteMapping("/{id}") public ResponseEntity<Void> deleteMovie(@PathVariable Long id) { if (!movieRepository.existsById(id)) { return ResponseEntity.notFound().build(); } movieRepository.deleteById(id); return ResponseEntity.noContent().build(); }}Test the API with curl:
curl -X POST http://localhost:8080/api/movies \ -H "Content-Type: application/json" \ -d '{"title":"The Matrix","releaseYear":1999,"genre":"Sci-Fi"}'{"id":1,"title":"The Matrix","releaseYear":1999,"genre":"Sci-Fi"}curl http://localhost:8080/api/moviesThe controller uses dependency injection - Spring automatically provides the MovieRepository instance. This is a core Spring concept.
Step 5: Add Professional Touches
Use Docker for PostgreSQL
H2 is fine for learning, but real projects use PostgreSQL. Here’s how to set it up with Docker:
version: '3.8'services: postgres: image: postgres:15 environment: POSTGRES_DB: movietracker POSTGRES_USER: myuser POSTGRES_PASSWORD: mypassword ports: - "5432:5432" volumes: - postgres_data:/var/lib/postgresql/data
volumes: postgres_data:Start the database:
docker-compose up -dUpdate application.properties for PostgreSQL:
spring.datasource.url=jdbc:postgresql://localhost:5432/movietrackerspring.datasource.username=myuserspring.datasource.password=mypasswordspring.datasource.driver-class-name=org.postgresql.Driverspring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialectspring.jpa.hibernate.ddl-auto=validateAdd the PostgreSQL driver dependency to pom.xml:
<dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <scope>runtime</scope></dependency>Use Liquibase for Migrations
Liquibase tracks database schema changes over time. This is how professional teams manage databases.
Add to pom.xml:
<dependency> <groupId>org.liquibase</groupId> <artifactId>liquibase-core</artifactId></dependency>Create a migration file:
databaseChangeLog: - changeSet: id: 1 author: cowrie changes: - createTable: tableName: movies columns: - column: name: id type: bigint autoIncrement: true constraints: primaryKey: true - column: name: title type: varchar(255) constraints: nullable: false - column: name: release_year type: int - column: name: genre type: varchar(50)Configure Liquibase in application.properties:
spring.liquibase.change-log=classpath:db/changelog/db.changelog-master.yamlLiquibase automatically runs migrations when the application starts.
Common Mistakes to Avoid
- Skipping the official documentation - Spring’s docs are excellent. Read them first.
- Not understanding dependency injection - This is the core of Spring. Learn how
@Autowiredand constructor injection work. - Overcomplicating the first project - Start simple. A basic CRUD API is enough to learn the concepts.
- Ignoring project structure - Follow standard conventions. Controllers go in a
controllerpackage, repositories inrepository, etc.
Next Steps
After you’re comfortable with the basics:
- Add authentication with Spring Security
- Write tests with JUnit and Mockito
- Deploy to a cloud platform (Railway, Render, AWS)
- Build a frontend to consume your API
Summary
In this post, I showed how to start with Spring Boot for backend development. The key points are:
- Use Spring Initializr to create projects quickly
- Build REST controllers with
@RestControllerand@GetMapping - Connect to databases with Spring Data JPA - just define an interface
- Implement full CRUD operations with minimal code
- Add Docker and Liquibase for professional development practices
The framework handles most complexity automatically. Start with a simple project, then gradually add features as you learn.
Final Words + More Resources
My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me
Here are also the most important links from this article along with some further resources that will help you in this scope:
- 👨💻 Spring Initializr
- 👨💻 Spring Boot Official Documentation
- 👨💻 Building a RESTful Web Service - Spring Guide
- 👨💻 Baeldung Spring Boot Tutorials
- 👨💻 Reddit Discussion: Java Projects for Resume
Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!
Comments