Tutorial Series-springboot-restful Application

Source: Internet
Author: User
Tags representational state transfer

First, the goal
    1. Understand what Restful is, the basic concept and style;
    2. can use Springboot to achieve a set of basic Restful style interface;
    3. Use swagger to generate clear interface documentation.
Ii. the basics of Restful

What is rest
From the definition of Wikipedia: Rest is representational state transfer (English: representational, Transfer, rest)
is a software architecture style proposed by Dr. Roy Fielding (the main contributor to the HTTP specification) in a 2000 paper.
is a design and development method for network application, which can reduce the complexity of development and increase the scalability of the system.

In layman's terms, rest is a set of architectural constraints, and many of these guidelines take advantage of existing web standards capabilities.
The ultimate goal is to simplify the design and development of the current business layer.

The RESTful API is an API that conforms to the rest schema constraints, which have been very popular in the early years, but most developers still
Being in a wait-and-see state does not necessarily apply immediately. This belief is closely related to the maturity and atmosphere of the technical community at that time.
In any case, as the microservices architecture is so popular today, Restful APIs have become a must-have standard design style .

Key points
Understanding Restful styles requires understanding the following points:

    • Resources

Resource refers to an abstract information entity, which can be a user, a song, an article, as long as the object that can be referenced is a resource.
Each resource is typically mapped to a URI that can be accessed by accessing the URI.

    • Presentation of resources

Resource representation (representation) refers to the external representation of resources
such as a post, can be displayed in HTML format, or through XML, JSON and other formats to the client.

As mentioned in the previous article (Springboot-scope), the HTTP protocol uses MIME to uniformly define the format criteria for data information.
Generally,accept,content-type can be used to specify the client and the server acceptable information format, and this is the expression of resources

    • State transitions

During HTTP access, the state of the resource changes. Here are some of the following verbs:

name Semantics
GET Get Resources
POST New Resource
PUT Update Resources
DELETE Delete a resource

For different access methods, the server generates the corresponding behavior and causes the resource state to be transformed.

About stateless
Restful is a stateless design, which means that requests in the interactive process should contain all the information needed,
Without having to rely on an existing context.
However, there are some breaches in Java EE, such as setting jsessionid in cookies,
Passing this value between multiple requests is a unique identifier for the session, which identifies the server that must hold the session state data.

The Playframework framework implements a stateless session that encrypts and encodes session data into a cookie.
In this way, the client's request will carry all the information directly, is a
stateless request * *, which is very beneficial to the scalability of the server.

Iii. springboot Realization of Restful

Next, we use Springboot to implement a restful style sample.

Description
Based on the case of Petstore (Pet Shop), the Pet (PET) under the name of a customer is modified and deleted.

1. Entity definition

Customer

public class Customer {    private String name;    public Customer() {        super();    }    public Customer(String name) {        super();        this.name = name;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }}

The Customer contains only one name attribute, which we assume is the only flag.

Pet

public class Pet {    private String petId;    private String name;    private String type;    private String description;    public String getPetId() {        return petId;    }    public void setPetId(String petId) {        this.petId = petId;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public String getType() {        return type;    }    public void setType(String type) {        this.type = type;    }    public String getDescription() {        return description;    }    public void setDescription(String description) {        this.description = description;    }}

Pet contains the following properties

Property name Description
Petid Pet ID Number
Name Pet Name
Type Pet Type
Description Description of the Pet
2. URL Resources

Based on the principle of restful, we define the following set of URLs:

Interface Method URL
Add a Pet POST /rest/pets/{customer}
Get a list of pets GET /rest/pets/{customer}
Get pet information GET /rest/pets/{customer}/{petid}
Update your pet information PUT /rest/pets/{customer}/{petid}
Delete a pet DELETE /rest/pets/{customer}/{petid}
3. Data management

A Petmanager class is then implemented to simulate the pruning of pet data in memory
The code is as follows:

@Componentpublic class Petmanager {private static map<string, customer> customers = new Concurrenthashmap<str    ING, customer> (); private static map<string, map<string, pet>> pets = new concurrenthashmap<string, map<string, Pet>&    gt; ();         @PostConstruct public void init () {string[] customernames = new string[] {"Lilei", "Hanmeimei", "Jim Green"};        for (String customername:customernames) {customers.put (CustomerName, New Customer (CustomerName)); }}/** * Get customer * * @param customer * @return */public customer GetCustomer (stri        Ng customer) {if (Stringutils.isempty (customer)) {return null;    } return Customers.get (customer); }/** * Get the pet list in customer name * * @param customer * @return */public list<pet> getpets (St Ring customer) {if (Stringutils.isempty (customer)) {return collections.emptylist ();        } if (!pets.containskey (customer)) {return collections.emptylist ();    Return Pets.get (Customer). values (). Stream (). Collect (Collectors.tolist ()); }/** * Get a pet * * @param customer * @param petid * @return */public Pet Getpet (String cu Stomer, String Petid) {if (Stringutils.isempty (customer) | |        Stringutils.isempty (Petid)) {return null;        } if (!pets.containskey (customer)) {return null;    } return Pets.get (Customer). get (Petid); }/** * Delete Pet * * @param customer * @param petid * @return */public boolean removepet (stri Ng customer, String petid) {if (Stringutils.isempty (customer) | |        Stringutils.isempty (Petid)) {return false;        } if (!pets.containskey (customer)) {return false;    } return Pets.get (Customer). Remove (petid)! = NULL; }/** * Add pet * * @param cUstomer * @param pet * @return */Public pet Addpet (String customer, pet Pet) {if (Stringutils.isem Pty (Customer) | |        Pet = = null) {return null;        } map<string, pet> customerpets = null;            if (!pets.containskey (customer)) {customerpets = new linkedhashmap<string, pet> ();            Map<string, pet> previous = Pets.putifabsent (customer, customerpets);            already exists if (previous! = null) {customerpets = previous;        }} else {customerpets = Pets.get (customer);        } if (Pet.getpetid () = = null) {Pet.setpetid (Uuid.randomuuid (). toString ());        } customerpets.put (Pet.getpetid (), pet);    return pet; }/** * Update a pet * * @param customer * @param petpojo * @return */public Pet Updatepet (stri        Ng customer, Pet Petpojo) {if (Stringutils.isempty (customer) | | | petpojo = = NULL) {    return null;        } if (Petpojo.getpetid () = = null) {return null;        } Pet pet = Getpet (Customer, Petpojo.getpetid ());        Pet.settype (Petpojo.gettype ());        Pet.setname (Petpojo.getname ());        Pet.setdescription (Petpojo.getdescription ());    return pet; }}
4. Control Layer Implementation

Springboot provides @RestControllerfor quickly defining a restful-style controller class
@[email protected] + @Controller

@RestController @requestmapping ("/rest/pets/{customer}") public class Restapicontroller {@Autowired private petmanage    R DataManager; /** * Add Pet * * @param customer * @param pet * @return */@PostMapping public responseentity        <Object> Addpet (@PathVariable String customer, @RequestBody Pet Pet) {Validatecustomer (customer);        Pet Newpet = Datamanager.addpet (customer, PET); Returns the 201.created if (newpet! = null) {URI location = Servleturicomponentsbuilder.fromcurrentrequest ().            Path ("/{petid}"). Buildandexpand (Newpet.getpetid ()). Touri ();        return responseentity.created (location). build ();    }//returns 204.noContent return Responseentity.nocontent (). build (); /** * Get Pet List * * @param customer * @return */@GetMapping @ResponseBody public list<       Pet> listpets (@PathVariable String customer) {Validatecustomer (customer); List<pet> pets = Datamanager.getpets (customer);    return pets;    /** * Get a pet * * @param customer * @param petid */@GetMapping ("/{petid}") @ResponseBody        Public Pet Getpet (@PathVariable string customer, @PathVariable string petid) {Validatecustomer (customer);        Validatepet (Customer, Petid);        Pet Pet = Datamanager.getpet (Customer, Petid);    return pet;    */** * UPDATE pet information * * @param customer * @param petid * @param pet */@PutMapping ("/{petid}") Public responseentity<object> Updatepet (@PathVariable string customer, @PathVariable string Petid, @RequestBody P        ET pet) {validatecustomer (customer);        Validatepet (Customer, Petid);        Pet.setpetid (Petid);        Pet Petobject = Datamanager.updatepet (customer, PET);        if (petobject! = null) {return Responseentity.ok (petobject);    } return Responseentity.nocontent (). build (); }    /**     *Delete a pet * * @param customer * @param petid * @return */@DeleteMapping ("/{petid}") Public respon Seentity<object> Removepet (@PathVariable string customer, @PathVariable string petid) {Validatecustomer (cust        Omer);        Validatepet (Customer, Petid);        Datamanager.removepet (Customer, Petid);    Return Responseentity.ok (). build (); }

The above code has realized the complete deletion and modification of the semantics.
In restful-style API interface definitions, HTTP status codes are often used to denote different results, such as some wrong state types.
Here we customer, Pet for the existence of check, if the resource does not exist return 404_notfound.

    /**     * 校验customer是否存在     *      * @param customer     */    private void validateCustomer(String customer) {        if (dataManager.getCustomer(customer) == null) {            throw new ObjectNotFoundException(String.format("the customer['%s'] is not found", customer));        }    }    /**     * 校验pet是否存在     *      * @param customer     */    private void validatePet(String customer, String petId) {        if (dataManager.getPet(customer, petId) == null) {            throw new ObjectNotFoundException(String.format("the pet['%s/%s'] is not found", customer, petId));        }    }

Custom Exception Blocking

    /**     * 自定义异常,及拦截逻辑     *      * @author atp     *     */    @SuppressWarnings("serial")    public static class ObjectNotFoundException extends RuntimeException {        public ObjectNotFoundException(String msg) {            super(msg);        }    }    @ResponseBody    @ExceptionHandler(ObjectNotFoundException.class)    @ResponseStatus(HttpStatus.NOT_FOUND)    public String objectNotFoundExceptionHandler(ObjectNotFoundException ex) {        return ex.getMessage();    }
5. Interface Verification 1. Add a Pet

Url
POST Http://{{server}}/rest/pets/lilei
Request Content

{ "name": "Smart Baby", "description": "very small and smart also.", "type": "Dog"}

return example

201 createdContent-Length →0Date →Mon, 09 Jul 2018 05:15:01 GMTLocation →http://localhost:8090/rest/pets/LiLei/b5400334-e7b3-42f1-b192-f5e7c3193543
2. Get a list of pets

Url
GET Http://{{server}}/rest/pets/lilei
Request Content

<Empty>

return example

200 OKContent-Type →application/json;charset=UTF-8Date →Mon, 09 Jul 2018 05:23:27 GMTTransfer-Encoding →chunked[    {        "petId": "b5400334-e7b3-42f1-b192-f5e7c3193543",        "name": "Smart Baby",        "type": "Dog",        "description": "very small and smart also."    },    {        "petId": "610780af-94f1-4011-a175-7a0f3895163d",        "name": "Big Cat",        "type": "Cat",        "description": "very old but I like it."    }]
3. Check your pet information

Url
GET http://{{server}}/rest/pets/lilei/b5400334-e7b3-42f1-b192-f5e7c3193543
Request Content

<Empty>

return example

200 OKContent-Type →application/json;charset=UTF-8Date →Mon, 09 Jul 2018 05:25:24 GMTTransfer-Encoding →chunked{    "petId": "b5400334-e7b3-42f1-b192-f5e7c3193543",    "name": "Smart Baby",    "type": "Dog",    "description": "very small and smart also."}
4. Update your pet information

Url
PUT http://{{server}}/rest/pets/lilei/b5400334-e7b3-42f1-b192-f5e7c3193543
Request Content

{ "name": "Big Cat V2", "description": "I don't like it any more", "type": "Cat"}

return example

200 OKContent-Type →application/json;charset=UTF-8Date →Mon, 09 Jul 2018 05:31:28 GMTTransfer-Encoding →chunked{    "petId": "a98e4478-e754-4969-851b-bcaccd67263e",    "name": "Big Cat V2",    "type": "Cat",    "description": "I don't like it any more"}
5. Delete a pet

Url
DELETE http://{{server}}/rest/pets/lilei/b5400334-e7b3-42f1-b192-f5e7c3193543
Request Content

<empty>

return example

200 OKContent-Length →0Date →Mon, 09 Jul 2018 05:32:51 GMT

Related error

    • Customer does not exist: 404 the customer[' test ' is not found
    • Pet not present: 404 the Pet[' lilei/b5400334-e7b3-42f1-b192-f5e7c31935431 ' is not found
Iv. Use of Swagger

About Swagger

Swagger is currently a very popular API Design development framework (based on OPENAPI),
Available for API design, management, code generation, mock testing, and more.

At present, the application of swagger is very wide, it covers more open source modules, which will use Swagger-ui to implement API online doc generation.

Introducing Dependencies

        <dependency>            <groupId>io.springfox</groupId>            <artifactId>springfox-swagger2</artifactId>            <version>2.7.0</version>        </dependency>        <dependency>            <groupId>io.springfox</groupId>            <artifactId>springfox-swagger-ui</artifactId>            <version>2.7.0</version>        </dependency>

Defining the API Configuration

  @EnableSwagger2 @configurationpublic class Swaggerconfig {public static final String VERSION = "1.0.0";    @Value ("${swagger.enable}") Private Boolean enabled;                Apiinfo Apiinfo () {return new Apiinfobuilder ().                 Title ("Pet Api Definition"). Description ("The Petstore CRUD Example"). License ("Apache 2.0")                . Licenseurl ("http://www.apache.org/licenses/LICENSE-2.0.html"). Termsofserviceurl ("") . version. Contact (new Contact ("," "," [email protected] "). Build ()    ;                } @Bean Public Docket Customimplementation () {return new docket (documentationtype.swagger_2). Select () . APIs (Requesthandlerselectors.withclassannotation (Api.class)). Build (). Enable (Enab    LED). Apiinfo (Apiinfo ()); }}

The @EnableSwagger2 declares the swagger enabled, and the docket bean definition is the gateway to the API configuration.
You can set the API name, version number, scan range, and so on.

Declaring API Descriptions

Add a declaration on the API to the original controller method, as follows:

@Api(value = "Pet Restful api")@RestController@RequestMapping("/rest/pets/{customer}")public class RestApiController {    @ApiOperation("添加宠物")    @ApiImplicitParams({            @ApiImplicitParam(paramType = "path", name = "customer", dataType = "String", required = true, value = "客户名", defaultValue = ""),            @ApiImplicitParam(paramType = "body", name = "pet", dataType = "Pet", required = true, value = "pet 请求", defaultValue = "") })    @ApiResponses({        @ApiResponse(code = 201, message = "添加成功"),        @ApiResponse(code = 404, message = "资源不存在")    })    @PostMapping    public ResponseEntity<Object> addPet(@PathVariable String customer, @RequestBody Pet pet) {        ...

To be able to describe the document description of the returned object, make an API declaration for the Pet class:

@ApiModel("宠物信息")public class Pet {    @ApiModelProperty(name="petId", value="宠物ID")    private String petId;        @ApiModelProperty(name="name", value="宠物名称")    private String name;        @ApiModelProperty(name="type", value="宠物类型")    private String type;        @ApiModelProperty(name="description", value="宠物描述")    private String description;

Related annotations:

Annotations Description
@ApiModelProperty Used on fields in the Access parameter object
@Api For controller classes
@ApiOperation For the Controller method, describes the operation
@ApiResponses For the Controller method that describes the response
@ApiResponse Used in @apiresponses to describe a single response result
@ApiImplicitParams The method used for the controller, which describes the entry parameter
@ApiImplicitParam Used in @apiimplicitparams to describe a single entry parameter
@ApiModel Used to return an object class

accessing documents

Finally, to access http://localhost:8000/swagger_ui.html, you can see the resulting document interface:

Reference documents

Springboot-tutorials-bookmarks
Nanyi-Understanding the RESTful architecture
Sprintboot-using the Swagger Publishing API
Swagger-2-documentation-for-spring-rest-api

Welcome to continue to pay attention to "American Code Master's Tutorial series-springboot", look forward to more exciting content ^-^

Tutorial Series-springboot-restful Application

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.