My FeedDiscussionsHeadless CMS
New
Sign in
Log inSign up
Learn more about Hashnode Headless CMSHashnode Headless CMS
Collaborate seamlessly with Hashnode Headless CMS for Enterprise.
Upgrade ✨Learn more
Spring Boot Rest Example

Spring Boot Rest Example

saravanagumar's photo
saravanagumar
·Mar 27, 2018

I recently started taking a look into Angular 2 and though about a proper project setup in combination with Spring RestControllers. During development, the front-end Angular 2 application will run via Webpack and the Spring Boot application with an embedded Tomcat. All RestController should use a common base path, since I plan to run the Angular 2 application together with the Spring application in a production environment. The test scenario is a simple index.html file that should be hosted in the URL ‘/index.html’ and RestController hosted in ‘/api/hello’

Expected URL structure

/index.html – angular app placeholder

/api/hello – Endpoint for a rest controller

I recommend downloading the source of this example before you start. Link to the repository blog_rest-controller-base-path direct link to the source zip source-zip

purpose of this post:

Spring configuration for the base path of all RestControllers Custom annotation that combines @RestController and @RequestMapping

Spring configuration

The starting point is a Spring Boot project generated with start.spring.io with just the web dependency.

The only necessary configuration is a bean of type WebMvcRegistrationsAdapter that was introduced with Spring Boot 1.4.0. This class allows to define a custom implementation of the RequestMappingHandlerMapping via overriding ‘getRequestMappingHanlderMapping’. As usual with Spring Boot we can declare such a bean in any class that is annotation with @Configuration.

In this implementation we check if the declaring annotation is annotated with @RestController. It is a good approach to use the AnnotationUtils class for this check since it traverses interfaces, annotations, and superclasses.

In this implementation we define a new pattern that starts with ‘api’ and is followed by the existing patter. If the @RestController annotation is present.

WebConfig.java

@Configuration
public class WebConfig {

    @Bean
    public WebMvcRegistrationsAdapter webMvcRegistrationsHandlerMapping() {
        return new WebMvcRegistrationsAdapter() {
            @Override
            public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
                return new RequestMappingHandlerMapping() {
                    private final static String API_BASE_PATH = "api";

                    @Override
                    protected void registerHandlerMethod(Object handler, Method method, RequestMappingInfo mapping) {
                        Class<?> beanType = method.getDeclaringClass();
                        if (AnnotationUtils.findAnnotation(beanType, RestController.class) != null) {
                            PatternsRequestCondition apiPattern = new PatternsRequestCondition(API_BASE_PATH)
                                    .combine(mapping.getPatternsCondition());

                            mapping = new RequestMappingInfo(mapping.getName(), apiPattern,
                                    mapping.getMethodsCondition(), mapping.getParamsCondition(),
                                    mapping.getHeadersCondition(), mapping.getConsumesCondition(),
                                    mapping.getProducesCondition(), mapping.getCustomCondition());
                        }

                        super.registerHandlerMethod(handler, method, mapping);
                    }
                };
            }
        };
    }

}

here it is used to test if the our controllers are now hosted relative to the ‘api’ path.

HelloController.java

@RestController
@RequestMapping("hello")
public class HelloController {

    @RequestMapping
    public Hello all() {
        Hello hello = new Hello();
        hello.setText("Hello api");
        return hello;
    }
}

We expect that static content will still be available in the root path ‘/’

resources/static/index.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Hello page</title>
</head>
<body>
Hello world!
</body>
</html>

Custom annotation combining @RestController and @RequestMapping Once you write multiple controllers, it is necessary to annotated all of them with @RestController and @RequestMapping(“subpath”). This can combined into a custom annotation. I named it @RestApiController that expects a parameter for the subpath similar to @RequestMapping.

The @AliasFor annotation introduced with Spring 4.2 allows to pass the parameter to another annotation. For our case we pass the value from @RestApiController to @RequestMapping

RestApiController.java

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@RestController
@RequestMapping
public @interface RestApiController {

 @AliasFor(annotation = RequestMapping.class, attribute = "value")
 String[] value();

}

The modified controller using this annotation looks like the following.

@RestApiController("hello")
public class HelloController {

    @RequestMapping
    public Hello all() {
        Hello hello = new Hello();
        hello.setText("Hello api");
        return hello;
    }
}

RESOURCES:

SPRING BOOT REST EXAMPLE

SPRING OFFICIAL