Spring Boot integrates RESTful API

Integrating a RESTful API in Spring Boot is a common development task in our actual development. The following is a small case to demonstrate how to create a RESTful API in Spring Boot to write a unit test.
Annotations used in this section:
@Controller: modified class, used to create objects that handle http requests

@RestController: annotation added after Spring 4. Originally in @Controller, returning json requires @ResponseBody to cooperate. If you use @ directly RestController replaces @Controller and there is no need to configure @ResponseBody. It returns json format by default.

@RequestMapping: Configure url mapping. Now more will be defined directly with mapping annotations directly related to Http Method, such as: GetMapping, PostMapping, DeleteMapping, PutMapping, etc.


First, we still need to import relevant dependencies. First create a Spring Boot project and add relevant dependencies to it. Add relevant dependencies under the pom.xml file.

<dependencies>
    <!-- Spring Boot Web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- Spring Boot Test -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

Then create an entity class User

public class User {<!-- -->

    private Long id;
    private String name;
    private Integer age;

    public Long getId() {<!-- -->
        return id;
    }

    public void setId(Long id) {<!-- -->
        this.id = id;
    }

    public String getName() {<!-- -->
        return name;
    }

    public void setName(String name) {<!-- -->
        this.name = name;
    }

    public Integer getAge() {<!-- -->
        return age;
    }

    public void setAge(Integer age) {<!-- -->
        this.age = age;
    }

    @Override
    public boolean equals(Object o) {<!-- -->
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        User user = (User) o;
        return Objects.equals(id, user.id) & amp; & amp; Objects.equals(name, user.name) & amp; & amp; Objects.equals(age, user.age);
    }

    @Override
    public int hashCode() {<!-- -->
        return Objects.hash(id, name, age);
    }

    public User() {<!-- -->
    }

    public User(Long id, String name, Integer age) {<!-- -->
        this.id = id;
        this.name = name;
        this.age = age;
    }
}

Write a Controller class, which is actually a RESTful API controller class, such as UserController

@RestController
@RequestMapping(value = "/users") // Through this configuration, the following mappings are all under /users
public class UserController {<!-- -->

    //Create a thread-safe Map to simulate the storage of users information
    static Map<Long, User> users = Collections.synchronizedMap(new HashMap<Long, User>());

    /**
     * Process the GET request of "/users/" to obtain the user list
     *
     * @return
     */
    @GetMapping("/")
    public List<User> getUserList() {<!-- -->
        // You can also pass parameters from the page through @RequestParam to pass query conditions or page turning information.
        List<User> r = new ArrayList<User>(users.values());
        return r;
    }

    /**
     * Process the POST request of "/users/" to create User
     *
     * @param user
     * @return
     */
    @PostMapping("/")
    public String postUser(@RequestBody User user) {<!-- -->
        // @RequestBody annotation is used to bind data uploaded through application/json type in http request
        users.put(user.getId(), user);
        return "success";
    }

    /**
     * Process the GET request of "/users/{id}" to obtain the User information of the id value in the URL
     *
     * @param id
     * @return
     */
    @GetMapping("/{id}")
    public User getUser(@PathVariable Long id) {<!-- -->
        //The id in the url can be bound to the parameters of the function through @PathVariable
        return users.get(id);
    }

    /**
     * Process the PUT request of "/users/{id}" to update User information
     *
     * @param id
     * @param user
     * @return
     */
    @PutMapping("/{id}")
    public String putUser(@PathVariable Long id, @RequestBody User user) {<!-- -->
        User u = users.get(id);
        u.setName(user.getName());
        u.setAge(user.getAge());
        users.put(id, u);
        return "success";
    }

    /**
     * Process the DELETE request of "/users/{id}" to delete the User
     *
     * @param id
     * @return
     */
    @DeleteMapping("/{id}")
    public String deleteUser(@PathVariable Long id) {<!-- -->
        users.remove(id);
        return "success";
    }
}

In the above example, we marked the class as a controller using the @RestController annotation and specified the base path to the API using the @RequestMapping annotation.

Next, we can write unit tests for this controller. Create a test class and write test methods using the test annotations provided by JUnit and Spring Boot:

@RunWith(SpringRunner.class)
@SpringBootTest
public class ApplicationTests {<!-- -->
 
    private MockMvc mvc;

    @Before
    public void setUp() {<!-- -->
        mvc = MockMvcBuilders.standaloneSetup(new UserController()).build();
    }

    @Test
    public void testUserController() throws Exception {<!-- -->
        //Test UserController
        RequestBuilder request;

        // 1. Get and check the user list, it should be empty
        request = get("/users/");
        mvc.perform(request)
                .andExpect(status().isOk())
                .andExpect(content().string(equalTo("[]")));

        // 2. Post and submit a user
        request = post("/users/")
                .contentType(MediaType.APPLICATION_JSON)
                .content("{"id":1,"name":"Test Master","age":20 }");
        mvc.perform(request)
                .andExpect(content().string(equalTo("success")));

        // 3. Get the user list, which should contain the data just inserted.
        request = get("/users/");
        mvc.perform(request)
                .andExpect(status().isOk())
                .andExpect(content().string(equalTo("[{"id":1,"name":"Test Master",\ "age":20}]")));

        // 4. put to modify the user with id 1
        request = put("/users/1")
                .contentType(MediaType.APPLICATION_JSON)
                .content("{"name":"Test Ultimate Master","age":30}");
        mvc.perform(request)
                .andExpect(content().string(equalTo("success")));

        // 5. Get a user with id 1
        request = get("/users/1");
        mvc.perform(request)
                .andExpect(content().string(equalTo("{"id":1,"name":"Test Ultimate Master",\ "age":30}")));

        // 6. del deletes the user with id 1
        request = delete("/users/1");
        mvc.perform(request)
                .andExpect(content().string(equalTo("success")));

        // 7. Use get to check the user list, it should be empty.
        request = get("/users/");
        mvc.perform(request)
                .andExpect(status().isOk())
                .andExpect(content().string(equalTo("[]")));

    }

}

We use the @RunWith(SpringRunner.class) annotation to specify the test runner. By introducing the web module (without any other configuration), we can easily use the functions of Spring MVC to complete the creation of the RESTful API of the User object and the writing of unit tests with very concise code. It also introduces several of the most commonly used core annotations in Spring MVC: @RestController, RequestMapping and some parameter binding annotations: @PathVariable ,@RequestBody, etc.