in Spring

Spring MVC Framework Tutorial

Introduction

In this tutorial I am going to cover spring MVC by creating nice examples on how to

  • Bootstrap your application
  • Add REST APIs
  • Add Services with method security
  • Handle exceptions
  • Add security layer that will force users to authenticate
  • Unit test for Service and Rest Controller

Bootstrap

Bootstrapping spring application is done using several classes that spring gives by default

  • AbstractAnnotationConfigDispatcherServletInitializer

  • WebMvcConfigurerAdapter

First we must create WebInitializer class that will extends  AbstractAnnotationConfigDispatcherServletInitializer class, here we will tell spring what is our root config and our servlet config class( or classes) along with servlet mapping path. Child class will be automatically scanned by spring so that we do not have to do anything.

Here is the example:

Observe that we have set servlet mapping to path / and that we have two spring config classes PomodoroServletConfig  and PomodoroRootConfig .

  • PomodoroServletConfig is used to configure RestControllers and static content handlers.
  • PomodoroRootConfig is used to wire spring beans and other configurations like data sources, security and other

PomodoroRootConfig

 

Lets go through all annotations in above class:

  • @Configuration marks this class as spring configuration class
  • @ComponentScan helps spring find other beans for this case services and security configuration classes ( we will go through this latter).
  • @Import tells that spring should import specified configuration class
  • @PropertySource tells spring that it should import property file into the environment in this case app.properties that can be found in the class path

PomodoroServletConfig

 

Most important annotation is @EnableWebMvc  annotations that enables Spring MVC, also it is equivalent to  <mvc:annotation-driven /> for XML configurations.

Observe that we have used ComponentScan annotation so that all of our RestControllers are auto configured.

I have added resource handler that will help us download static content like photos for example
http://pscode.rs/webapp/resources/logo.png  will download file from   classpath:/META-INF/public-web-resources/logo.png

Note: ComponentScan can accept class as well, using class is better approach since it does  not fail after renaming package. Here package is used so that example can be easily comprehended.

Even now with nothing more but 3 classes we can start our application :), problem is that it would not be able to do anything since we did not add any REST APIs yet.

Spring REST APIs

First thing is first , lets add one Rest Controller to this application. Using @RestController  and @RequestMapping  we are telling spring to map method getPomodoros  to path /.

Response is in JSON format since we have added jackson libs to this project, spring automatically enables JSON response by default. You can examine this feature in class

org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport

Ok, so now we have our application set and running. Lets go through other options and features.

RequestMapping additional options

RequestMapping annotation can be added on method and on the class, this can be quite handy in case where we have main path and extra paths for actions like update, delete and so on… For example our main path would be /pomodoro  and extra path is /pomodoro/find-max, as you can see we have /pomodoro twice :(. Here is how to solve this:

URL to getMax() will be /pomodoro/find-max

HTTP Request Type currently is not specified, this means that all http request types ( GET, POST, PUT… ) that use this URL will hit method getMax.

RequestMapping options:

  • Value, used to filter path for example /find-max
  • Method, used to filter http request method. Possible values are enum values RequestMethod {GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE}
  • Params, used to filter requests that have required parameters, example is myParam=myValue, or myParam!=myValue , or !MyParam
  • Headers, used to filter requests that have required headers present, example is My-Header=myValue, My-Header!=myValue or !MyHeader, also My-Header=my* can be used.
  • Consumes, used to filter consumable media types of the request, example is consumes={“text/plain”, application/*} or !text/plain
  • Produces, used to filter producible media types example is produces = “text/plain” or produces = {“text/plain”, “application/*”}

Above RequestMapping options are used to filter request but when request hits the method we can map request parameters to method arguments using few handy annotations.

Here are all possibilities for parameter annotations

  • @PathVariable, lets assume that our url is /find-max/{pomodoroType} when request comes as /find-max/AwesomePomodoro  we would like that AwesomePomodoro value maps to one method argument that we like. @PathVariable String pomodoroType .
    We can also map path variable to custom named parameter by specifying PathVariable value @PathVariable("customParam"). This also works for enumerations.
  • @CookieValue
  • @RequestHeader
  • @RequestParam
  • @RequestBody, is used to tell spring to convert request body to the instance of object that we specify(ie PomodoroRequestJson).
  • @MatrixVariable, is used to max matrix parameters here is nice example from spring official page

Services and @Autowire annotation

To make things interesting lets add one service that will be autowired into rest controller. Service is going to be PomodoroService and its implementation PomodoroServiceImpl. Two thins are important in the service implementation class, first is that class is annotated with @Component making the class interesting for component scanning and @Secured annotation on methods that helps us make sure that only users with correct role can “call” this method.

To wire PomodoroService into RestController we can use @Autowire annotation.

Handling exceptions

When exception occurs it is important that your backend responds in a such way that caller will be able to understand the problem, process it and respond to it in proper manner ( show error message to the user). Here is one RestController that throws exception called MissingPomodoroException.

Observe usage of @PathVariable , idea is that this method returns pomodoro with specified id. In case when it is missing HTTP response should be  HttpStatus.NOT_FOUND.  We could handle exceptions here in the getPomodoro method but this would not be good approach. It is better to have one class( or small set of classes) that deal with exceptions and convert them to responses with right details.

To do this we will define a class with annotation @ControllerAdvice that extends ResponseEntityExceptionHandler.

ResponseEntityExceptionHandler is the class that handles default spring exceptions like NoSuchRequestHandlingMethodException and other. Just override methods that you are interested in the specify your own response.

Here is how to handle exceptions specific to your application

I have defined class ErrorResponse that will be standard response when error occurs . Here how this response looks like with correct HttpStatus NOT_FOUND.

Security layer

Hm, looking what we covered so far you may noticed that everyone can get read anything :), this is never smart idea. Lets fix this in a nice way using spring security. Here is a short list of what we need to do to accomplish this.

  • Enable Spring MVC Security
  • First we are going to secure all paths so that only registered users can add and list pomodoros
  • Demonstrate several ways of authentication

Enable Spring security with method security

For spring security to be enabled two components are required

  1. Security Web initialiser
  2. Web security configurer

Here we have securityConfig where we have enabled in memory authentication for two users (admin and user) and paths security is set like this:

  • /pomodoro/** can be accessed by users only
  • /signup can be accessed by all
  • All other paths can be accessed by authenticated users
  • csrf is disabled
  • Basic authentication is enabled
  • All unauthenticated users have role Anonymous.

Setting up spring MVC with spring security is not hard and with just few classes and lines of code you have have nice REST API enabled backend application with security.

You may have noticed @EnableGlobalMethodSecurity this handy annotation enables us to secure our service methods. Check the PomodoroServiceImpl methods you will notice @Secured annotation.

Unit Testing

Testing the services and rest controllers is every developer primary concern , in next short code listing I will show how to test PomodoroService and PomodoroCollectionResource.

Testing PomodoroService

 

Testing RestControllers

RestControllers testing can be a bit complicated because of number of things developer needs take care of , one is http response, http request , authentication …  Here is a simple example that demonstrates how to test json response with single object or array or objects in this case pomodoros.

 

I do really hope that this post will help you kick start your spring MVC projects. In future posts we will go through other spring projects.

Happy coding.

 

Write a Comment

Comment