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

Какие знаешь ключевые признаки обычного контроллера?

2.2 Middle🔥 191 комментариев
#Базы данных и SQL

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

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

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

Ключевые признаки обычного контроллера в Spring

Обычный контроллер (traditional/view controller, не REST) имеет характерные отличия от REST контроллеров. Давайте рассмотрим основные признаки и различия.

1. Аннотация @Controller

Основной признак — использование аннотации @Controller вместо @RestController:

// ✓ Обычный контроллер
@Controller
@RequestMapping("/users")
public class UserController {
    // ...
}

// ❌ REST контроллер (другой подход)
@RestController
@RequestMapping("/api/v1/users")
public class UserRestController {
    // ...
}

2. Возвращает String (имя View)

Обычный контроллер возвращает логическое имя представления (view), а не объекты данных:

@Controller
public class HomeController {
    
    @GetMapping("/")
    public String home() {
        return "home"; // Возвращает имя шаблона (home.html, home.jsp)
    }
    
    @GetMapping("/about")
    public String about() {
        return "about"; // about.html или about.jsp
    }
    
    @GetMapping("/contact")
    public String contact() {
        return "contact"; // contact.html
    }
}

Spring автоматически ищет шаблон с таким именем в папке templates/ (для Thymeleaf) или WEB-INF/jsp/ (для JSP).

3. Использует Model для передачи данных

Для передачи данных в шаблон используется объект Model:

@Controller
@RequestMapping("/products")
public class ProductController {
    
    @Autowired
    private ProductService productService;
    
    @GetMapping
    public String listProducts(Model model) {
        List<Product> products = productService.getAllProducts();
        model.addAttribute("products", products); // Передаём в шаблон
        model.addAttribute("title", "All Products");
        return "products/list"; // products/list.html
    }
    
    @GetMapping("/{id}")
    public String showProduct(@PathVariable Long id, Model model) {
        Product product = productService.getProductById(id);
        model.addAttribute("product", product);
        model.addAttribute("relatedProducts", productService.getRelated(id));
        return "products/detail"; // products/detail.html
    }
    
    @PostMapping
    public String createProduct(@ModelAttribute Product product, Model model) {
        Product saved = productService.save(product);
        model.addAttribute("success", true);
        return "products/created"; // products/created.html
    }
}

4. Работает с HTML формами

Обычный контроллер часто обрабатывает HTML формы с использованием @ModelAttribute:

@Controller
@RequestMapping("/users")
public class UserFormController {
    
    @Autowired
    private UserService userService;
    
    // Показываем форму
    @GetMapping("/register")
    public String showRegistrationForm(Model model) {
        model.addAttribute("user", new User()); // Пустой объект для формы
        return "registration"; // registration.html
    }
    
    // Обрабатываем отправку формы
    @PostMapping("/register")
    public String registerUser(
        @ModelAttribute User user, // Автоматически заполняется из POST параметров
        BindingResult bindingResult,
        Model model) {
        
        // Валидация
        if (bindingResult.hasErrors()) {
            return "registration"; // Повторно показываем форму с ошибками
        }
        
        userService.register(user);
        model.addAttribute("message", "Registration successful!");
        return "registration-success"; // registration-success.html
    }
}

5. Использует Template Engine (Thymeleaf, FreeMarker, JSP)

Данные обрабатываются на сервере и вставляются в HTML шаблон:

<!-- templates/products/list.html (Thymeleaf) -->
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title th:text="${title}">Products</title>
</head>
<body>
    <h1 th:text="${title}">All Products</h1>
    
    <table>
        <tr>
            <th>Name</th>
            <th>Price</th>
        </tr>
        <tr th:each="product : ${products}">
            <td th:text="${product.name}">Product Name</td>
            <td th:text="${product.price}">$0.00</td>
        </tr>
    </table>
</body>
</html>
// Контроллер передаёт данные
@GetMapping
public String listProducts(Model model) {
    List<Product> products = productService.getAllProducts();
    model.addAttribute("products", products);
    model.addAttribute("title", "All Products");
    return "products/list"; // Thymeleaf обработает шаблон
}

6. Редирект вместо JSON

Обычно после обработки формы контроллер выполняет redirect (перенаправление) на другую страницу:

@Controller
@RequestMapping("/orders")
public class OrderController {
    
    @Autowired
    private OrderService orderService;
    
    @PostMapping
    public String createOrder(@ModelAttribute Order order) {
        Order saved = orderService.save(order);
        // Редирект на страницу просмотра заказа
        return "redirect:/orders/" + saved.getId(); // Редирект
    }
    
    @GetMapping("/{id}")
    public String viewOrder(@PathVariable Long id, Model model) {
        Order order = orderService.findById(id);
        model.addAttribute("order", order);
        return "orders/view"; // orders/view.html
    }
}

7. Не использует @ResponseBody

Обычный контроллер не аннотирует методы с @ResponseBody:

// ❌ Неправильно для обычного контроллера
@Controller
public class BadController {
    @GetMapping
    @ResponseBody // Не нужна!
    public String getData() {
        return "{\"data\": \"value\"}"; // Это будет возвращено как text/plain
    }
}

// ✓ Правильно
@Controller
public class GoodController {
    @GetMapping
    public String getData(Model model) {
        model.addAttribute("data", "value");
        return "mypage"; // mypage.html
    }
}

8. Работает с SessionAttributes

Для хранения данных сессии используется аннотация @SessionAttributes:

@Controller
@RequestMapping("/checkout")
@SessionAttributes("cart") // Хранить корзину в сессии
public class CheckoutController {
    
    @GetMapping("/step1")
    public String step1(Model model) {
        Cart cart = new Cart();
        model.addAttribute("cart", cart);
        return "checkout/step1"; // checkout/step1.html
    }
    
    @PostMapping("/step1")
    public String processStep1(
        @ModelAttribute Cart cart, // Автоматически из сессии
        RedirectAttributes redirectAttributes) {
        
        // Обрабатываем step 1
        return "redirect:/checkout/step2"; // Переход на step 2
    }
    
    @GetMapping("/step2")
    public String step2(@ModelAttribute Cart cart, Model model) { //Cart из сессии
        model.addAttribute("cart", cart);
        return "checkout/step2"; // checkout/step2.html
    }
}

9. Post-Redirect-Get (PRG) паттерн

Обычный контроллер следует паттерну PRG для обработки форм:

@Controller
public class CommentController {
    
    // GET — показываем форму
    @GetMapping("/comments/new")
    public String showCommentForm(Model model) {
        model.addAttribute("comment", new Comment());
        return "comment-form"; // comment-form.html
    }
    
    // POST — обрабатываем форму
    @PostMapping("/comments")
    public String saveComment(@ModelAttribute Comment comment) {
        commentService.save(comment);
        // Редирект (не вернуть шаблон!)
        return "redirect:/comments/" + comment.getId();
    }
    
    // GET — показываем результат
    @GetMapping("/comments/{id}")
    public String viewComment(@PathVariable Long id, Model model) {
        Comment comment = commentService.findById(id);
        model.addAttribute("comment", comment);
        return "comment-view"; // comment-view.html
    }
}

Сравнение: @Controller vs @RestController

Признак@Controller@RestController
ВозвращаетView name (String)JSON/XML (объекты)
Использует ModelДаНет
Использует Template EngineДаНет
Обрабатывает формыДаРедко
Content-Typetext/htmlapplication/json
РедиректыЧастоРедко
@ResponseBody нужнаНетАвтоматична
SessionAttributesЧастоРедко
ЦельВеб-приложения (MVC)REST API

Полный пример обычного контроллера

@Controller
@RequestMapping("/blog")
public class BlogController {
    
    @Autowired
    private BlogService blogService;
    
    @Autowired
    private CommentService commentService;
    
    // Показать список статей
    @GetMapping
    public String list(
        @RequestParam(defaultValue = "0") int page,
        Model model) {
        List<Post> posts = blogService.getPostsByPage(page);
        model.addAttribute("posts", posts);
        model.addAttribute("currentPage", page);
        return "blog/list"; // blog/list.html
    }
    
    // Показать одну статью
    @GetMapping("/{slug}")
    public String view(
        @PathVariable String slug,
        Model model) {
        Post post = blogService.getBySlug(slug);
        List<Comment> comments = commentService.getByPostId(post.getId());
        
        model.addAttribute("post", post);
        model.addAttribute("comments", comments);
        model.addAttribute("newComment", new Comment());
        
        return "blog/post-detail"; // blog/post-detail.html
    }
    
    // Обработать добавление комментария
    @PostMapping("/{slug}/comments")
    public String addComment(
        @PathVariable String slug,
        @ModelAttribute Comment comment) {
        Post post = blogService.getBySlug(slug);
        comment.setPost(post);
        commentService.save(comment);
        
        // PRG паттерн — редирект
        return "redirect:/blog/" + slug;
    }
}

Когда использовать @Controller

  • ✓ Традиционные веб-приложения (MVC)
  • ✓ Приложения с шаблонами (Thymeleaf, JSP)
  • ✓ Обработка HTML форм
  • ✓ Server-side rendering
  • ✓ Полные веб-сайты (не API)

В современной разработке обычные контроллеры использую меньше, так как популярны:

  • Frontend frameworks (React, Vue, Angular) + REST API
  • Single Page Applications (SPA)
  • API-first подход

Однако для простых админ-панелей, внутренних систем и traditional веб-приложений обычные контроллеры остаются удобным решением.