SpringBoot中使用Restful API

現在前後端分離這麼流行,後端採用Restful API來設計也是大勢所趨吧。下面介紹一下在Spring boot中使用RestFul API的基本方式吧。

PS:不去說什麼是Restful服務,只是說說它在代碼中的實際使用。

首先,定義兩個model:

其一:User實體類

package com.baiding.security.model;

import com.fasterxml.jackson.annotation.JsonView;

import java.util.Date;

/**
 * @Author: BaiDing
 * @Date: 2018/10/10 21:08
 * @Email: [email protected]
 */
public class User {

    public interface UserSimpleView {};
    public interface UserDetailView extends UserSimpleView {};

    private long id;
    private String userName;
    private String password;
    private Date birthday;

    // JsonView根據視圖控制字段的輸出
    @JsonView(UserSimpleView.class)
    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    @JsonView(UserDetailView.class)
    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @JsonView(UserSimpleView.class)
    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    @JsonView(UserSimpleView.class)
    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }
}

其二:UserQueryCondition實體類

package com.baiding.security.model;

/**
 * @Author: BaiDing
 * @Date: 2018/10/10 21:10
 * @Email: [email protected]
 */
public class UserQueryCondition {

    private String username;

    private int age;
    private int ageTo;

    private String xxx;

   // getter、setter
    
}

之後,定義一個controller:

package com.baiding.security.web.controller;

import com.baiding.security.model.User;
import com.baiding.security.model.UserQueryCondition;
import com.fasterxml.jackson.annotation.JsonView;
import org.apache.commons.lang.builder.ReflectionToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import org.springframework.data.domain.Pageable;
import org.springframework.data.web.PageableDefault;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.List;

/**
 * @Author: BaiDing
 * @Date: 2018/10/10 21:07
 * @Email: [email protected]
 */
@RestController
@RequestMapping("/user")
public class UserController {

    @GetMapping
    @JsonView(User.UserSimpleView.class)
    public List<User> query(UserQueryCondition condition,
                            @PageableDefault(page = 2, size = 17, sort = "username,asc") Pageable pageable) {

        System.out.println(ReflectionToStringBuilder.toString(condition, ToStringStyle.MULTI_LINE_STYLE));

        System.out.println(pageable.getPageSize());
        System.out.println(pageable.getPageNumber());
        System.out.println(pageable.getSort());

        List<User> users = new ArrayList<>();
        users.add(new User());
        users.add(new User());
        users.add(new User());
        return users;
    }

    @GetMapping("/{id:\\d+}")
    @JsonView(User.UserDetailView.class)
    public User getInfo(@PathVariable String id) {
        User user = new User();
        user.setUserName("tom");
        return user;
    }
    
	@PostMapping
    public User create(@RequestBody User user) {

        System.out.println(user.getId());
        System.out.println(user.getUserName());
        System.out.println(user.getPassword());
        System.out.println(user.getBirthday());

        user.setId(1);
        return user;
    }
    
    @PutMapping
    public User update(@RequestBody User user) {

        System.out.println(user.getId());
        System.out.println(user.getUserName());
        System.out.println(user.getPassword());
        System.out.println(user.getBirthday());
        user.setId(1);
        return user;
    }

    @DeleteMapping("/{id:\\d+}")
    public void delete(@PathVariable String id) {
        System.out.println(id);
    }

}

上面分別是使用Restful API來進行增刪改查,這裏簡單說明一下其中的一些代碼:

  • @PostMapping、@DeleteMapping、@PutMapping、@GetMapping這四個註解分別代表着增刪改查了
  • Pageable 是Spring Data庫中定義的一個接口,該接口是所有分頁相關信息的一個抽象,通過該接口,我們可以得到和分頁相關所有信息,當然你可以自己自定義一個類似的實體類來保存這些數據。
  • @JsonView 可以過濾序列化對象的字段屬性,可以使你有選擇的序列化對象。具體怎麼使用就不做介紹了
  • /{id:\\d+} 冒號後面接正則表達式是對參數做匹配約束

下面就可以設計測試類來做測試了,如下:

package com.baiding.security.test;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;

import java.util.Date;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

/**
 * @Author: BaiDing
 * @Date: 2018/10/10 21:03
 * @Email: [email protected]
 */
@RunWith(SpringRunner.class)
@SpringBootTest
public class WebTest {

    @Autowired
    private WebApplicationContext wac;

    private MockMvc mockMvc;

    @Before
    public void setUp(){
        this.mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
    }

    @Test
    public void whenQuerySuccess() throws Exception {
        String result = mockMvc.perform(
                get("/user").param("username", "jojo").param("age", "18").param("ageTo", "60").param("xxx", "yyy")
                        // .param("size", "15")
                        // .param("page", "3")
                        // .param("sort", "age,desc")
                        .contentType(MediaType.APPLICATION_JSON_UTF8))
                .andExpect(status().isOk()).andExpect(jsonPath("$.length()").value(3))
                .andReturn().getResponse().getContentAsString();

        System.out.println(result);
    }

    @Test
    public void whenGetInfoSuccess() throws Exception {
        String result = mockMvc.perform(get("/user/1")
                .contentType(MediaType.APPLICATION_JSON_UTF8))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.userName").value("tom"))
                .andReturn().getResponse().getContentAsString();

        System.out.println(result);
    }

    @Test
    public void whenGetInfoFail() throws Exception {
        mockMvc.perform(get("/user/a")
                .contentType(MediaType.APPLICATION_JSON_UTF8))
                .andExpect(status().is4xxClientError());
    }

    @Test
    public void whenCreateSuccess() throws Exception {

        Date date = new Date();
        System.out.println(date.getTime());
        String content = "{\"userName\":\"tom\",\"password\":\"as11\",\"birthday\":"+date.getTime()+"}";
        String reuslt = mockMvc.perform(post("/user").contentType(MediaType.APPLICATION_JSON_UTF8)
                .content(content))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.id").value("1"))
                .andReturn().getResponse().getContentAsString();

        System.out.println(reuslt);
    }

    @Test
    public void whenUpdateSuccess() throws Exception {

//        Date date = new Date(LocalDateTime.now().plusYears(1).atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
        Date date = new Date();
        System.out.println(date.getTime());
        String content = "{\"id\":1, \"userName\":\"tom\",\"password\":\"pwd123\",\"birthday\":"+date.getTime()+"}";
        String reuslt = mockMvc.perform(put("/user").contentType(MediaType.APPLICATION_JSON_UTF8)
                .content(content))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.id").value("1"))
                .andReturn().getResponse().getContentAsString();

        System.out.println(reuslt);
    }

    @Test
    public void whenDeleteSuccess() throws Exception {
        mockMvc.perform(delete("/user/1")
                .contentType(MediaType.APPLICATION_JSON_UTF8))
                .andExpect(status().isOk());
    }
}

關於如何使用MockMvc做單元測試,這裏不再贅述。

這裏的Before註解是在執行測試方法前先執行其標註的方法。

關於jsonPath的使用推薦學一下。

上面基本就是全部的代碼了,歡迎指正。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章