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

Как создать @RestController в Spring?

1.0 Junior🔥 301 комментариев
#Spring Boot и Spring Data

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

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

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

Как создать @RestController в Spring?

@RestController — это аннотация в Spring для создания RESTful веб-сервисов. Она комбинирует @Controller и @ResponseBody, автоматически сериализуя возвращаемые значения в JSON/XML.

1. Базовая структура @RestController

import org.springframework.web.bind.annotation.*;
import org.springframework.http.ResponseEntity;
import org.springframework.http.HttpStatus;

@RestController
@RequestMapping("/api/v1/users")  // Базовый путь для всех методов
public class UserController {
    
    // GET: http://localhost:8080/api/v1/users
    @GetMapping
    public List<User> getAllUsers() {
        return new ArrayList<>();  // Автоматически сериализуется в JSON
    }
    
    // GET: http://localhost:8080/api/v1/users/1
    @GetMapping("/{id}")
    public User getUserById(@PathVariable Long id) {
        return new User(id, "John");
    }
    
    // POST: http://localhost:8080/api/v1/users
    @PostMapping
    public User createUser(@RequestBody User user) {
        // user автоматически десериализуется из JSON
        return user;  // Сериализуется обратно в JSON
    }
    
    // PUT: http://localhost:8080/api/v1/users/1
    @PutMapping("/{id}")
    public User updateUser(@PathVariable Long id, @RequestBody User user) {
        user.setId(id);
        return user;
    }
    
    // DELETE: http://localhost:8080/api/v1/users/1
    @DeleteMapping("/{id}")
    public void deleteUser(@PathVariable Long id) {
        // Удаляем пользователя
    }
}

// Model
public class User {
    private Long id;
    private String name;
    
    public User(Long id, String name) {
        this.id = id;
        this.name = name;
    }
    
    // Getters и Setters
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
}

2. @RestController vs @Controller

@Controller — для обычных MVC приложений:

@Controller
public class WebController {
    @GetMapping("/users")
    public String getUsers(Model model) {
        model.addAttribute("users", userService.getAll());
        return "users";  // Возвращает имя HTML шаблона (Thymeleaf, JSP)
    }
}

@RestController — для REST API:

@RestController
public class UserRestController {
    @GetMapping("/api/v1/users")
    public List<User> getUsers() {
        return userService.getAll();  // Сериализуется в JSON
    }
}

// Эквивалентно:
@Controller
public class UserRestController {
    @GetMapping("/api/v1/users")
    @ResponseBody
    public List<User> getUsers() {
        return userService.getAll();
    }
}

3. Полный пример с сервисом

// User model
public class User {
    private Long id;
    private String email;
    private String firstName;
    private String lastName;
    
    // Конструкторы, getters, setters
    public User() {}
    public User(Long id, String email, String firstName, String lastName) {
        this.id = id;
        this.email = email;
        this.firstName = firstName;
        this.lastName = lastName;
    }
    
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }
    public String getEmail() { return email; }
    public void setEmail(String email) { this.email = email; }
    public String getFirstName() { return firstName; }
    public void setFirstName(String firstName) { this.firstName = firstName; }
    public String getLastName() { return lastName; }
    public void setLastName(String lastName) { this.lastName = lastName; }
}

// Service слой
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class UserService {
    private final Map<Long, User> users = new HashMap<>();
    private Long currentId = 1L;
    
    public UserService() {
        // Инициализация тестовых данных
        users.put(1L, new User(1L, "john@example.com", "John", "Doe"));
        users.put(2L, new User(2L, "jane@example.com", "Jane", "Smith"));
        currentId = 3L;
    }
    
    public List<User> getAllUsers() {
        return new ArrayList<>(users.values());
    }
    
    public User getUserById(Long id) {
        return users.get(id);
    }
    
    public User createUser(User user) {
        user.setId(currentId++);
        users.put(user.getId(), user);
        return user;
    }
    
    public User updateUser(Long id, User user) {
        if (!users.containsKey(id)) {
            return null;
        }
        user.setId(id);
        users.put(id, user);
        return user;
    }
    
    public boolean deleteUser(Long id) {
        return users.remove(id) != null;
    }
}

// REST Controller
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/v1/users")
public class UserController {
    
    @Autowired
    private UserService userService;
    
    // GET все пользователи
    @GetMapping
    public ResponseEntity<List<User>> getAllUsers() {
        List<User> users = userService.getAllUsers();
        return ResponseEntity.ok(users);
    }
    
    // GET пользователя по ID
    @GetMapping("/{id}")
    public ResponseEntity<User> getUserById(@PathVariable Long id) {
        User user = userService.getUserById(id);
        if (user == null) {
            return ResponseEntity.notFound().build();
        }
        return ResponseEntity.ok(user);
    }
    
    // POST создание нового пользователя
    @PostMapping
    public ResponseEntity<User> createUser(@RequestBody User user) {
        User createdUser = userService.createUser(user);
        return ResponseEntity.status(HttpStatus.CREATED).body(createdUser);
    }
    
    // PUT обновление пользователя
    @PutMapping("/{id}")
    public ResponseEntity<User> updateUser(
            @PathVariable Long id,
            @RequestBody User user) {
        User updatedUser = userService.updateUser(id, user);
        if (updatedUser == null) {
            return ResponseEntity.notFound().build();
        }
        return ResponseEntity.ok(updatedUser);
    }
    
    // DELETE удаление пользователя
    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
        boolean deleted = userService.deleteUser(id);
        if (!deleted) {
            return ResponseEntity.notFound().build();
        }
        return ResponseEntity.noContent().build();
    }
}

4. Параметры запроса (@RequestParam, @PathVariable)

@RestController
@RequestMapping("/api/v1/search")
public class SearchController {
    
    // Query параметры: /api/v1/search?name=john&age=30
    @GetMapping
    public List<User> searchUsers(
            @RequestParam(required = false) String name,
            @RequestParam(required = false) Integer age) {
        // Параметры опциональны (required = false)
        return userService.search(name, age);
    }
    
    // Path переменные: /api/v1/users/123/orders/456
    @GetMapping("/users/{userId}/orders/{orderId}")
    public Order getUserOrder(
            @PathVariable Long userId,
            @PathVariable Long orderId) {
        return orderService.getOrder(userId, orderId);
    }
    
    // Комбинированные параметры
    @GetMapping("/users")
    public Page<User> listUsers(
            @RequestParam(defaultValue = "0") int page,
            @RequestParam(defaultValue = "10") int size,
            @RequestParam(required = false) String sort) {
        return userService.listUsers(page, size, sort);
    }
}

5. ResponseEntity — управление HTTP ответом

@RestController
@RequestMapping("/api/v1/products")
public class ProductController {
    
    // Простой ответ (200 OK)
    @GetMapping
    public List<Product> getAll() {
        return productService.getAll();
    }
    
    // С явным статусом
    @PostMapping
    public ResponseEntity<Product> create(@RequestBody Product product) {
        Product created = productService.create(product);
        return ResponseEntity
            .status(HttpStatus.CREATED)
            .body(created);
        // Эквивалентно: return new ResponseEntity<>(created, HttpStatus.CREATED);
    }
    
    // 204 No Content
    @DeleteMapping("/{id}")
    public ResponseEntity<Void> delete(@PathVariable Long id) {
        productService.delete(id);
        return ResponseEntity.noContent().build();
    }
    
    // 404 Not Found
    @GetMapping("/{id}")
    public ResponseEntity<Product> getById(@PathVariable Long id) {
        Product product = productService.getById(id);
        if (product == null) {
            return ResponseEntity.notFound().build();
        }
        return ResponseEntity.ok(product);
    }
    
    // С headers
    @GetMapping("/{id}")
    public ResponseEntity<Product> getWithHeaders(@PathVariable Long id) {
        Product product = productService.getById(id);
        return ResponseEntity.ok()
            .header("X-Custom-Header", "value")
            .body(product);
    }
}

6. Обработка ошибок (@ExceptionHandler)

// Custom Exception
public class ResourceNotFoundException extends RuntimeException {
    public ResourceNotFoundException(String message) {
        super(message);
    }
}

// Global Exception Handler
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

@RestControllerAdvice
public class GlobalExceptionHandler {
    
    @ExceptionHandler(ResourceNotFoundException.class)
    public ResponseEntity<Map<String, String>> handleNotFound(
            ResourceNotFoundException ex) {
        Map<String, String> error = new HashMap<>();
        error.put("error", ex.getMessage());
        error.put("status", "404");
        return ResponseEntity.notFound().build();
    }
    
    @ExceptionHandler(IllegalArgumentException.class)
    public ResponseEntity<Map<String, String>> handleBadRequest(
            IllegalArgumentException ex) {
        Map<String, String> error = new HashMap<>();
        error.put("error", ex.getMessage());
        error.put("status", "400");
        return ResponseEntity.badRequest().body(error);
    }
}

// Использование в контроллере
@RestController
@RequestMapping("/api/v1/users")
public class UserController {
    
    @GetMapping("/{id}")
    public User getUser(@PathVariable Long id) {
        User user = userService.getUserById(id);
        if (user == null) {
            throw new ResourceNotFoundException("User not found: " + id);
        }
        return user;
    }
}

7. Валидация данных (@Valid, @Validated)

// Model с аннотациями валидации
import javax.validation.constraints.*;

public class User {
    @NotNull
    @Positive
    private Long id;
    
    @NotBlank
    @Email
    private String email;
    
    @NotBlank
    @Size(min = 2, max = 50)
    private String firstName;
    
    @NotBlank
    @Size(min = 2, max = 50)
    private String lastName;
    
    // Getters, Setters
}

// RestController с валидацией
@RestController
@RequestMapping("/api/v1/users")
public class UserController {
    
    // @Valid активирует валидацию
    @PostMapping
    public ResponseEntity<User> createUser(@Valid @RequestBody User user) {
        User created = userService.create(user);
        return ResponseEntity.status(HttpStatus.CREATED).body(created);
    }
    // Если валидация не пройдена:
    // 400 Bad Request + детали ошибок
}

// Custom Exception Handler для ошибок валидации
@RestControllerAdvice
public class ValidationExceptionHandler {
    
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<Map<String, Object>> handleValidationException(
            MethodArgumentNotValidException ex) {
        Map<String, Object> errors = new HashMap<>();
        Map<String, String> fieldErrors = new HashMap<>();
        
        ex.getBindingResult().getFieldErrors().forEach(error ->
            fieldErrors.put(error.getField(), error.getDefaultMessage())
        );
        
        errors.put("errors", fieldErrors);
        errors.put("status", 400);
        return ResponseEntity.badRequest().body(errors);
    }
}

8. Пример API с пагинацией

import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;

@RestController
@RequestMapping("/api/v1/users")
public class UserController {
    
    @Autowired
    private UserRepository userRepository;
    
    // GET /api/v1/users?page=0&size=10&sort=name,asc
    @GetMapping
    public Page<User> listUsers(
            @RequestParam(defaultValue = "0") int page,
            @RequestParam(defaultValue = "10") int size) {
        Pageable pageable = PageRequest.of(page, size);
        return userRepository.findAll(pageable);
    }
}

9. Конфигурация Spring Boot Application

// Main Application
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class UserManagementApplication {
    
    public static void main(String[] args) {
        SpringApplication.run(UserManagementApplication.class, args);
    }
}

// application.properties
spring.application.name=user-api
server.port=8080
server.servlet.context-path=/

# Logging
logging.level.root=INFO
logging.level.com.example=DEBUG

10. Тестирование @RestController

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.servlet.MockMvc;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import static org.hamcrest.Matchers.*;

@SpringBootTest
@AutoConfigureMockMvc
public class UserControllerTest {
    
    @Autowired
    private MockMvc mockMvc;
    
    @Test
    public void testGetAllUsers() throws Exception {
        mockMvc.perform(get("/api/v1/users"))
            .andExpect(status().isOk())
            .andExpect(content().contentType("application/json"))
            .andExpect(jsonPath("$", hasSize(greaterThanOrEqualTo(0))));
    }
    
    @Test
    public void testCreateUser() throws Exception {
        String newUser = "{\"email\":\"test@example.com\",\"firstName\":\"Test\",\"lastName\":\"User\"}";
        
        mockMvc.perform(post("/api/v1/users")
                .contentType("application/json")
                .content(newUser))
            .andExpect(status().isCreated())
            .andExpect(jsonPath("$.id", notNullValue()))
            .andExpect(jsonPath("$.email", is("test@example.com")));
    }
}

Итоги

Шаги для создания @RestController:

  1. Аннотируй класс @RestController
  2. Определи @RequestMapping для базового пути
  3. Реализуй методы с @GetMapping, @PostMapping и т.д.
  4. Используй @PathVariable и @RequestBody для параметров
  5. Возвращай объекты (сериализуются в JSON) или ResponseEntity
  6. Добавь валидацию через @Valid
  7. Обработай ошибки через @ExceptionHandler
  8. Протестируй через MockMvc или RestTemplate

@RestController автоматически сериализует все возвращаемые значения в JSON, делая создание REST API просто и удобно.