You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring框架中如何用@RestController返回视图并作为REST服务使用

在Spring中使用@RestController返回视图及兼顾REST服务的方案

Alright, let's break this down clearly since @RestController has a specific default behavior that trips up a lot of developers when they want to return views alongside REST responses. First, a quick reminder: @RestController is just a combination of @Controller and @ResponseBody, meaning every method in it defaults to returning a JSON/XML response body instead of a view name. To return views, we need to work around that default.


1. 在@RestController中返回视图的两种方法

方法一:使用ModelAndView对象

The simplest way to bypass the default @ResponseBody behavior is to return a ModelAndView directly. Spring will recognize this type and hand it off to your configured view resolver instead of serializing it as a response body.

Example code:

@RestController
public class ViewReturningController {

    @GetMapping("/welcome")
    public ModelAndView showWelcomePage() {
        // "welcome" refers to your view file (e.g., welcome.html for Thymeleaf, welcome.jsp for JSP)
        ModelAndView mav = new ModelAndView("welcome");
        // Add data to pass to the view
        mav.addObject("greeting", "Hello from @RestController!");
        return mav;
    }
}

Just make sure your view resolver is properly set up (e.g., Thymeleaf configured to look in src/main/resources/templates/) so Spring can find the view file.

方法二:直接返回View对象

If you don't need to pass model data and just want to return a view, you can return a concrete View implementation like InternalResourceView (for JSP) or let Spring auto-resolve it via a view name.

Example:

@RestController
public class SimpleViewController {

    @GetMapping("/about")
    public View showAboutPage() {
        // Points directly to the "about" view
        return new InternalResourceView("about");
    }
}

2. 让@RestController同时支持视图返回和REST服务

The common use case here is having a controller that serves both UI pages (via views) and API endpoints (via JSON/XML responses). This is straightforward—you just mix the two approaches above.

场景一:分离视图方法和REST方法

Create separate methods for each purpose: REST methods return objects (automatically serialized to JSON), and view methods return ModelAndView or View.

Example:

@RestController
@RequestMapping("/app")
public class MixedController {

    // REST API endpoint: returns JSON
    @GetMapping("/users/{id}")
    public User getUserDetails(@PathVariable Long id) {
        User user = new User();
        user.setId(id);
        user.setName("Maria Garcia");
        user.setEmail("maria@example.com");
        return user; // Auto-converted to JSON
    }

    // View endpoint: returns rendered HTML page
    @GetMapping("/dashboard")
    public ModelAndView showDashboard() {
        ModelAndView mav = new ModelAndView("dashboard");
        mav.addObject("totalUsers", 250);
        mav.addObject("recentActivity", "5 new users in the last hour");
        return mav;
    }
}

Now:

  • Visiting /app/users/1 gives you a JSON response with user data.
  • Visiting /app/dashboard renders the dashboard HTML page with the provided model data.

场景二:根据请求类型动态返回视图或REST响应

If you want a single endpoint to return either a view or JSON based on the client's request (e.g., via the Accept header or a query parameter), you can implement content negotiation.

Option 1: Manual condition check

Check the request's Accept header or a query parameter to decide what to return:

@RestController
public class ContentNegotiationController {

    @GetMapping("/data")
    public Object getData(HttpServletRequest request) {
        String acceptHeader = request.getHeader("Accept");
        
        if (MediaType.APPLICATION_JSON_VALUE.equalsIgnoreCase(acceptHeader)) {
            // Return JSON for API clients
            Product product = new Product(101, "Wireless Headphones", 99.99);
            return product;
        } else {
            // Return view for browsers
            ModelAndView mav = new ModelAndView("productView");
            mav.addObject("product", new Product(101, "Wireless Headphones", 99.99));
            return mav;
        }
    }
}

Option 2: Spring's built-in content negotiation

For a more elegant solution, configure Spring's content negotiation to automatically handle this. First, add a configuration class:

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
        configurer
            .favorParameter(true) // Allow using a "format" query parameter
            .parameterName("format")
            .defaultContentType(MediaType.TEXT_HTML) // Default to view
            .mediaType("html", MediaType.TEXT_HTML)
            .mediaType("json", MediaType.APPLICATION_JSON);
    }
}

Then update your controller method to return a model object and add data to the Model for views:

@RestController
public class SmartController {

    @GetMapping("/product/{id}")
    public Product getProduct(@PathVariable Long id, Model model) {
        Product product = new Product(id, "Laptop", 999.99);
        model.addAttribute("product", product); // Pass data to view
        return product; // Spring decides: JSON if format=json, view otherwise
    }
}

Now:

  • /product/101 → Renders the productView HTML page.
  • /product/101?format=json → Returns the product data as JSON.

Key Notes

  • Ensure your project has a view resolver configured (e.g., Thymeleaf, JSP) to resolve the view names you return.
  • @RestController's default @ResponseBody only applies to methods that return non-view types. Returning ModelAndView or View tells Spring to render a view instead.

内容的提问来源于stack exchange,提问作者Ferdous Islam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 12:04:45