In this blog, we will learn the difference between @Controller and @RestController. How @RestController works internally – with the help of a working example.
Usually, dispatcher servlet is responsible for identifying the controller and appropriate request handler method inside the controller by URL matching.
@Controller: A spring mvc controller is used typically in GUI-based applications where the response is generally HTML content.
e.g.
@Controller
@ResponseBody
@RequestMapping("employees")
public class EmployeeController
{
@RequestMapping(value = "/{name}", method = RequestMethod.GET, produces = "application/json")
public Employee getEmployeeByName(@PathVariable String name) {
//pull date
return employee;
}
}
@RestController: It is a convenience annotation that is itself annotated with @Controller
and @ResponseBody
. The handler methods will return the JSON/XML response directly to client rather using view resolvers.
e.g.
@RestController
@RequestMapping("employees")
public class EmployeeController
{
@RequestMapping(value = "/{name}", method = RequestMethod.GET, produces = "application/json")
public Employee getEmployeeByName(@PathVariable String name) {
//pull date
return employee;
}
}
package com.the.basic.tech.info.rest.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
// http://localhost:8080/spring-boot-rest-api/userlogin
// http://localhost:8080/spring-boot-rest-api/adminlogin
@RestController
public class SpringBootRestController {
@RequestMapping("/userlogin")
public String userValidation() {
return "User: Successfully logged in!";
}
@RequestMapping("/adminlogin")
public String adminValidation() {
return "Admin: Successfully logged in!";
}
}
Maven dependencties file would be like as below
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>spring-boot-rest-api</artifactId>
<version>0.0.1-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.4</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
<properties>
<java.version>1.8</java.version>
</properties>
</project>
High level project structure
We need to extend WebSecurityConfigurerAdapter class as below
package com.the.basic.tech.info.rest.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
public class SpringBootSecurityConfig extends WebSecurityConfigurerAdapter {
// Authentication : set user/password details and mention the role
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.passwordEncoder(org.springframework.security.crypto.password.NoOpPasswordEncoder.getInstance())
.withUser("user").password("pass").roles("USER").and().withUser("admin").password("pass")
.roles("USER", "ADMIN");
}
// Authorization : mention which role can access which URL
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic().and().authorizeRequests().antMatchers("/userlogin").hasRole("USER").antMatchers("/adminlogin")
.hasRole("ADMIN").and()
// sample logout customization
.logout().logoutUrl("/logout").deleteCookies("remove").invalidateHttpSession(false).and().csrf()
.disable().headers().frameOptions().disable();
}
}
Actuator endpoints we are using here for application health monitoring.
# Management
server:
port: 8080
servlet.context-path: /spring-boot-rest-api/
endpoints:
hawtio:
enabled: true
jolokia:
enabled: true
management:
endpoints:
web:
exposure:
include: info, health, metrics, hawtio, env
base-path: /monitoring
endpoint:
health:
show-details: always
info:
app:
spring-boot-rest-api
description:This is a microservice for springboot application testing
package com.the.basic.tech.info.rest;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringBootRestMain {
public static void main(String[] args) {
SpringApplication.run(SpringBootRestMain.class, args);
}
}
We need to run below maven command for running the application.
mvn spring-boot:run
Application Logs:
2021-06-05 20:25:26.427 INFO 7700 --- [ main] c.t.b.tech.info.rest.SpringBootRestMain : No active profile set, falling back to default profiles: default
2021-06-05 20:25:29.432 INFO 7700 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2021-06-05 20:25:29.455 INFO 7700 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2021-06-05 20:25:29.456 INFO 7700 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.44]
2021-06-05 20:25:29.768 INFO 7700 --- [ main] o.a.c.c.C.[.[.[/spring-boot-rest-api] : Initializing Spring embedded WebApplicationContext
2021-06-05 20:25:29.768 INFO 7700 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 3243 ms
2021-06-05 20:25:30.921 INFO 7700 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2021-06-05 20:25:31.502 INFO 7700 --- [ main] o.s.s.web.DefaultSecurityFilterChain : Will secure any request with [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@8f2098e, org.springframework.security.web.context.SecurityContextPersistenceFilter@35764bef, org.springframework.security.web.header.HeaderWriterFilter@131ff6fa, org.springframework.security.web.authentication.logout.LogoutFilter@58860997, org.springframework.security.web.authentication.www.BasicAuthenticationFilter@161f6623, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@5d5160e6, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@d8d9199, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@6c6366cf, org.springframework.security.web.session.SessionManagementFilter@216914, org.springframework.security.web.access.ExceptionTranslationFilter@3ae9d1e2, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@f679798]
2021-06-05 20:25:31.538 INFO 7700 --- [ main] o.s.b.a.e.web.EndpointLinksResolver : Exposing 4 endpoint(s) beneath base path '/monitoring'
2021-06-05 20:25:31.619 INFO 7700 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '/spring-boot-rest-api'
2021-06-05 20:25:31.651 INFO 7700 --- [ main] c.t.b.tech.info.rest.SpringBootRestMain : Started SpringBootRestMain in 6.047 seconds (JVM running for 6.878)
2021-06-05 20:25:31.899 INFO 7700 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/spring-boot-rest-api] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2021-06-05 20:25:31.899 INFO 7700 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2021-06-05 20:25:31.907 INFO 7700 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 3 ms
Admin Login, it will prompt for username/password: http://localhost:8080/spring-boot-rest-api/adminlogin
username/password: admin/pass
User Login, it will prompt for username/password: http://localhost:8080/spring-boot-rest-api/userlogin
username/password: user/pass
And after successful login, it will display below screen.
Kindly, let me know in case I missed anything. Have a nice day 🙂