Learn Spring Boot from scratch — REST APIs, JPA, Security, and deployment — with real code examples. Written by Deen Bandhu, working Java developer.
Spring Boot is an opinionated framework built on top of Spring Framework that eliminates boilerplate configuration. It gives you a production-ready application in minutes — embedded Tomcat server, auto-configuration, and starter dependencies do the heavy lifting.
spring-boot-starter-web includes Tomcat, MVC, Jackson.java -jar app.jar.Use Spring Initializr at start.spring.io. Select:
<!-- Web + REST API --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- JPA + Hibernate --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <!-- MySQL --> <dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> <scope>runtime</scope> </dependency> <!-- Lombok (boilerplate reduction) --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency>
Spring Boot applications follow a layered architecture:
@RestController @RequestMapping("/api/products") @RequiredArgsConstructor public class ProductController { private final ProductService productService; @GetMapping public ResponseEntity<List<ProductDTO>> getAll() { return ResponseEntity.ok(productService.findAll()); } @GetMapping("/" ) public ResponseEntity<ProductDTO> getById(@PathVariable Long id) { return ResponseEntity.ok(productService.findById(id)); } @PostMapping public ResponseEntity<ProductDTO> create( @Valid @RequestBody ProductDTO dto) { ProductDTO saved = productService.save(dto); return ResponseEntity.status(201).body(saved); } @PutMapping("/" ) public ResponseEntity<ProductDTO> update( @PathVariable Long id, @Valid @RequestBody ProductDTO dto) { return ResponseEntity.ok(productService.update(id, dto)); } @DeleteMapping("/" ) public ResponseEntity<Void> delete(@PathVariable Long id) { productService.delete(id); return ResponseEntity.noContent().build(); } }
@Entity @Table(name = "products") @Data @NoArgsConstructor @AllArgsConstructor @Builder public class Product { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(nullable = false, length = 100) private String name; @Column(nullable = false) private Double price; @Column(length = 500) private String description; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "category_id") private Category category; }
@Repository public interface ProductRepository extends JpaRepository<Product, Long> { // Spring Data auto-generates query from method name List<Product> findByNameContainingIgnoreCase(String keyword); List<Product> findByCategoryIdOrderByPriceAsc(Long categoryId); // Custom JPQL query @Query("SELECT p FROM Product p WHERE p.price BETWEEN :min AND :max") List<Product> findInPriceRange(@Param("min") Double min, @Param("max") Double max); }
@Data public class ProductDTO { @NotBlank(message = "Name is required") @Size(min = 2, max = 100, message = "Name must be 2-100 characters") private String name; @NotNull(message = "Price is required") @DecimalMin(value = "0.01", message = "Price must be positive") private Double price; @Size(max = 500) private String description; }
@RestControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(ResourceNotFoundException.class) public ResponseEntity<ErrorResponse> handleNotFound( ResourceNotFoundException ex) { return ResponseEntity.status(404) .body(new ErrorResponse("NOT_FOUND", ex.getMessage())); } @ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntity<ErrorResponse> handleValidation( MethodArgumentNotValidException ex) { Map<String, String> errors = ex.getBindingResult() .getFieldErrors().stream() .collect(Collectors.toMap( FieldError::getField, FieldError::getDefaultMessage)); return ResponseEntity.badRequest() .body(new ErrorResponse("VALIDATION_FAILED", errors.toString())); } }
@Configuration @EnableWebSecurity @RequiredArgsConstructor public class SecurityConfig { private final JwtAuthFilter jwtAuthFilter; @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { return http .csrf(AbstractHttpConfigurer::disable) .authorizeHttpRequests(auth -> auth .requestMatchers("/api/auth/**").permitAll() .anyRequest().authenticated() ) .sessionManagement(s -> s .sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class) .build(); } }
# Server server.port=8080 spring.application.name=my-app # Database (MySQL) spring.datasource.url=jdbc:mysql://localhost:3306/mydb spring.datasource.username=root spring.datasource.password=yourpassword spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver # JPA / Hibernate spring.jpa.hibernate.ddl-auto=update spring.jpa.show-sql=true spring.jpa.properties.hibernate.format_sql=true spring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect # Logging logging.level.org.springframework=INFO logging.level.com.yourpackage=DEBUG
mvn clean package -DskipTests. Creates target/app.jar with embedded Tomcat.java -jar target/app.jar --spring.profiles.active=prod. Use profiles for environment-specific configs.FROM eclipse-temurin:17-jre, COPY target/app.jar app.jar, ENTRYPOINT ["java","-jar","app.jar"]. Build and push to Docker Hub or ECR.Deen Bandhu's course covers everything above — with live coding, real projects (e-commerce API, JWT auth), code reviews, and placement guidance.