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/1gives you a JSON response with user data. - Visiting
/app/dashboardrenders 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 theproductViewHTML 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@ResponseBodyonly applies to methods that return non-view types. ReturningModelAndVieworViewtells Spring to render a view instead.
内容的提问来源于stack exchange,提问作者Ferdous Islam

