← Назад к вопросам
Как достать id из пути в контроллере
1.0 Junior🔥 231 комментариев
#REST API и микросервисы#Spring Framework
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
# Как достать ID из пути в Spring контроллере
Это один из основных навыков в Spring MVC/Boot разработке. ID в пути URL — это path variable, и Spring предоставляет несколько способов это сделать.
Основной способ: @PathVariable
1. Простой случай
@RestController
@RequestMapping("/api/users")
public class UserController {
// GET /api/users/123
@GetMapping("/{id}")
public ResponseEntity<UserDTO> getUser(@PathVariable Long id) {
User user = userService.findById(id);
return ResponseEntity.ok(new UserDTO(user));
}
}
Как работает:
- URL path:
/api/users/123 - Spring автоматически извлекает
123из{id} - Преобразует в
Long(или другой тип) - Передаёт в метод как параметр
2. Несколько ID в пути
@GetMapping("/{userId}/posts/{postId}")
public ResponseEntity<PostDTO> getUserPost(
@PathVariable Long userId,
@PathVariable Long postId
) {
Post post = postService.findById(userId, postId);
return ResponseEntity.ok(new PostDTO(post));
}
// GET /api/users/123/posts/456
// userId = 123
// postId = 456
Явное указание имени переменной
Когда имя в пути отличается от параметра
@GetMapping("/user/{uid}")
public ResponseEntity<UserDTO> getUser(
@PathVariable("uid") Long id // "uid" в пути, но параметр "id"
) {
return ResponseEntity.ok(userService.findById(id));
}
// GET /api/user/123
// Spring ищет {uid} в пути и передаёт как параметр id
Разные типы данных
UUID (Universally Unique Identifier)
@GetMapping("/{id}")
public ResponseEntity<UserDTO> getUser(@PathVariable UUID id) {
User user = userService.findById(id);
return ResponseEntity.ok(new UserDTO(user));
}
// GET /api/users/550e8400-e29b-41d4-a716-446655440000
// id = UUID.fromString("550e8400-e29b-41d4-a716-446655440000")
String
@GetMapping("/user/{username}")
public ResponseEntity<UserDTO> getUserByUsername(@PathVariable String username) {
User user = userService.findByUsername(username);
return ResponseEntity.ok(new UserDTO(user));
}
// GET /api/user/john_doe
// username = "john_doe"
Опциональный ID (required = false)
Когда ID может быть не обязательным
@GetMapping("/items/{id}")
public ResponseEntity<ItemDTO> getItem(
@PathVariable(required = false) Long id
) {
if (id == null) {
return ResponseEntity.ok(itemService.getDefault());
}
return ResponseEntity.ok(itemService.findById(id));
}
Валидация ID
С аннотацией @Validated
@RestController
@Validated // Включить валидацию
@RequestMapping("/api/users")
public class UserController {
@GetMapping("/{id}")
public ResponseEntity<UserDTO> getUser(
@PathVariable
@Positive(message = "ID должен быть положительным числом")
Long id
) {
User user = userService.findById(id);
return ResponseEntity.ok(new UserDTO(user));
}
}
Валидация происходит:
- Если
id<= 0, возвращается 400 Bad Request - Message будет в ответе
Custom валидация
@GetMapping("/user/{id}")
public ResponseEntity<UserDTO> getUser(@PathVariable Long id) {
if (id <= 0) {
throw new IllegalArgumentException("ID должен быть положительным");
}
User user = userService.findById(id)
.orElseThrow(() -> new UserNotFoundException("User with id " + id + " not found"));
return ResponseEntity.ok(new UserDTO(user));
}
Regex в пути
Когда нужна валидация формата
@GetMapping("/users/{id:[0-9]+}") // Только числа
public ResponseEntity<UserDTO> getUser(@PathVariable Long id) {
return ResponseEntity.ok(userService.findById(id));
}
// GET /api/users/123 → ✅ OK
// GET /api/users/abc → ❌ 404 Not Found (путь не соответствует regex)
UUID regex
@GetMapping("/users/{id:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}}")
public ResponseEntity<UserDTO> getUser(@PathVariable UUID id) {
return ResponseEntity.ok(userService.findById(id));
}
Получение всех path variables сразу
Через Map
@GetMapping("/users/{userId}/posts/{postId}")
public ResponseEntity<PostDTO> getUserPost(
@PathVariable Map<String, String> pathVariables
) {
Long userId = Long.parseLong(pathVariables.get("userId"));
Long postId = Long.parseLong(pathVariables.get("postId"));
Post post = postService.findById(userId, postId);
return ResponseEntity.ok(new PostDTO(post));
}
Комбинация Path и Query параметров
Path ID + Query фильтры
@GetMapping("/users/{id}/posts")
public ResponseEntity<List<PostDTO>> getUserPosts(
@PathVariable Long id,
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size,
@RequestParam(required = false) String sortBy
) {
Pageable pageable = PageRequest.of(page, size, Sort.by(sortBy));
List<Post> posts = postService.findByUserId(id, pageable);
return ResponseEntity.ok(posts.stream().map(PostDTO::new).toList());
}
// GET /api/users/123/posts?page=0&size=20&sortBy=createdAt
// id = 123
// page = 0
// size = 20
// sortBy = "createdAt"
Обработка ошибок
Когда ID не найден
@GetMapping("/{id}")
public ResponseEntity<UserDTO> getUser(@PathVariable Long id) {
return userService.findById(id)
.map(user -> ResponseEntity.ok(new UserDTO(user)))
.orElseThrow(() -> new ResponseStatusException(
HttpStatus.NOT_FOUND,
"User with id " + id + " not found"
));
}
Глобальный exception handler
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(UserNotFoundException.class)
public ResponseEntity<ErrorResponse> handleUserNotFound(UserNotFoundException ex) {
return ResponseEntity
.status(HttpStatus.NOT_FOUND)
.body(new ErrorResponse("USER_NOT_FOUND", ex.getMessage()));
}
@ExceptionHandler(MethodArgumentTypeMismatchException.class)
public ResponseEntity<ErrorResponse> handleTypeMismatch(MethodArgumentTypeMismatchException ex) {
return ResponseEntity
.status(HttpStatus.BAD_REQUEST)
.body(new ErrorResponse("INVALID_ID_FORMAT", "ID должен быть числом"));
}
}
Best Practices
-
Используй правильный тип данных
@PathVariable Long id // для больших чисел @PathVariable UUID id // для UUID @PathVariable String slug // для slug'ов -
Валидируй ID
@PathVariable @Positive Long id -
Именуй переменные понятно
@GetMapping("/users/{userId}/posts/{postId}") // ясно @GetMapping("/users/{id}/posts/{id}") // ПЛОХО, конфликт имён! -
Обрабатывай ошибки gracefully
- 404 если ID не найден
- 400 если ID невалидный формат
-
Используй RESTful соглашения
- GET /api/users/123 — получить user
- POST /api/users — создать user
- PUT /api/users/123 — обновить user
- DELETE /api/users/123 — удалить user
Резюме
@PathVariable — основной способ извлечения ID из пути. Spring автоматически:
- Парсит значение из URL
- Преобразует в нужный тип
- Валидирует (если указано)
- Передаёт в метод контроллера
Это один из самых используемых паттернов в REST API разработке.