Claude
Skills
Sign in
Back

spring-boot

Included with Lifetime
$97 forever

Spring Boot 3.x - Java framework for production-ready applications with dependency injection, REST APIs, data access, security, and actuator monitoring

toolchainjavaspring-bootspringmicroservicesrest-apidependency-injectionjpasecurity

What this skill does


# Spring Boot 3.x - Production-Ready Java Framework

## Overview

Spring Boot is an opinionated Java framework for building production-ready applications with minimal configuration. It provides auto-configuration, embedded servers, and production-ready features like health checks and metrics.

**Key Features**:
- Auto-configuration (sensible defaults)
- Embedded servers (Tomcat, Jetty, Undertow)
- Dependency Injection with @Autowired
- Spring Data JPA for database access
- Spring Security for authentication/authorization
- Actuator for production monitoring
- Built-in testing support

**Requirements**:
- Java 17+ (Spring Boot 3.x requires Java 17 minimum)
- Maven or Gradle

**Quick Start**:
```bash
# Create project from Spring Initializr
curl https://start.spring.io/starter.zip \
  -d type=maven-project \
  -d language=java \
  -d bootVersion=3.2.0 \
  -d dependencies=web,data-jpa,postgresql,lombok,actuator \
  -d name=myapp \
  -o myapp.zip && unzip myapp.zip

# Run the application
cd myapp
./mvnw spring-boot:run
```

## Project Structure

```
src/
├── main/
│   ├── java/com/example/myapp/
│   │   ├── MyappApplication.java      # Main class
│   │   ├── config/                    # @Configuration classes
│   │   ├── controller/                # @RestController classes
│   │   ├── service/                   # @Service classes
│   │   ├── repository/                # @Repository interfaces
│   │   ├── model/                     # Entity classes
│   │   ├── dto/                       # Data Transfer Objects
│   │   └── exception/                 # Exception handlers
│   └── resources/
│       ├── application.yml            # Configuration
│       └── application-{profile}.yml  # Profile-specific config
└── test/
    └── java/com/example/myapp/        # Test classes
```

## Core Annotations

### Application Setup

```java
// Main application class
@SpringBootApplication  // Combines @Configuration, @EnableAutoConfiguration, @ComponentScan
public class MyappApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyappApplication.class, args);
    }
}
```

### Dependency Injection

```java
// Constructor injection (recommended)
@Service
public class UserService {
    private final UserRepository userRepository;
    private final PasswordEncoder passwordEncoder;

    // @Autowired optional on single constructor (Spring 4.3+)
    public UserService(UserRepository userRepository, PasswordEncoder passwordEncoder) {
        this.userRepository = userRepository;
        this.passwordEncoder = passwordEncoder;
    }
}

// With Lombok
@Service
@RequiredArgsConstructor  // Generates constructor for final fields
public class UserService {
    private final UserRepository userRepository;
    private final PasswordEncoder passwordEncoder;
}

// Field injection (avoid in production code)
@Service
public class UserService {
    @Autowired
    private UserRepository userRepository;  // Harder to test
}
```

### Component Stereotypes

```java
@Component      // Generic component
@Service        // Business logic layer
@Repository     // Data access layer (enables exception translation)
@Controller     // MVC controller (returns views)
@RestController // REST API controller (returns JSON)
@Configuration  // Configuration class with @Bean methods
```

## REST Controllers

### Basic Controller

```java
@RestController
@RequestMapping("/api/v1/users")
@RequiredArgsConstructor
public class UserController {

    private final UserService userService;

    // GET /api/v1/users
    @GetMapping
    public ResponseEntity<List<UserDto>> getAllUsers() {
        return ResponseEntity.ok(userService.findAll());
    }

    // GET /api/v1/users/{id}
    @GetMapping("/{id}")
    public ResponseEntity<UserDto> getUserById(@PathVariable Long id) {
        return userService.findById(id)
            .map(ResponseEntity::ok)
            .orElse(ResponseEntity.notFound().build());
    }

    // POST /api/v1/users
    @PostMapping
    public ResponseEntity<UserDto> createUser(@Valid @RequestBody CreateUserRequest request) {
        UserDto created = userService.create(request);
        URI location = ServletUriComponentsBuilder
            .fromCurrentRequest()
            .path("/{id}")
            .buildAndExpand(created.getId())
            .toUri();
        return ResponseEntity.created(location).body(created);
    }

    // PUT /api/v1/users/{id}
    @PutMapping("/{id}")
    public ResponseEntity<UserDto> updateUser(
            @PathVariable Long id,
            @Valid @RequestBody UpdateUserRequest request) {
        return ResponseEntity.ok(userService.update(id, request));
    }

    // DELETE /api/v1/users/{id}
    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
        userService.delete(id);
        return ResponseEntity.noContent().build();
    }

    // GET /api/v1/users/[email protected]
    @GetMapping("/search")
    public ResponseEntity<List<UserDto>> searchUsers(
            @RequestParam(required = false) String email,
            @RequestParam(defaultValue = "0") int page,
            @RequestParam(defaultValue = "20") int size) {
        return ResponseEntity.ok(userService.search(email, page, size));
    }
}
```

### Request/Response DTOs

```java
// Request DTO with validation
@Data
public class CreateUserRequest {
    @NotBlank(message = "Email is required")
    @Email(message = "Invalid email format")
    private String email;

    @NotBlank(message = "Name is required")
    @Size(min = 2, max = 100, message = "Name must be 2-100 characters")
    private String name;

    @NotBlank(message = "Password is required")
    @Size(min = 8, message = "Password must be at least 8 characters")
    private String password;
}

// Response DTO
@Data
@Builder
public class UserDto {
    private Long id;
    private String email;
    private String name;
    private LocalDateTime createdAt;
    private LocalDateTime updatedAt;

    public static UserDto fromEntity(User user) {
        return UserDto.builder()
            .id(user.getId())
            .email(user.getEmail())
            .name(user.getName())
            .createdAt(user.getCreatedAt())
            .updatedAt(user.getUpdatedAt())
            .build();
    }
}
```

## Service Layer

```java
@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)  // Default to read-only transactions
public class UserService {

    private final UserRepository userRepository;
    private final PasswordEncoder passwordEncoder;

    public List<UserDto> findAll() {
        return userRepository.findAll().stream()
            .map(UserDto::fromEntity)
            .collect(Collectors.toList());
    }

    public Optional<UserDto> findById(Long id) {
        return userRepository.findById(id)
            .map(UserDto::fromEntity);
    }

    @Transactional  // Read-write transaction
    public UserDto create(CreateUserRequest request) {
        if (userRepository.existsByEmail(request.getEmail())) {
            throw new EmailAlreadyExistsException(request.getEmail());
        }

        User user = User.builder()
            .email(request.getEmail())
            .name(request.getName())
            .passwordHash(passwordEncoder.encode(request.getPassword()))
            .build();

        return UserDto.fromEntity(userRepository.save(user));
    }

    @Transactional
    public UserDto update(Long id, UpdateUserRequest request) {
        User user = userRepository.findById(id)
            .orElseThrow(() -> new UserNotFoundException(id));

        if (request.getName() != null) {
            user.setName(request.getName());
        }
        if (request.getEmail() != null) {
            user.setEmail(request.getEmail());
        }

        return UserDto.fromEntity(userRepository.save(user));
    }

    @Transactional
    public void delete(Long id) {
        if (!userRepository.existsById(id)) {
            throw new UserNotFoundException(i

Related in toolchain