← Назад к вопросам

Что нужно сконфигурировать для работы контроллера?

1.8 Middle🔥 151 комментариев
#Stream API и функциональное программирование#Многопоточность

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Конфигурация контроллера в Spring

Контроллер — это входная точка REST API в приложении. Для корректной работы контроллера необходимо настроить несколько уровней: от аннотаций до конфигурации фреймворка.

1. Минимальная конфигурация контроллера

// Самая простая конфигурация
@RestController  // Компонент Spring, обрабатывающий HTTP запросы
@RequestMapping("/api/users")  // Базовый путь для всех методов контроллера
public class UserController {
    
    @GetMapping("/{id}")  // GET /api/users/{id}
    public UserDto getUser(@PathVariable Long id) {
        // Реализация
        return new UserDto(id, "John");
    }
    
    @PostMapping  // POST /api/users
    public UserDto createUser(@RequestBody CreateUserRequest request) {
        // Реализация
        return new UserDto(1L, request.name());
    }
}

Здесь необходимо:

  • @RestController — указывает Spring, что это REST контроллер
  • @RequestMapping — определяет базовый URL prefix
  • @GetMapping/@PostMapping — определяют HTTP метод и путь

2. Инъекция зависимостей

Контроллер редко работает в изоляции. Он нужно иметь доступ к сервисам бизнес-логики:

@RestController
@RequestMapping("/api/users")
public class UserController {
    private final UserService userService;  // Инъекция зависимости
    private final UserMapper userMapper;    // Маппер DTO
    
    // Constructor injection (рекомендуется для Spring 5.1+)
    public UserController(UserService userService, UserMapper userMapper) {
        this.userService = userService;
        this.userMapper = userMapper;
    }
    
    @GetMapping("/{id}")
    public UserDto getUser(@PathVariable Long id) {
        User user = userService.findById(id).orElseThrow();
        return userMapper.toDto(user);
    }
}

// Service должна быть компонентом Spring
@Service
public class UserService {
    private final UserRepository userRepository;
    
    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }
    
    public Optional<User> findById(Long id) {
        return userRepository.findById(id);
    }
}

3. Сканирование компонентов (Component Scanning)

Spring должна знать, где искать компоненты. Это настраивается в конфигурации:

@SpringBootApplication  // Автоматически настраивает component scanning
@ComponentScan(basePackages = {"com.example.controllers", "com.example.services"})
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

Or в application.yml:

spring:
  application:
    name: user-api

4. Конфигурация диспетчера сервлетов (DispatcherServlet)

В Spring Boot это настраивается автоматически, но в обычном Spring нужно явно:

// Spring MVC конфигурация
@Configuration
@EnableWebMvc  // Включает основные MVC возможности
public class WebConfig implements WebMvcConfigurer {
    
    @Bean
    public DispatcherServlet dispatcherServlet() {
        return new DispatcherServlet();
    }
    
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // Регистрация интерсепторов
        registry.addInterceptor(new LoggingInterceptor());
    }
    
    @Override
    public void addFormatters(FormatterRegistry registry) {
        // Регистрация форматеров
    }
}

5. Парсинг и валидация данных запроса

Контроллер должен уметь парсить входные данные и валидировать их:

@RestController
@RequestMapping("/api/users")
public class UserController {
    private final UserService userService;
    private final Validator validator;  // Инъекция валидатора
    
    public UserController(UserService userService, Validator validator) {
        this.userService = userService;
        this.validator = validator;
    }
    
    @PostMapping
    public ResponseEntity<UserDto> createUser(@Valid @RequestBody CreateUserRequest request) {
        // @Valid автоматически валидирует request
        User user = userService.createUser(request);
        return ResponseEntity.status(HttpStatus.CREATED).body(toDto(user));
    }
}

// Request DTO с аннотациями валидации
public record CreateUserRequest(
    @NotBlank(message = "Name is required")
    String name,
    
    @Email(message = "Invalid email")
    String email,
    
    @Min(18)
    @Max(120)
    int age
) {}

6. Сериализация ответов

Spring Boot автоматически конфигурирует Jackson для JSON:

# application.yml
spring:
  jackson:
    default-property-inclusion: non_null  # Не включать null в JSON
    serialization:
      write-dates-as-timestamps: false
      indent-output: true
    deserialization:
      fail-on-unknown-properties: false
public record UserDto(
    @JsonProperty("user_id")
    Long id,
    
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @JsonProperty("created_at")
    LocalDateTime createdAt
) {}

7. Обработка исключений (Exception Handling)

Контроллер должен корректно обрабатывать ошибки:

@RestControllerAdvice  // Глобальный обработчик исключений
public class GlobalExceptionHandler {
    
    @ExceptionHandler(ResourceNotFoundException.class)
    public ResponseEntity<ErrorResponse> handleNotFound(ResourceNotFoundException ex) {
        ErrorResponse error = new ErrorResponse(
            "NOT_FOUND",
            ex.getMessage(),
            LocalDateTime.now()
        );
        return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);
    }
    
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<ErrorResponse> handleValidationError(
            MethodArgumentNotValidException ex) {
        String message = ex.getBindingResult()
            .getFieldErrors()
            .stream()
            .map(error -> error.getField() + ": " + error.getDefaultMessage())
            .collect(Collectors.joining(", "));
        
        ErrorResponse error = new ErrorResponse(
            "VALIDATION_ERROR",
            message,
            LocalDateTime.now()
        );
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error);
    }
}

public record ErrorResponse(
    String code,
    String message,
    LocalDateTime timestamp
) {}

8. Content Negotiation

Настройка того, какие форматы ответов поддерживает контроллер:

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
        configurer
            .defaultContentType(MediaType.APPLICATION_JSON)
            .mediaType("json", MediaType.APPLICATION_JSON)
            .mediaType("xml", MediaType.APPLICATION_XML);
    }
}

@RestController
@RequestMapping("/api/users")
public class UserController {
    @GetMapping("/{id}", produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE})
    public UserDto getUser(@PathVariable Long id) {
        // Может вернуть JSON или XML в зависимости от Accept header
    }
}

9. CORS конфигурация

Для работы с фронтендом на другом домене нужна CORS конфигурация:

@Configuration
public class CorsConfig {
    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurer() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/api/**")
                    .allowedOrigins("http://localhost:3000", "https://example.com")
                    .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
                    .allowedHeaders("*")
                    .allowCredentials(true)
                    .maxAge(3600);
            }
        };
    }
}

Или в application.yml:

spring:
  web:
    cors:
      allowed-origins: http://localhost:3000
      allowed-methods: GET,POST,PUT,DELETE
      allowed-headers: "*"
      allow-credentials: true
      max-age: 3600

10. Безопасность (Spring Security)

Для защиты контроллера:

@Configuration
@EnableWebSecurity
public class SecurityConfig {
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(authz -> authz
                .requestMatchers("/api/auth/**").permitAll()  // Публичные endpoints
                .requestMatchers("/api/users/**").authenticated()  // Требуют аутентификации
                .anyRequest().authenticated()
            )
            .httpBasic(Customizer.withDefaults())
            .formLogin(Customizer.withDefaults());
        return http.build();
    }
}

@RestController
@RequestMapping("/api/users")
public class UserController {
    @GetMapping("/{id}")
    @PreAuthorize("@userSecurityService.canViewUser(#id)")  // Проверка прав
    public UserDto getUser(@PathVariable Long id) {
        // Реализация
    }
}

11. Конфигурация Jackson для кастомной сериализации

@RestController
@RequestMapping("/api/orders")
public class OrderController {
    @GetMapping("/{id}")
    public OrderDto getOrder(@PathVariable Long id) {
        // Spring автоматически сериализует в JSON
    }
}

@Data
public class OrderDto {
    private Long id;
    
    @JsonSerialize(using = MoneySerializer.class)
    private BigDecimal totalAmount;
    
    @JsonDeserialize(using = LocalDateTimeDeserializer.class)
    private LocalDateTime createdAt;
}

public class MoneySerializer extends StdSerializer<BigDecimal> {
    public MoneySerializer() {
        super(BigDecimal.class);
    }
    
    @Override
    public void serialize(BigDecimal value, JsonGenerator gen, SerializerProvider provider)
            throws IOException {
        gen.writeString(String.format("$%.2f", value));
    }
}

Чеклист конфигурации контроллера

✓ Класс помечен @RestController или @Controller
✓ Определён базовый путь через @RequestMapping
✓ Инъецированы необходимые сервисы
✓ Входные параметры помечены @PathVariable, @RequestParam, @RequestBody
✓ Входные данные валидируются через @Valid
✓ Выходные данные сериализуются в правильный формат
✓ Исключения обрабатываются через @ExceptionHandler
✓ CORS настроен, если требуется
✓ Безопасность настроена через Spring Security
✓ Content Negotiation конфигурирован
✓ Jackson конфигурирован для правильной сериализации

Когда все эти элементы на месте, контроллер готов обрабатывать HTTP запросы и предоставлять надёжный REST API.