An overview of

In previous articles, we learned how to access data access layer components, such as using Spring Boot to access a database. Next we’ll look at another component, how to use Spring Boot to build a Web services layer.

Why do YOU need to build a Web services layer?

As those of you who have read the previous articles know, the current application built by Spring Boot can access the database, store and extract data. However, our application does not have the ability to provide services externally. In today’s distributed system and microservice architecture, RESTful style is a mainstream way of presenting Web services. Let’s focus on the understanding of RESTful

RESTful understand

You’re probably hearing a lot about RESTful apis, but what exactly does that mean, what qualifies as RESTful apis, can be a little confusing,

Representational State Transfer This is really abstract, and is essentially an architectural style rather than a specification that treats the server-side access point as a resource, Each Resource is given a unique address using a Universal Resource Identifier (URI), and standard HTTP methods are used over transport protocols, such as the most common GET, PUT, POST, and DELETE. Apis that satisfy this style are called RESTful apis. Here’s an example of how RESTful apis are defined:

URL HTTP request methods describe
http://www/example.com/v1/users GET Gets the list of User objects
http://www/example.com/v1/user/{id} GET Query the User object by id
http://www/example.com/v1/user POST Adding a User object
http://www/example.com/v1/user PUT Update the User object
http://www/example.com/v1/user/{id} DELETE Delete the User object by ID

On the other hand, the data interaction between client and server involves serialization and anti-serial number issues. There are many ways to serialize business objects in the network environment, the common ones are text and binary.

JSON is currently the most widely used serialization method, and we will use JSON as the default serialization method for all code examples in this course.

Having said our understanding of RESTful, let’s take a quick look at how to build RESTful Web services using Spring Boot.

Simple introduction

The repository address corresponding to the instance code:

Github.com/dragon8844/…

Gitee.com/drag0n/spri…

Introduction of depend on

Introduce dependencies into the pom.xml file:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <! Get, set-->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>

    <! Write unit tests later -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
        <exclusions>
            <exclusion>
                <groupId>org.junit.jupiter</groupId>
                <artifactId>junit-jupiter-api</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>
Copy the code

Add the configuration

Create the application configuration file application.yml in the Resources directory and add the following configuration information:

Port used to modify the Web service
server:
  port: 8080
Copy the code

The web service port is configured in the configuration file. If the port is not configured, port 8080 is used by default.

Write the code

Define User request VO

@Data
public class UserReqVO implements Serializable {

    private String username;
    private String password;

}
Copy the code

Define User to respond to VO

@Data
public class UserRespVO implements Serializable {

    private Integer id;
    private String username;
    private Date createTime;
}
Copy the code

Write controllers to expose apis

@RestController
@RequestMapping(value = "v1")
@Slf4j
public class UserController {

    @PostMapping(value = "/user", produces = MediaType.APPLICATION_JSON_VALUE)
    public R<Boolean> insert(@RequestBody UserReqVO userReqVO){
        log.info("Username :{}, password:{}", userReqVO.getUsername(), userReqVO.getPassword());
        // Call the Service layer to save user
        return R.ok(true);
    }

    @GetMapping(value = "/user/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
    public R<UserRespVO> selectById(@PathVariable Integer id){
        log.info("Accepted parameter ID :{}",id);
        // The simulation generates the UserRespVO object, which should be obtained by calling Service
        UserRespVO userRespVO = new UserRespVO();
        userRespVO.setCreateTime(new Date());
        userRespVO.setId(id);
        userRespVO.setUsername("Zhang");
        return R.ok(userRespVO);
    }

    @PutMapping(value = "/user/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
    public R<Boolean> updateById(@PathVariable Integer id, @RequestBody UserReqVO userReqVO){
        log.info("Username :{}, password:{}",userReqVO.getUsername(), userReqVO.getPassword());
        // Call the Service layer to update the user
        return R.ok(true);
    }

    @DeleteMapping(value = "/user/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
    public R<Boolean> deleteById(@PathVariable Integer id){
        log.info("Accepted parameter ID :{}",id);
        // Call the Service layer to delete the user
        return R.ok(true); }}Copy the code

In Controller, we defined four apis for User resource, respectively corresponding to adding User resource, querying User according to ID, updating User according to ID, and deleting User according to ID. We use a series of annotations @RestController, @RequestMapping, @PostMapping, @putMapping, @getMapping, @deletemapping, @RequestBody, @PathVariabl E and so on. The meaning of each note will be explained later.

At this point, a typical RESTful service has been developed, and we are now ready to run the Spring Boot application directly from the Java-jar command. So to verify that the API we wrote is usable, we’ll introduce Postman to demonstrate how remote service access can be done through the API exposed by the HTTP protocol. We query the User, for example, use the Postman to access “http://localhost:8080/v1/user/1” endpoint to get response results.

Unit testing

In addition to using Postman’s third-party tools for testing, we can also write unit tests for the Controller layer

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
@Slf4j
public class UserControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @Test
    public void insert(a) throws Exception {

        UserReqVO userReqVO = new UserReqVO();
        userReqVO.setPassword("123456");
        userReqVO.setUsername("Zhang");
        / / set the value
        ObjectMapper mapper = new ObjectMapper();
        ObjectWriter ow = mapper.writer().withDefaultPrettyPrinter();
        String requestJson = ow.writeValueAsString(userReqVO);

        MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.post("/v1/user")
                .contentType(MediaType.APPLICATION_JSON)
                .content(requestJson))
                .andExpect(MockMvcResultMatchers.status().isOk())
                .andDo(MockMvcResultHandlers.print())
                .andReturn();
        log.info("mvcResult:{}", mvcResult.getResponse().getContentAsString(Charset.forName("UTF-8")));
    }

    @Test
    public void selectById(a) throws Exception {
        MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.get("/v1/user/1"))
                    .andExpect(MockMvcResultMatchers.status().isOk())
                    .andDo(MockMvcResultHandlers.print())
                    .andReturn();
        log.info("mvcResult:{}", mvcResult.getResponse().getContentAsString(Charset.forName("UTF-8")));
    }

    @Test
    public void updateById(a) throws Exception{
        UserReqVO userReqVO = new UserReqVO();
        userReqVO.setPassword("123456");
        userReqVO.setUsername("Zhang");
        / / set the value
        ObjectMapper mapper = new ObjectMapper();
        ObjectWriter ow = mapper.writer().withDefaultPrettyPrinter();
        String requestJson = ow.writeValueAsString(userReqVO);

        MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.put("/v1/user/1")
                .contentType(MediaType.APPLICATION_JSON)
                .content(requestJson))
                .andExpect(MockMvcResultMatchers.status().isOk())
                .andDo(MockMvcResultHandlers.print())
                .andReturn();
        log.info("mvcResult:{}", mvcResult.getResponse().getContentAsString(Charset.forName("UTF-8")));

    }

    @Test
    public void deleteById(a)throws Exception{
        MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.delete("/v1/user/1"))
                .andExpect(MockMvcResultMatchers.status().isOk())
                .andDo(MockMvcResultHandlers.print())
                .andReturn();
        log.info("mvcResult:{}", mvcResult.getResponse().getContentAsString(Charset.forName("UTF-8"))); }}Copy the code

Annotation summary

In quick Start, we used a number of annotations when we used Spring Boot to expose our Web services, and I’ll cover each one in more detail.

Base notes

Building on the existing Spring Boot application, we can expose RESTful apis by building a series of Controller classes. The Controller here is conceptually the same as the Controller in Spring MVC. The simplest Controller class looks like this:

@RestController
public class HelloController {
 
    @GetMapping("/")
    public String index(a) {
        return "Hello World!"; }}Copy the code

The code above uses the @RestController and @getMapper annotations.

The @RestController annotation, inherited from the @Controller annotation in Spring MVC, is, as its name implies, a RESTful HTTP endpoint and automatically serializes/deserializes HTTP requests and responses using JSON.

With this feature, we can use the @RestController annotation instead of the @Controller annotation to simplify development when building RESTful services. You don’t have to have an @responseBody annotation on the method.

Another @getMapping annotation is similar to the @requestMapping annotation in Spring MVC. Let’s take a look at the definition of the @RequestMapping annotation. The attributes provided by the annotation are easier to understand, as shown in the code below:

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {
    String name(a) default "";

    @AliasFor("path")
    String[] value() default {};

    @AliasFor("value")
    String[] path() default {};

    RequestMethod[] method() default {};

    String[] params() default {};

    String[] headers() default {};

    String[] consumes() default {};

    String[] produces() default {};
}
Copy the code

The @getMapping annotation is defined very similarly to @requestMapping, except that by default requestMethod. GET specifies the HTTP method, as shown below:

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@RequestMapping( method = {RequestMethod.GET} )
public @interface GetMapping {}
Copy the code

In addition to @getMapping annotations, Spring Boot 2.X also provides @postMapping, @putMapping, @deletemapping, and @PatchMapping annotations, which specify Http request modes explicitly. Convenient development of the use of developers. Of course you can use the @requestMapping annotation to achieve the same effect.

Annotations that control requests and responses

Spring Boot provides a series of simple and useful annotations to simplify the process of controlling request input. Common ones include @PathVariable, @requestParam, @RequestBody, and @ModelAttribute annotations.

The @pathVariable annotation is used to get the path parameter, that is, the value of the {id} parameter from a path of the form url/{id}.

This annotation is defined as follows:

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PathVariable {
    @AliasFor("name")
    String value(a) default "";

    @AliasFor("value")
    String name(a) default "";

    boolean required(a) default true;
}

Copy the code

When using the @pathvariable annotation, we only need to specify the name of a parameter and bind the value of the parameter in the URL, as shown in the following example:

@GetMapping(value = "/user/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
    public R<UserRespVO> selectById(@PathVariable Integer id){
Copy the code

{id} is bound to the id parameter on the method.

The @requestParam annotation is similar to the @PathVariable annotation in that it is used to retrieve the parameters in the request, but it is used for things like urls. The path id=XXX.

This annotation is defined as shown in the code below, and instead of the @pathvariable annotation, it simply has a defaultValue attribute that sets the defaultValue.

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestParam {
    @AliasFor("name")
    String value(a) default "";
    @AliasFor("value")
    String name(a) default "";
    boolean required(a) default true;
    String defaultValue(a) default ValueConstants.DEFAULT_NONE;
}
Copy the code

The @requestbody annotation is used to handle encoded content when the content-type is application/json. The @requestbody annotation binds the json string in the RequestBody to the corresponding javabeans.

The code shown below is a scenario that uses the @RequestBody annotation to control input.

@PostMapping(value = "/user", produces = MediaType.APPLICATION_JSON_VALUE)
    public R<Boolean> insert(@RequestBody UserReqVO userReqVO){
Copy the code

summary

So much for how to build RESTful Web services with Spring Boot. We’ll start with an understanding of RESUful and then give you a simple primer on how to build a standard RESTful API with Spring Boot. And in the introductory tutorial, we experienced the powerful annotations provided by Spring Boot that make it easy to implement this feature. Later, we summarized the annotations provided by Spring Boot, and introduced the specific functions and usage of each annotation in detail.

One last word

If this article is helpful to you, or inspired, help pay attention to it, your support is the biggest motivation I insist on writing, thank you for your support.

In addition, pay attention to the public number: black lighthouse, focus on Java back-end technology sharing, covering Spring, Spring the Boot, SpringCloud, Docker, Kubernetes middleware technology, etc.