Project

General

Profile

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.