We usually use the @Controller annotation to develop Spring MVC applications, but since version 4.x, Spring has introduced another annotation called @RestController. What is the purpose of annotation @RestController? What is the difference between @Controller annotation and @RestController annotation? In this tutorial, let’s find out!
First, I will create a new Maven project as an example:
If You do not know how to create this project, please follow the instructions of this tutorial.
The default dependencies have changed version as follows:
1 2 3 4 5 6 |
<properties> <java-version>1.8</java-version> <org.springframework-version>5.0.0.RELEASE</org.springframework-version> <org.aspectj-version>1.8.11</org.aspectj-version> <org.slf4j-version>1.7.25</org.slf4j-version> </properties> |
To run this project, I will use Maven Jetty Pluggin:
1 2 3 4 5 |
<plugin> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-maven-plugin</artifactId> <version>9.4.7.v20170914</version> </plugin> |
OK, let’s get started.
As you all know, in Spring MVC, the controller is the class that will be responsible for preparing the Model and selecting View to display the data in the Model to the View. In the example we just created, we have the HomeController class as a Controller class.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
package com.huongdanjava.springmvc; import java.text.DateFormat; import java.util.Date; import java.util.Locale; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; /** * Handles requests for the application home page. */ @Controller public class HomeController { private static final Logger logger = LoggerFactory.getLogger(HomeController.class); /** * Simply selects the home view to render by returning its name. */ @RequestMapping(value = "/", method = RequestMethod.GET) public String home(Locale locale, Model model) { logger.info("Welcome home! The client locale is {}.", locale); Date date = new Date(); DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale); String formattedDate = dateFormat.format(date); model.addAttribute("serverTime", formattedDate ); return "home"; } } |
It adds the “serverTime” data to the Model and selects View as the home.jsp file located in /src/main/webapp/WEB-INF/views to render the interface.
The results will look like this:
Beside preparation Model and selecting View, Controller class can also write data directly into the response stream without having to select any View. To do this, in the handle request method, we have to add another annotation, @ResponseBody.
For example, now, I add the @ResponseBody annotation to the home() method in the HomeController class as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
/** * Simply selects the home view to render by returning its name. */ @RequestMapping(value = "/", method = RequestMethod.GET) @ResponseBody public String home(Locale locale, Model model) { logger.info("Welcome home! The client locale is {}.", locale); Date date = new Date(); DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale); String formattedDate = dateFormat.format(date); model.addAttribute("serverTime", formattedDate ); return "home"; } |
When running, you will no longer see results as before. Instead of the content of the home.jsp file with the Model data, the result is only “home” as the return portion of the home() method.
This is what we usually do to develop RESTful Web Service applications. We only return data in formats such as JSON, XML, … and no View is needed.
For the sake of developing RESTful Web Service applications, Spring has introduced the @RestController annotation from version 4.x. With @RestController annotation replacing @Controller annotation, we do not need to declare annotation @ResponseBody anymore.
Now if I replace @Controller annotation with @RestController annotation and remove annotation @ResponseBody in the home() method:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
package com.huongdanjava.springmvc; import java.text.DateFormat; import java.util.Date; import java.util.Locale; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; /** * Handles requests for the application home page. */ @RestController public class HomeController { private static final Logger logger = LoggerFactory.getLogger(HomeController.class); /** * Simply selects the home view to render by returning its name. */ @RequestMapping(value = "/", method = RequestMethod.GET) public String home(Locale locale, Model model) { logger.info("Welcome home! The client locale is {}.", locale); Date date = new Date(); DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale); String formattedDate = dateFormat.format(date); model.addAttribute("serverTime", formattedDate ); return "home"; } } |
The result is the same.
If you look at the code of @RestController annotation, you will see clearly the combination.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
/* * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.web.bind.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.springframework.stereotype.Controller; /** * A convenience annotation that is itself annotated with * {@link Controller @Controller} and {@link ResponseBody @ResponseBody}. * <p> * Types that carry this annotation are treated as controllers where * {@link RequestMapping @RequestMapping} methods assume * {@link ResponseBody @ResponseBody} semantics by default. * * <p><b>NOTE:</b> {@code @RestController} is processed if an appropriate * {@code HandlerMapping}-{@code HandlerAdapter} pair is configured such as the * {@code RequestMappingHandlerMapping}-{@code RequestMappingHandlerAdapter} * pair which are the default in the MVC Java config and the MVC namespace. * * @author Rossen Stoyanchev * @author Sam Brannen * @since 4.0 */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Controller @ResponseBody public @interface RestController { /** * The value may indicate a suggestion for a logical component name, * to be turned into a Spring bean in case of an autodetected component. * @return the suggested component name, if any * @since 4.0.1 */ String value() default ""; } |