Programming Guide - Web Services (RESTful) » History » Revision 3
Revision 2 (chin-yeh, 12/27/2011 12:00 PM) → Revision 3/4 (chin-yeh, 01/03/2012 10:24 AM)
{{toc}}
h1. Programming Guide - Web Services (RESTful)
This guide describes how to develop the _RESTful_ based web services.
In general, the web services should contains the following layers:
* *Web Services Layer* _(a.k.a controller)_ - this is the only place where the client will talk to
* *Services Layer* - contains the business logic on how to handle the client's request
* *DAO layer* - contains the logic on how to retrieve & persist data
!web_services_layers.png!
h2. Step-By-Step
> Assume that you have setup the [[General Info:Setup Development Environment|Eclipse environment]]
# launch *Eclipse*
# create a new *Dynamic Web Project*:
** _Dynamic web module version_ should set to _2.4_ or above
** _JDK_ compiler compliance version should set to _5.0_ or above
# and then *configure* the project:
## obtain the [[Programming Guide - Web Services (RESTful)#Project-Dependencies|project dependencies]] and then place it in the <code>WEB-INF/lib</code> folder
## replace the *web.xml* with this attachment:"web.xml"
## create the following folder:
*** <code>src/META-INF/spring</code>
## copy attachment:"applicationContext.xml" to <code>src/META-INF/spring</code> folder
*** edit the following line to put in the *root package* of the project
<pre>
<code class="XML">
<context:component-scan base-package="my.root.package"/>
</code>
</pre>
## copy attachment:"restful-servlet.xml" to <code>src/META-INF/spring</code> folder
*** edit the following line to put in the *package name* which contains all of the *controller* classes
<pre>
<code class="XML">
<context:component-scan base-package="my.package.controller"/>
</code>
</pre>
# after configured the project, let's start coding the following layers:
** *Web Services/Controller* - _see_ [[Programming_Guide_-_Web_Services_(RESTful)#Controller-Layer|Coding Guidelines]]
** *Services* - _see_ [[Programming_Guide_-_Web_Services_(RESTful)#Services-Layer|Coding Guidelines]]
** *DAO* - _optional but it's highly recommended to implement it_
# done
> download this sample project, attachment:sample_restful_project.zip to view all code snippets
h2. Project Dependencies
* com.springsource.org.aopalliance-1.0.0.jar
* jackson-core-asl-1.9.0.jar
* jackson-jaxrs-1.9.0.jar
* jackson-mapper-asl-1.9.0.jar
* jcl-over-slf4j-1.6.1.jar
* org.springframework.aop-3.0.5.RELEASE.jar
* org.springframework.asm-3.0.5.RELEASE.jar
* org.springframework.beans-3.0.5.RELEASE.jar
* org.springframework.context.support-3.0.5.RELEASE.jar
* org.springframework.context-3.0.5.RELEASE.jar
* org.springframework.core-3.0.5.RELEASE.jar
* org.springframework.expression-3.0.5.RELEASE.jar
* org.springframework.jdbc-3.0.5.RELEASE.jar
* org.springframework.transaction-3.0.5.RELEASE.jar
* org.springframework.web.servlet-3.0.5.RELEASE.jar
* org.springframework.web-3.0.5.RELEASE.jar
* slf4j-api-1.6.1.jar
* slf4j-log4j12-1.6.1.jar
* spring-security-config-3.0.5.RELEASE.jar
* spring-security-core-3.0.5.RELEASE.jar
* spring-security-web-3.0.5.RELEASE.jar
These dependencies can be found in:
* [[General Info:SearchBrowse_artifact|Nexus]]
* download attachment:web_inf_lib.zip and extract it to <code>WEB-INF/lib</code> folder
h1. Coding Guidelines
This guidelines will be revised anytime to accommodate requirement changes.
h2. Controller Layer
* the controller class must be *thread safe* as there's only *one instance* will be created to serve all web request
* every controller *must annotated* with <code>@Controller</code> at the class level
<pre>
<code class="JAVA">
@Controller
public class RegistrationController {
...
}
</code>
</pre>
* use the <code>@RequestMapping</code> to map the web request to the *handler class* or *handler method*, e.g.:
<pre>
<code class="JAVA">
@Controller
@RequestMapping(value = "/reg-services")
public class RegistrationController {
@RequestMapping(value = "/shopper", method = RequestMethod.POST)
@ResponseBody
public boolean registerMember(@RequestBody MemberRegistrationRequest request) {
return registrationServices.registerMember(request);
}
}
</code>
</pre>
** for this example, the following web request will be mapped to the *registerMember* method:
*** *request URL* - http://.../.../reg-services/shopper
*** *request method* - POST
* refer to this "link":http://en.wikipedia.org/wiki/Representational_state_transfer#RESTful_web_services for the guidelines about how to choose the appropriate *HTTP methods* and *request URI*
* every *method handler* should be annotated with <code>@ResposeBody</code> at the method level and return a value _(do not return <code>void</code>)_
<pre>
<code class="JAVA">
@ResponseBody
public boolean registerMember(@RequestBody MemberRegistrationRequest request) {
return registrationServices.registerMember(request);
}
</code>
</pre>
* if an argument is annotated with <code>@RequestBody</code>, the body of the web request will be automatically parsed.
<pre>
<code class="JAVA">
public boolean registerMember(@RequestBody MemberRegistrationRequest request) {
</code>
</pre>
* to bound the value of a *URI template variable*, just annotate, <code>@PathVariable</code> to the *target argument*
<pre>
<code class="JAVA">
@RequestMapping(value = "/shopper/{shopperRefNo}", method = RequestMethod.GET)
@ResponseBody
public MemberInfo retrieveMemberInfo(@PathVariable int refNo) {
...
</code>
</pre>
** for this example, the value of the URI template variable, *shopperRefNo* will be bound to the argument, *refNo*.
* use <code>@RequestParam</code> to access the specific *Servlet request paramater*. Parameter values will be converted to the declared argument type.
<pre>
<code class="JAVA">
public String setupForm(@RequestParam("petId") int petId)
</code>
</pre>
** *note:* By default, the parameter is required. To make the parameter as optional, set the *required* attribute to *false*, e.g.:
*** <code>@RequestParam(value="id", required=false)</code>
h2. Services Layer
* the service class is just a *POJO* (plain-old-java-object)
* the service class must be *thread safe* if, and only if it is one of the *field members* of the *controller*
* the service class should contains the *business logics only*. Try to delegate the un-relevant codes to other appropriate layers.