Skip to content

Tutorial: SpringMVC

cepage edited this page Mar 6, 2013 · 9 revisions

Suppose you have an existing User domain object, that you would like to expose as a REST resource:

public class User
{
    private long _id;
    private String _name;
    private Set<Artist> _favoriteArtists;

    public long getId()
    {
        return _id;
    }

    public String getName()
    {
        return _name
    }

    public Set<Artist> getFavoriteArtists()
    {
        return _favoriteArtists;
    }
}

1. Maven

Import the relevant Yoga projects.

Add the following to your pom.xml, and define yoga.version to the current number:

<dependency>
    <groupId>org.skyscreamer</groupId>
    <artifactId>yoga-core</artifactId>
    <version>${yoga.version}</version>
</dependency>
<dependency>
    <groupId>org.skyscreamer</groupId>
    <artifactId>yoga-springmvc</artifactId>
    <version>${yoga.version}</version>
</dependency>

2. Controllers

Make sure your SpringMVC controller supports RESTful URLs. In this example, we are supporting GET requests to /user (to retrieve all users) and /user/{id} (to retrieve a single user by id number)

@Controller
@RequestMapping("/user")
public class UserController extends AbstractController<User>
{
    @RequestMapping
    public List<User> getUsers()
    {
        return _userService.findAllUsers();
    }

    @RequestMapping("/{id}")
    public User getUser( @PathVariable long id )
    {
        return _userService.findUser( id );
    }
}

Note: If you are using Spring's @ResponseBody annotation to render JSON from your controller method, you'll need to remove it. We're going to replace it with Yoga's mechanism for rendering your view!

3. Configuration

Next, register our supplied custom View with your Spring MVC configuration. This is easy if you are using annotation configuration for your SpringMVC controllers (Spring 3.0 required):

<bean name="viewResolver" class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver"
    p:order="1" p:ignoreAcceptHeader="true">
    <property name="mediaTypes">
        <map>
            <entry key="json"  value="application/json"/>
            <entry key="xml"   value="application/xml"/>
            <entry key="xhtml" value="text/html"/>
        </map>
    </property>
    <property name="defaultViews">
        <list>
            <bean class="org.skyscreamer.yoga.springmvc.view.YogaSpringView" p:yogaView-ref="jsonView"/>
            <bean class="org.skyscreamer.yoga.springmvc.view.YogaSpringView" p:yogaView-ref="xmlView"/>
            <bean class="org.skyscreamer.yoga.springmvc.view.YogaSpringView" p:yogaView-ref="xhtmlView"/>
        </list>
    </property>
</bean>

You can see that we have elected to support rendering your REST resources in JSON, XML, or XHTML response format. Of course, you can remove any formats that you don't wish to support from the viewResolver configuration.

You can see that we referenced three beans in the above configuration: jsonView, xmlView, and xhtmlView. We define those beans in our application context:

<bean name="jsonView" class="org.skyscreamer.yoga.view.JsonSelectorView"
      p:selectorParser-ref="selectorParser" />
<bean name="xmlView" class="org.skyscreamer.yoga.view.XmlSelectorView"
      p:selectorParser-ref="selectorParser" />
<bean name="xhtmlView" class="org.skyscreamer.yoga.view.XhtmlSelectorView"
      p:selectorParser-ref="selectorParser" />

<bean id="selectorParser" class="org.skyscreamer.yoga.selector.parser.GDataSelectorParser"/>

Last, we defined the selectorParser bean, which determines what syntax we will use for our selectors. We chose the GData syntax, based on Google's Data API specification.

4. Deploy and Run

Start your server. You can now issue a browser request to your controller, passing in selector as a request parameter to determine what fields of the User object will be rendered in the response:

/user.json?selector=id,name

Check out the other supported formats:

/user.xml?selector=id,name
/user.xhtml?selector=id,name

Notice that the User object has a property named favoriteArtists, which is a complex property type (set of Artist objects). If the Artist object has properties to render, you can name them in a nested selector. This request retrieves data for the user with ID#1, along with some information about his favorite artists:

/user/1.json?selector=id,name,favoriteArtists(name,currentRecordLabel)

5. Using @Core Annotation

As you can imagine, these selector strings can get very verbose for rich resources or complex object graphs. To simplify the selectors, you can designate certain properties of your REST resource as Core properties. Core properties will always be returned when the resource is rendered, and do not need to be named in the Selector.

One way to designate a property as a Core property is to use the @Core annotation that is supplied with the Yoga libraries. Here, we apply the annotation to two getter methods of the User class:

@Core
public long getId()
{
    return _id;
}

@Core
public String getName()
{
    return _name
}

Now, the following request will render the id and name properties of the User resource.

/user/1.json

And this request will render the id and name fields of the User resource as well as the name and currentRecordLabel fields of all of the user's favorite artists.

/user/1.json?selector=favoriteArtists(name,currentRecordLabel)

6. Using @URITemplate Annotation

When deploying a REST interface, you will want the resources that you return to be addressable through a clean URI. You can use the class annotation @URITemplate to tell Yoga how to construct the URI for an instance of your resource. Here's an example:

@URITemplate("/user/{id}")
public class User
{
    private long _id;
    ......

Here, the brackets around id tell Yoga to substitute the id field of the user instance in that part of the URI. So if the controller was returning the User object that had an id of 5, then the JSON response would include the following href field:

"href":"/user/5.json"

If you do not specify a URI template through the class annotation (or through a FieldPopulator for the resource), then no href link will be returned as part of the response.

7. Advanced Yoga

This is a great example for getting started quickly, and seeing what you can do with selectors in Yoga. We've been operating under the naive (but fun!) assumption that all of the data you would like to expose to REST requests is encapsulated in properties on your model objects, and that you want to expose all of your model data to anyone who asks.

To learn how to perform a more controlled deployment of Yoga, proceed to Configuring Resources with FieldPopulators