Spring MVC RESTFul Web Services

来源:互联网 发布:ubuntu安装哪个版本好 编辑:程序博客网 时间:2024/06/04 23:24

In this post we will write a CRUD Restful WebService using Spring MVC 4, and write a REST client with RestTemplate to consume those services. We will also test those services using external clients.


Short & Quick introduction to REST

REST stands for Representational State Transfer.It’s an is an architectural style which can be used to design web services, that can be consumed from a variety of clients. The core idea is that, rather than using complex mechanisms such as CORBA, RPC or SOAP to connect between machines, simple HTTP is used to make calls among them.

In Rest based design, resources are being manipulated using a common set of verbs.

  • To Create a resource : HTTP POST should be used
  • To Retrieve a resource : HTTP GET should be used
  • To Update a resource : HTTP PUT should be used
  • To Delete a resource : HTTP DELETE should be used

That means, you as a REST service developer or Client, should comply to above criteria, in order to be REST complained.

Often Rest based Web services return JSON or XML as response, although it is not limited to these types only. Clients can specify (using HTTPAccept header) the resource type they are interested in, and server may return the resource , specifyingContent-Type of the resource it is serving. ThisStackOverflow link is a must read to understand REST in detail.

Rest Based Controller

Following is one possible Rest based controller, implementing REST API. I said possible, means Other’s may implement it in another way, still (or even more pure way) conforming to REST style.

This is what our REST API does:

  • GET request to /api/user/ returns a list of users
  • GET request to /api/user/1 returns the user with ID 1
  • POST request to /api/user/ with a user object as JSON creates a new user
  • PUT request to /api/user/3 with a user object as JSON updates the user with ID 3
  • DELETE request to /api/user/4 deletes the user with ID 4
  • DELETE request to /api/user/ deletes all the users
package com.npf.controller; import java.util.List;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.http.HttpHeaders;import org.springframework.http.HttpStatus;import org.springframework.http.MediaType;import org.springframework.http.ResponseEntity;import org.springframework.web.bind.annotation.PathVariable;import org.springframework.web.bind.annotation.RequestBody;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.RestController;import org.springframework.web.util.UriComponentsBuilder;import com.npf.model.User;import com.npf.service.UserService; @RestControllerpublic class HelloWorldRestController {     @Autowired    private UserService userService;           //-------------------Retrieve All Users--------------------------------------------------------         @RequestMapping(value = "/user/", method = RequestMethod.GET)    public ResponseEntity<List<User>> listAllUsers() {        List<User> users = userService.findAllUsers();        if(users.isEmpty()){        //You many decide to return HttpStatus.NOT_FOUND            return new ResponseEntity<List<User>>(HttpStatus.NO_CONTENT);        }        return new ResponseEntity<List<User>>(users, HttpStatus.OK);    }    //-------------------Retrieve Single User--------------------------------------------------------         @RequestMapping(value = "/user/{id}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)    public ResponseEntity<User> getUser(@PathVariable("id") long id) {        System.out.println("Fetching User with id " + id);        User user = userService.findById(id);        if (user == null) {            System.out.println("User with id " + id + " not found");            return new ResponseEntity<User>(HttpStatus.NOT_FOUND);        }        return new ResponseEntity<User>(user, HttpStatus.OK);    }         //-------------------Create a User--------------------------------------------------------         @RequestMapping(value = "/user/", method = RequestMethod.POST)    public ResponseEntity<Void> createUser(@RequestBody User user,    UriComponentsBuilder ucBuilder) {        System.out.println("Creating User " + user.getName());        if (userService.isUserExist(user)) {            System.out.println("A User with name " + user.getName() + " already exist");            return new ResponseEntity<Void>(HttpStatus.CONFLICT);        }        userService.saveUser(user);        HttpHeaders headers = new HttpHeaders();        headers.setLocation(ucBuilder.path("/user/{id}").buildAndExpand(user.getId()).toUri());        return new ResponseEntity<Void>(headers, HttpStatus.CREATED);    }    //------------------- Update a User --------------------------------------------------------         @RequestMapping(value = "/user/{id}", method = RequestMethod.PUT)    public ResponseEntity<User> updateUser(@PathVariable("id") long id, @RequestBody User user) {        System.out.println("Updating User " + id);        User currentUser = userService.findById(id);        if (currentUser==null) {            System.out.println("User with id " + id + " not found");            return new ResponseEntity<User>(HttpStatus.NOT_FOUND);        }        currentUser.setName(user.getName());        currentUser.setAge(user.getAge());        currentUser.setSalary(user.getSalary());        userService.updateUser(currentUser);        return new ResponseEntity<User>(currentUser, HttpStatus.OK);    }     //------------------- Delete a User --------------------------------------------------------    @RequestMapping(value = "/user/{id}", method = RequestMethod.DELETE)    public ResponseEntity<User> deleteUser(@PathVariable("id") long id) {        System.out.println("Fetching & Deleting User with id " + id);         User user = userService.findById(id);        if (user == null) {            System.out.println("Unable to delete. User with id " + id + " not found");            return new ResponseEntity<User>(HttpStatus.NOT_FOUND);        }         userService.deleteUserById(id);        return new ResponseEntity<User>(HttpStatus.NO_CONTENT);    }          //------------------- Delete All Users --------------------------------------------------------    @RequestMapping(value = "/user/", method = RequestMethod.DELETE)    public ResponseEntity<User> deleteAllUsers() {        System.out.println("Deleting All Users");        userService.deleteAllUsers();        return new ResponseEntity<User>(HttpStatus.NO_CONTENT);    } }

Detailed Explanation :

@RestController : First of all, we are using Spring 4′s new @RestController annotation. This annotation eliminates the need of annotating each method with @ResponseBody. Under the hood, @RestController is itself annotated with @ResponseBody, and can be considered as combination of @Controller and @ResponseBody.

@RequestBody : If a method parameter is annotated with @RequestBody, Spring will bind the incoming HTTP request body(for the URL mentioned in @RequestMapping for that method) to that parameter. While doing that, Spring will [behind the scenes] use HTTP Message converters to convert the HTTP request body into domain object [deserialize request body to domain object], based on ACCEPT or Content-Type header present in request.

@ResponseBody : If a method is annotated with @ResponseBody, Spring will bind the return value to outgoing HTTP response body. While doing that, Spring will [behind the scenes] useHTTP Message converters to convert the return value to HTTP response body [serialize the object to response body], based on Content-Type present in request HTTP header. As already mentioned, in Spring 4, you may stop using this annotation.

ResponseEntity is a real deal. It represents the entire HTTP response. Good thing about it is that you can control anything that goes into it. You can specify status code, headers, and body. It comes with several constructors to carry the information you want to sent in HTTP Response.

@PathVariable This annotation indicates that a method parameter should be bound to a URI template variable [the one in '{}'].

Basically, @RestController , @RequestBody, ResponseEntity & @PathVariable are all you need to know to implement a REST API in Spring 4. Additionally, spring provides several support classes to help you implement something customized.

MediaType : With @RequestMapping annotation, you can additionally, specify the MediaType to be produced or consumed (usingproduces orconsumes attributes) by that particular controller method, to further narrow down the mapping.


Deploy and Test this API, let’s dig deeper into how this thing works

At the at end of day, it’s just a plain controller class, part of a deploy-able application.[Complete downloadable application code is shown further down in post which you can deploy straight-away in your container]. I am going to deploy it, in order to see things live and discuss each operation in detail. Deployed Application is available at http://localhost:8080/Spring4MVCCRUDRestService.

To test this API, i will use an external client POSTMAN (An extension from CHROME). We will write our own client in just few minutes.

Writing REST Client using RestTemplate

Postman tool we used above is a wonderful Client to test Rest API. But if you want to consume REST based web services from your application, you would need a REST client for your application. One of the most popular HTTP client is Apache HttpComponents HttpClient. But the details to access REST services using this are too low level.

Spring’s RestTemplate comes to Rescue. RestTemplate provides higher level methods that correspond to each of the six main HTTP methods that make invoking many RESTful services a one-liner and enforce REST best practices.

Below shown are HTTP methods and corresponding RestTemplate methods to handle that type of HTTP request.

HTTP Methods and corresponding RestTemplate methods:

  • HTTP GET : getForObject, getForEntity
  • HTTP PUT : put(String url, Object request, String…​urlVariables)
  • HTTP DELETE : delete
  • HTTP POST : postForLocation(String url, Object request, String…​ urlVariables), postForObject(String url, Object request, Class responseType, String…​ uriVariables)
  • HTTP HEAD : headForHeaders(String url, String…​ urlVariables)
  • HTTP OPTIONS : optionsForAllow(String url, String…​ urlVariables)
  • HTTP PATCH and others : exchange execute

Custom Rest client , consuming the REST services created earlier.

package com.npf.test;import java.net.URI;import java.util.LinkedHashMap;import java.util.List;import org.junit.Test;import org.springframework.web.client.RestTemplate;import com.npf.model.User; public class SpringRestTestClient {     public static final String REST_SERVICE_URI = "http://localhost:8080/springmvcRESTful";         /* GET */    @SuppressWarnings("unchecked")    @Test    public void listAllUsers(){        System.out.println("Testing listAllUsers API-----------");                 RestTemplate restTemplate = new RestTemplate();        List<LinkedHashMap<String, Object>> usersMap = restTemplate.getForObject(REST_SERVICE_URI+"/user/", List.class);                 if(usersMap!=null){            for(LinkedHashMap<String, Object> map : usersMap){                System.out.println("User : id="+map.get("id")+", Name="+map.get("name")+", Age="+map.get("age")+", Salary="+map.get("salary"));;            }        }else{            System.out.println("No user exist----------");        }    }         /* GET */    @Test    public void getUser(){        System.out.println("Testing getUser API----------");        RestTemplate restTemplate = new RestTemplate();        User user = restTemplate.getForObject(REST_SERVICE_URI+"/user/1", User.class);        System.out.println(user);    }         /* POST */    @Test    public void createUser() {        System.out.println("Testing create User API----------");        RestTemplate restTemplate = new RestTemplate();        User user = new User(0,"Sarah",51,134);        URI uri = restTemplate.postForLocation(REST_SERVICE_URI+"/user/", user, User.class);        System.out.println("Location : "+uri.toASCIIString());    }     /* PUT */    @Test    public void updateUser() {        System.out.println("Testing update User API----------");        RestTemplate restTemplate = new RestTemplate();        User user  = new User(1,"Tomy",33, 70000);        restTemplate.put(REST_SERVICE_URI+"/user/1", user);        System.out.println(user);    }     /* DELETE */    @Test    public void deleteUser() {        System.out.println("Testing delete User API----------");        RestTemplate restTemplate = new RestTemplate();        restTemplate.delete(REST_SERVICE_URI+"/user/3");    }      /* DELETE */    @Test    public void deleteAllUsers() {        System.out.println("Testing all delete Users API----------");        RestTemplate restTemplate = new RestTemplate();        restTemplate.delete(REST_SERVICE_URI+"/user/");    }}

code link : https://github.com/SpringMVCOrganization/springmvcRESTful

 ref link :  http://websystique.com/springmvc/spring-mvc-4-restful-web-services-crud-example-resttemplate/
0 0