RESTful Spring MVC and ExtJs (Episode 1, The Spring Stuff)

My latest adventures have taken me to a client replacing legacy Flex apps with ExtJs apps backed by Spring. In this two part post, you’ll see the product of the many bits of documentation, examples and blog posts I had to cobble together to get this set up, in hopes that it will serve as a complete example for someone else.

Background
If I had my druthers, I’d choose something a little more lightweight for the task at hand – at one time, this was supposed to be a Grails back end, and I was looking forward to getting back in to that mix. That option vaporized and we are now taking it a little slower with a Spring back-end. Thankfully, I work with folks that can make a little lemonade of that lemon, and we’re at least working with pretty close-to-the-latest core Spring, Spring MVC, Spring Data – version 3.2.1.

At the end of this post, you’ll have a working RESTful API provided by Spring using Spring MVC, and some of it’s new features. The source code is on Github so you can follow along. I will walk through the app’s configuration as well as the particulars of the controller class that will serve the front end.

Getting Started
We’ll start with the basic project layout and required jars:

ExtJs Project Layout

<ivy-module version="2.0">
    <info organisation="com.rodenbostel" module="SpringExtJs"/>
    <dependencies>
        <dependency org="org.springframework" name="spring-aop" rev="3.2.1.RELEASE" />
        <dependency org="org.springframework" name="spring-beans" rev="3.2.1.RELEASE" />
        <dependency org="org.springframework" name="spring-core" rev="3.2.1.RELEASE" />
        <dependency org="org.springframework" name="spring-context" rev="3.2.1.RELEASE" />
        <dependency org="org.springframework" name="spring-context-support" rev="3.2.1.RELEASE" />
        <dependency org="org.springframework" name="spring-web" rev="3.2.1.RELEASE" />
        <dependency org="org.springframework" name="spring-webmvc" rev="3.2.1.RELEASE" />
        <dependency org="org.codehaus.jackson" name="jackson-core-asl" rev="1.9.12" />
        <dependency org="org.codehaus.jackson" name="jackson-mapper-asl" rev="1.9.12" />
        <dependency org="cglib" name="cglib-nodep" rev="2.2.2" />
    </dependencies>
</ivy-module>

Spring MVC Config
Spring 3.2 provides java-based Spring configuration (docs here). We’ll see a few examples of that here. The dispatcher servlet declaration and config remain in XML – all other bean declarations and config will be in java. First, in our web.xml file (/web/WEB-INF/web.xml), we need to configure the Spring MVC Dispatcher Servlet, as well as the Context Loader and it’s config locations. You can see a few important things here. The dispatcher servlet config itself, and it’s servlet mapping are near the bottom. They handle request routing, and will route requests behind “/spring/” to Spring MVC. We also see two context-params – the first (ContextClass) will tell Spring MVC to accept annotated classes as input in place of XML. The second (contextConfigLocation) will tell Spring MVC in which package to find the annotated classes that will make up the Spring config. Here is the web.xml in question:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
		  http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
           version="2.5">

    <context-param>
        <param-name>contextClass</param-name>
        <param-value>
            org.springframework.web.context.support.AnnotationConfigWebApplicationContext
        </param-value>
    </context-param>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>com.rodenbostel.springextjs.config</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/spring/*</url-pattern>
    </servlet-mapping>

    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
    </welcome-file-list>
</web-app>

Next up is configuring the dispatcher servlet itself in dispatcher-servlet.xml. Not much to do here – we’re simply telling Spring MVC that we’ll be using annotations to drive our config. Note that by default, Spring MVC provides JSON request marshalling/unmarshalling using the given config (more on that later).

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!-- Enables the Spring MVC @Controller programming model -->
    <mvc:annotation-driven/>

</beans>

Moving On…
…to the interesting parts. We’ll start with the java based config. In this example, we’ll rely on component scanning and autowiring, and keep the config to a minimum. We’ll be scanning the ‘com.rodenbostel.springextjs’ package for more Spring Beans…

package com.rodenbostel.springextjs.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.rodenbostel.springextjs")
public class Config {
}

RESTful Controller
You can see the annotated controller below. There is quite a bit of config directly in the file, but from the start, you should notice that the class is marked with the controller interface annotation. Spring will recognize this during the context scan and make this a Spring bean. Next, we see five methods – one for each of the 4 familiar operations of CRUD, plus one that retrieves a single item for convenience sake, though still providing the same interface from the caller’s perspective. The 5 methods follow the paradigm used by scaffolded RESTful controllers created by Grails and Rails. In our app, the items the interface is being provided for are called ‘Gizmos’.

package com.rodenbostel.springextjs.controllers;

import com.rodenbostel.springextjs.viewmodel.Gizmo;
import com.rodenbostel.springextjs.viewmodel.ManyGizmoResponse;
import com.rodenbostel.springextjs.viewmodel.SingleGizmoResponse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;

    @Controller
    public class ExampleGizmoController {

        @RequestMapping(value="/gizmos/{gizmoId}", method= RequestMethod.GET, produces=APPLICATION_JSON_VALUE)
        @ResponseBody
        public SingleGizmoResponse getFact(@PathVariable Long gizmoId) throws IOException {
            System.out.println("Gizmo retrieved.");
            return new SingleGizmoResponse(true,new Gizmo(1L,"HELLO"));
        }

        @RequestMapping(value="/gizmos", method= RequestMethod.GET, produces=APPLICATION_JSON_VALUE)
        @ResponseBody
        public ManyGizmoResponse getFacts() throws IOException {
            System.out.println("Gizmo search.");
            List<Gizmo> gizmos = new ArrayList<Gizmo>();
            gizmos.add(new Gizmo(1L, "HELLO"));
            gizmos.add(new Gizmo(2L, "WORLD"));
            return new ManyGizmoResponse(true,gizmos);
        }

        @RequestMapping(value="/gizmos", method= RequestMethod.POST, produces=APPLICATION_JSON_VALUE, consumes=APPLICATION_JSON_VALUE)
        @ResponseBody
        public SingleGizmoResponse createGizmo(@RequestBody Gizmo gizmo) throws IOException {
            System.out.println("Gizmo created.");
            return new SingleGizmoResponse(true,new Gizmo(1L,"NEW GIZMO"));
        }

        @RequestMapping(value="/gizmos/{gizmoId}", method= RequestMethod.PUT, produces=APPLICATION_JSON_VALUE, consumes=APPLICATION_JSON_VALUE)
        @ResponseBody
        public SingleGizmoResponse updateGizmo(@PathVariable Long gizmoId, @RequestBody Gizmo gizmo) throws IOException {
            System.out.println("Gizmo updated.");
            return new SingleGizmoResponse(true,new Gizmo(1L,"UPDATED GIZMO"));
        }

        @RequestMapping(value="/gizmos{gizmoId}", method= RequestMethod.DELETE, produces=APPLICATION_JSON_VALUE    )
        @ResponseBody
        public SingleGizmoResponse deleteGizmo(@PathVariable Long gizmoId) throws IOException {
            System.out.println("Gizmo deleted.");
            return new SingleGizmoResponse(true,new Gizmo(gizmoId,null));
        }
    }


For all of the methods, you’ll the ‘@RequestMapping’ annotation. This annotation is used by Spring for routing requests to individual controller methods. It also contains parameters that tell Spring what type data it can produce/consume and what HTTP verb the operation will be executed with. You’ll also see @RequestBody and @ResponseBody. Those tell Spring that the body of the request or response is to be unmarshalled and marshalled, respectively. By default (using the dispatcher-servlet config above), that format is JSON using the Jackson JSON utility. Let’s take a second to look at the value objects we’re mapping the aforementioned JSON to.

Here we have the Gizmo itself. You can see we’re using some annotations here to provide cues for the Jackson Utility. @JsonAutoDetect tells Jackson how to look at individual fields and which fields to look at. In our case, we’re telling Jackson to look only at those fields with a public accessor method.

package com.rodenbostel.springextjs.viewmodel;

import org.codehaus.jackson.annotate.JsonAutoDetect;
import org.codehaus.jackson.annotate.JsonProperty;

import java.io.Serializable;

@JsonAutoDetect(getterVisibility = JsonAutoDetect.Visibility.ANY, fieldVisibility = JsonAutoDetect.Visibility.NONE, setterVisibility = JsonAutoDetect.Visibility.ANY)
public class Gizmo implements Serializable {
    private Long id;
    private String description;

    public Gizmo(){}

    public Gizmo(Long id, String description) {
        this.id = id;
        this.description = description;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }
}

Depending on the type of response we’re sending we’re also providing a class to wrap a single Gizmo, and multiple Gizmos. You can see in the source there we’re using the same annotations to instruct Jackson where to find the fields it needs to use.

package com.rodenbostel.springextjs.viewmodel;

import org.codehaus.jackson.annotate.JsonAutoDetect;

import java.io.Serializable;

@JsonAutoDetect(getterVisibility = JsonAutoDetect.Visibility.ANY, fieldVisibility = JsonAutoDetect.Visibility.NONE, setterVisibility = JsonAutoDetect.Visibility.NONE)
public class SingleGizmoResponse implements Serializable {
    private boolean success;
    private Gizmo gizmo;

    public SingleGizmoResponse(boolean success, Gizmo gizmo) {
        this.success = success;
        this.gizmo = gizmo;
    }

    public boolean isSuccess() {
        return success;
    }

    public Gizmo getGizmo() {
        return gizmo;
    }
}


package com.rodenbostel.springextjs.viewmodel;

import org.codehaus.jackson.annotate.JsonAutoDetect;
import org.codehaus.jackson.annotate.JsonAutoDetect.Visibility;

import java.io.Serializable;
import java.util.List;

@JsonAutoDetect(getterVisibility = Visibility.ANY, fieldVisibility = Visibility.NONE, setterVisibility = Visibility.NONE)
public class ManyGizmoResponse implements Serializable {
    private boolean success;
    private List<Gizmo> gizmos;

    public ManyGizmoResponse(boolean success, List<Gizmo> gizmos) {
        this.success = success;
        this.gizmos = gizmos;
    }

    public boolean isSuccess() {
        return success;
    }

    public List<Gizmo> getGizmos() {
        return gizmos;
    }
}

Our read methods are mapped to ‘GET’ at /gizmos. You’ll notice though, that the getFact method also takes a Path Variable using the @PathVariable annotation. Spring allows you to name path variables in your request mapping ({gizmoId} in this case) and bind them to parameters passed to the underlying method (@PathVariable Long gizmoId). Providing the path variable in the request mapping allows Spring to differentiate the two read methods – “/gizmos/1” will return a single gizmo whose id is 1, and “/gizmos” will return all of the gizmos in the database. Our write methods are mapped in much the same way, but you can see the difference in the HTTP methods they work with.

Fire up the app in your favorite container and head to /spring/gizmos, and experiment with the different calls. You can use a nice little Chrome app called Postman to make different types of calls to exercise the whole interface ahead of our ExtJs development.

Good luck and get ready for Part 2 where we add an ExtJs UI on top of what we’ve just developed!

Advertisements

6 comments

    1. You can definitely configure the source as a Web Archive project in Eclipse and package and run it from within the IDE. The project was created using IntelliJ.

    1. There’s more info at: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html, section: 17.3.2 Mapping Requests With @RequestMapping.

      They’re called PathVariables. In my controller, you can see {gizmoId} in the value property of the RequestMapping annotation, and then you can also see it in that method’s input parameters, annotated with @PathVariable, using “gizmoId” as the name. Basically, this tells Spring, while routing your request, to take whatever is in the url at the same location as {gizmoId} and try to pass it into the method as the input parameter named “gizmoId”. Of course, for this binding to take place successfully, you have to ensure that the datatypes are compatible, or supply extra parsing information, as is shown in the spring docs.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s