Spring3 and REST Integration(I)
1. REST support in Spring MVC
@Controller
@RequestMapping
@RequestMapping(method=RequestMethod.GET, value="/emps",
headers="Accept=application/xml, application/json")
@PathVariable
@RequestMapping(method=RequestMethod.GET, value="/emp/{id}")
public ModelAndView getEmployee(@PathVariable String id) { … }
@RequestParam
inject a URL parameter into the method
@RequestHeader
inject a certain HTTP header into the method
@RequestBody
inject an HTTP request body into the method
HttpEntity<T>
inject into the method automatically if you provide it as a parameter
ResponseEntity<T>
return the HTTP response with your custom status or headers
2.HttpMessageConverter
HTTP request and responses are text based, a browser and server communicate by exchanging raw texts.
This is handled by HttpMessageConverter.
StringHttpMessageConverter
FormHttpMessageConverter
MarshallingHttpMessageConverter
MappingJacksonHttpMessageConverter
read/write JSON data using Jackson's ObjectMapping. It converts data of media type application/json
AtomFeedHttpMessageConverter
read/write ATOM feed using ROME's Feed API. application/atom+xml
RssChannelHttpMessageConverter
read/write RSS feed using ROME's feed API. application/rss+xml
3. I decide to use groovy script as my Controller layer
I will use my open-source project easygroovyplugin to make spring groovy controller with with spring together.
First of All, web.xml file, nothing special there:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:main-context.xml</param-value>
</context-param>
<servlet>
<servlet-name>restproxy</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
</listener>
<servlet-mapping>
<servlet-name>restproxy</servlet-name>
<url-pattern>/service/*</url-pattern>
</servlet-mapping>
and my servlet configuration file /WebContent/WEB-INF/restproxy-servlet.xml:
<?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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
</beans>
Nothing there, just a empty file.
Add my controller layer spring configuration file to main-context.xml:
<import resource="classpath:controller-easyrestproxy-context.xml" />
And the controller layer spring configuration file is controller-easyrestproxy-context.xml:
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:lang="http://www.springframework.org/schema/lang"
xmlns:groovy="http://www.sillycat.com/schema/groovy"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/lang
http://www.springframework.org/schema/lang/spring-lang-3.0.xsd
http://www.sillycat.com/schema/groovy
http://www.sillycat.com/schema/groovy/groovy.xsd
">
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"/>
<bean id="handlerAdapter" class="com.sillycat.easygroovyplugin.servlet.proxy.ProxyAwareAnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="jsonConverter" />
</list>
</property>
</bean>
<lang:defaults refresh-check-delay="5" />
<!-- file://D:/work/easyrestproxy/groovy/*.groovy -->
<groovy:scan source-pattern="/groovy/*.groovy" />
<bean id="jsonConverter"
class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="supportedMediaTypes" value="application/json" />
</bean>
<!-- Client -->
<bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
<property name="messageConverters">
<list>
<ref bean="jsonConverter" />
</list>
</property>
</bean>
</beans>
And this is the properties file tell the project where to find the groovy file, easygroovy.properties:
###############################################
# groovy configuration
###############################################
groovy.file.path=file://e:/work/easyrestproxy
And my jars are all configured in ivy.xml:
<dependencies>
<!-- commons -->
<dependency org="commons-logging" name="commons-logging" rev="1.1.1"/>
<dependency org="commons-httpclient" name="commons-httpclient" rev="3.1"/>
<dependency org="commons-codec" name="commons-codec" rev="1.4" />
<dependency org="commons-dbcp" name="commons-dbcp" rev="1.2.2" />
<dependency org="commons-pool" name="commons-pool" rev="1.5" />
<dependency org="commons-configuration" name="commons-configuration" rev="1.5" />
<dependency org="commons-lang" name="commons-lang" rev="2.4"/>
<!-- spring jar -->
<dependency org="org/springframework" name="spring-web" rev="3.0.5.RELEASE"/>
<dependency org="org/springframework" name="spring-webmvc" rev="3.0.5.RELEASE"/>
<!-- mysql -->
<dependency org="com/mysql/jdbc" name="mysql" rev="5.1.10" />
<!-- jackson -->
<dependency org="org/codehaus/jackson" name="jackson-core-asl" rev="1.6.3" />
<dependency org="org/codehaus/jackson" name="jackson-mapper-asl" rev="1.6.3" />
<!-- groovy -->
<dependency org="com/sillycat" name="easygroovyplugin" rev="1.3" />
</dependencies>
Some jars are copy to JBOSS_HOME/server/default/lib directory, so they are not listed here.
Now, all the configration is ready. The groovy controller will work with spring well.
4. My groovy Controller will be as follow, it will have the CRUD sample :
package com.sillycat.easyrestproxy.controller;
import java.util.List;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.beans.factory.annotation.Autowired;
import com.sillycat.easyjpa.manager.PersonManager;
import com.sillycat.easyjpa.model.Person;
import com.sillycat.easyrestproxy.model.PersonList;
@Controller
public class PersonController {
@Autowired
PersonManager personManager;
@RequestMapping(method = RequestMethod.GET, value = "/person/{id}", headers = "Accept=application/json")
public @ResponseBody Person get(@PathVariable("id") String id) {
Person person = personManager.get(Integer.valueOf(id));
return person;
}
@RequestMapping(method = RequestMethod.GET, value = "/persons", headers = "Accept=application/json")
public @ResponseBody PersonList getAll() {
List<Person> list = personManager.getAll();
PersonList persons = null;
if(list != null && !list.isEmpty()){
persons = new PersonList(list);
}
return persons;
}
@RequestMapping(method=RequestMethod.POST, value="/person")
public @ResponseBody Person add(@RequestBody Person p) {
personManager.save(p);
return p;
}
@RequestMapping(method=RequestMethod.PUT, value="/person/{id}")
public @ResponseBody Person update(
@RequestBody Person p, @PathVariable("id") String id) {
personManager.save(p);
return p;
}
@RequestMapping(method=RequestMethod.DELETE, value="/person/{id}")
public @ResponseBody void remove(@PathVariable("id") String id) {
personManager.delete(Integer.parseInt(id));
}
}
PersonList is only a POJO to hold the List of Person PersonList.java:
package com.sillycat.easyrestproxy.model;
import java.util.List;
import com.sillycat.easyjpa.model.Person;
public class PersonList
{
private int amount;
private List<Person> persons;
public PersonList()
{
}
public PersonList(List<Person> persons)
{
this.persons = persons;
this.amount = persons.size();
}
public int getAmount()
{
return amount;
}
public void setAmount(int amount)
{
this.amount = amount;
}
public List<Person> getPersons()
{
return persons;
}
public void setPersons(List<Person> persons)
{
this.persons = persons;
}
}
references:
http://www.ibm.com/developerworks/web/library/wa-spring3webserv/index.html
http://www.ibm.com/developerworks/web/library/wa-restful/
1. REST support in Spring MVC
@Controller
@RequestMapping
@RequestMapping(method=RequestMethod.GET, value="/emps",
headers="Accept=application/xml, application/json")
@PathVariable
@RequestMapping(method=RequestMethod.GET, value="/emp/{id}")
public ModelAndView getEmployee(@PathVariable String id) { … }
@RequestParam
inject a URL parameter into the method
@RequestHeader
inject a certain HTTP header into the method
@RequestBody
inject an HTTP request body into the method
HttpEntity<T>
inject into the method automatically if you provide it as a parameter
ResponseEntity<T>
return the HTTP response with your custom status or headers
2.HttpMessageConverter
HTTP request and responses are text based, a browser and server communicate by exchanging raw texts.
This is handled by HttpMessageConverter.
StringHttpMessageConverter
FormHttpMessageConverter
MarshallingHttpMessageConverter
MappingJacksonHttpMessageConverter
read/write JSON data using Jackson's ObjectMapping. It converts data of media type application/json
AtomFeedHttpMessageConverter
read/write ATOM feed using ROME's Feed API. application/atom+xml
RssChannelHttpMessageConverter
read/write RSS feed using ROME's feed API. application/rss+xml
3. I decide to use groovy script as my Controller layer
I will use my open-source project easygroovyplugin to make spring groovy controller with with spring together.
First of All, web.xml file, nothing special there:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:main-context.xml</param-value>
</context-param>
<servlet>
<servlet-name>restproxy</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
</listener>
<servlet-mapping>
<servlet-name>restproxy</servlet-name>
<url-pattern>/service/*</url-pattern>
</servlet-mapping>
and my servlet configuration file /WebContent/WEB-INF/restproxy-servlet.xml:
<?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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
</beans>
Nothing there, just a empty file.
Add my controller layer spring configuration file to main-context.xml:
<import resource="classpath:controller-easyrestproxy-context.xml" />
And the controller layer spring configuration file is controller-easyrestproxy-context.xml:
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:lang="http://www.springframework.org/schema/lang"
xmlns:groovy="http://www.sillycat.com/schema/groovy"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/lang
http://www.springframework.org/schema/lang/spring-lang-3.0.xsd
http://www.sillycat.com/schema/groovy
http://www.sillycat.com/schema/groovy/groovy.xsd
">
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"/>
<bean id="handlerAdapter" class="com.sillycat.easygroovyplugin.servlet.proxy.ProxyAwareAnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="jsonConverter" />
</list>
</property>
</bean>
<lang:defaults refresh-check-delay="5" />
<!-- file://D:/work/easyrestproxy/groovy/*.groovy -->
<groovy:scan source-pattern="/groovy/*.groovy" />
<bean id="jsonConverter"
class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="supportedMediaTypes" value="application/json" />
</bean>
<!-- Client -->
<bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
<property name="messageConverters">
<list>
<ref bean="jsonConverter" />
</list>
</property>
</bean>
</beans>
And this is the properties file tell the project where to find the groovy file, easygroovy.properties:
###############################################
# groovy configuration
###############################################
groovy.file.path=file://e:/work/easyrestproxy
And my jars are all configured in ivy.xml:
<dependencies>
<!-- commons -->
<dependency org="commons-logging" name="commons-logging" rev="1.1.1"/>
<dependency org="commons-httpclient" name="commons-httpclient" rev="3.1"/>
<dependency org="commons-codec" name="commons-codec" rev="1.4" />
<dependency org="commons-dbcp" name="commons-dbcp" rev="1.2.2" />
<dependency org="commons-pool" name="commons-pool" rev="1.5" />
<dependency org="commons-configuration" name="commons-configuration" rev="1.5" />
<dependency org="commons-lang" name="commons-lang" rev="2.4"/>
<!-- spring jar -->
<dependency org="org/springframework" name="spring-web" rev="3.0.5.RELEASE"/>
<dependency org="org/springframework" name="spring-webmvc" rev="3.0.5.RELEASE"/>
<!-- mysql -->
<dependency org="com/mysql/jdbc" name="mysql" rev="5.1.10" />
<!-- jackson -->
<dependency org="org/codehaus/jackson" name="jackson-core-asl" rev="1.6.3" />
<dependency org="org/codehaus/jackson" name="jackson-mapper-asl" rev="1.6.3" />
<!-- groovy -->
<dependency org="com/sillycat" name="easygroovyplugin" rev="1.3" />
</dependencies>
Some jars are copy to JBOSS_HOME/server/default/lib directory, so they are not listed here.
Now, all the configration is ready. The groovy controller will work with spring well.
4. My groovy Controller will be as follow, it will have the CRUD sample :
package com.sillycat.easyrestproxy.controller;
import java.util.List;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.beans.factory.annotation.Autowired;
import com.sillycat.easyjpa.manager.PersonManager;
import com.sillycat.easyjpa.model.Person;
import com.sillycat.easyrestproxy.model.PersonList;
@Controller
public class PersonController {
@Autowired
PersonManager personManager;
@RequestMapping(method = RequestMethod.GET, value = "/person/{id}", headers = "Accept=application/json")
public @ResponseBody Person get(@PathVariable("id") String id) {
Person person = personManager.get(Integer.valueOf(id));
return person;
}
@RequestMapping(method = RequestMethod.GET, value = "/persons", headers = "Accept=application/json")
public @ResponseBody PersonList getAll() {
List<Person> list = personManager.getAll();
PersonList persons = null;
if(list != null && !list.isEmpty()){
persons = new PersonList(list);
}
return persons;
}
@RequestMapping(method=RequestMethod.POST, value="/person")
public @ResponseBody Person add(@RequestBody Person p) {
personManager.save(p);
return p;
}
@RequestMapping(method=RequestMethod.PUT, value="/person/{id}")
public @ResponseBody Person update(
@RequestBody Person p, @PathVariable("id") String id) {
personManager.save(p);
return p;
}
@RequestMapping(method=RequestMethod.DELETE, value="/person/{id}")
public @ResponseBody void remove(@PathVariable("id") String id) {
personManager.delete(Integer.parseInt(id));
}
}
PersonList is only a POJO to hold the List of Person PersonList.java:
package com.sillycat.easyrestproxy.model;
import java.util.List;
import com.sillycat.easyjpa.model.Person;
public class PersonList
{
private int amount;
private List<Person> persons;
public PersonList()
{
}
public PersonList(List<Person> persons)
{
this.persons = persons;
this.amount = persons.size();
}
public int getAmount()
{
return amount;
}
public void setAmount(int amount)
{
this.amount = amount;
}
public List<Person> getPersons()
{
return persons;
}
public void setPersons(List<Person> persons)
{
this.persons = persons;
}
}
references:
http://www.ibm.com/developerworks/web/library/wa-spring3webserv/index.html
http://www.ibm.com/developerworks/web/library/wa-restful/