-
Notifications
You must be signed in to change notification settings - Fork 66
Tutorial: SpringMVC
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;
}
}
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>
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!
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.
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)
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)
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.
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