Что нужно сконфигурировать для работы контроллера?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Конфигурация контроллера в 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.