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.