In one of my project, I had the difficult decision to switch to another technology: I replaced JSF with Angular-JS.
Our goal was to speed up the development by removing the painful part implied with JSF, as a lot of server requests to manage, some view state issues, the refresh management, the need to implement the view on the Java part with its managed beans, etc…
But the big impact on the architectural point of view was that we have to move the GUI (and its logic) on the client side and give access to the data. Fortunately, this part was ease by the layered structure of the application, I just need to replace the old JSF part with a REST interface which is accessed by the Angular-JS components using Ajax requests.
As the project used already Spring, I decided to use it also to set up the restful part, I describe hereafter what I did.
First of all, we need to add the corresponding dependencies in our POM:
<properties> <spring.framework.version>4.0.5.RELEASE</spring.framework.version> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring.framework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.framework.version}</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.3.4</version> </dependency> <dependency> <groupId>org.codehaus.jackson</groupId> <artifactId>jackson-mapper-asl</artifactId> <version>1.9.12</version> </dependency> </dependencies>
We need also to activate the configuration using annotation, for that we have to add in our Spring configuration file:
<context:component-scan base-package="net.classnotfound.ws"/> <mvc:annotation-driven />
Even if I do not like to use the annotations to configure the application, I decided to make an exception for the web services, as they are not intended to have some intelligence and are just a bridge to the business layer, I consider it as acceptable.
A web service is declared using the @RestController Spring annotation:
package net.classnotfound.ws.controller; import org.springframework.web.bind.annotation.RestController; @RestController public class MyController { //Web service implementation here }
When we define an endpoint for the web service, we need to indicates which HTTP method we use, the type of data we expect (JSON is the usual case), etc…
This can be done easily by using the Spring annotation:
@RequestMapping(value = "/service/print", method = RequestMethod.POST, consumes = {"application/json" }) @ResponseStatus(HttpStatus.NO_CONTENT) public void print(@RequestBody final Data data) { System.out.println(data); }
Here, we defined a method print, which is reachable using “/service/print” URL, using a POST request with data in JSON format.
The @ResponseStatus is used to define the HTTP return code to be used.
Another option is to use a GET method, but doing this, the parameters are now directly provided with the requested URL:
@Autowired private DataService dataService; @Transactional @Globals @RequestMapping(value = "/service/data/{id}", method = RequestMethod.GET) @ResponseBody public Data find(@PathVariable("id") final String id) { Data data = dataService.find(id); if (data==null) { throw new ObjectNotFoundException(id); } return data; }
We can see the parameter defined in the URL using a EL syntax and this parameter is also mentioned in the signature of the method using @PathVariable annotation.
Too easy, isn’t it? 😀