【Spring Security技術棧開發企業級認證與授權】----使用Spring MVC開發RESTful API (一)

前言

編寫博客分享一下,騷氣的RestFul Api O(∩_∩)O哈哈~


一、Restful

  • 使用SpringMVC編寫Restful API
    在這裏插入圖片描述
    通過上面的圖片我們可以看出,傳統的請求方式與RESTFUL請求方式,存在的不同:
    1.用URL描述資源
    2.使用HTTP方法描述行爲,使用HTTP狀態碼來表示不同的結果
    3.使用json交互數據
    4.RESTful 只是一種風格,並不是強制的標準。

在這裏插入圖片描述

二、查詢請求

直接上乾貨:

在這裏插入圖片描述

  • 編寫測試用例:
package com.zcw.web.controller;

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.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;

/**
 * @ClassName : UserControllerTest
 * @Description :
 * @Author : Zhaocunwei
 * @Date: 2020-06-16 15:37
 */
@RunWith(SpringRunner.class)//這個註解是告訴我們大家,是如何來運行。
@SpringBootTest
public class UserControllerTest {

     //模擬一個web環境
    @Autowired
    private WebApplicationContext webApplicationContext;
    private MockMvc mockMvc;

    @Before
    public void setup(){
        mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
    }
    @Test
    public void whenQuerySuccess() throws Exception {
        mockMvc.perform(MockMvcRequestBuilders.get("/user")
        .contentType(MediaType.APPLICATION_JSON_UTF8))
        //希望服務器返回的數據
        .andExpect(MockMvcResultMatchers.status().isOk())
        //返回的json內容
        .andExpect(MockMvcResultMatchers.jsonPath("$.length()").value(3));
    }
}



  • 編寫服務,使用註解聲明RestfulAPI
    在這裏插入圖片描述
    在這裏插入圖片描述
    在這裏插入圖片描述
package com.zcw.web.controller;

import com.zcw.dto.User;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

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

/**
 * @ClassName : UserController
 * @Description :
 * @Author : Zhaocunwei
 * @Date: 2020-06-16 16:06
 */
@RestController
public class UserController {
    @RequestMapping(value = "/user",method = RequestMethod.GET)
    public List<User> query(){
        List<User> users = new ArrayList<>();
        users.add(new User());
        users.add(new User());
        users.add(new User());
        return users;
    }

}


  • 創建DTO用來存放輸入與輸出數據:
    在這裏插入圖片描述
 <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.12</version>
            <scope>provided</scope>
        </dependency>

package com.zcw.dto;


import lombok.Data;

/**
 * @ClassName : User
 * @Description :
 * @Author : Zhaocunwei
 * @Date: 2020-06-16 16:11
 */
@Data
public class User {

    private String username;
    private String password;
}


  • 測試
    在這裏插入圖片描述
  • 在RestfulAPI中傳遞參數
package com.zcw.dto;

import lombok.Data;

/**
 * @ClassName : UserQueryCondition
 * @Description :
 * @Author : Zhaocunwei
 * @Date: 2020-06-16 17:31
 */
@Data
public class UserQueryCondition {
    private String username;
    private int age;
    private int ageTo;
    private String xxx;
}


test方法:


 @Test
    public void whenQuerySuccess() throws Exception {
        mockMvc.perform(MockMvcRequestBuilders.get("/user")
                .param("username","jojo")
                .param("age","18")
                .param("ageTo","60")
                .param("xxx","yyyy")
                .param("size","15")
                .param("page","3")
                .param("sort","age,desc")
        .contentType(MediaType.APPLICATION_JSON_UTF8))
        //希望服務器返回的數據
        .andExpect(MockMvcResultMatchers.status().isOk())
        //返回的json內容
        .andExpect(MockMvcResultMatchers.jsonPath("$.length()").value(3));
    }

在這裏插入圖片描述

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
**加粗樣式**

三、用戶詳情請求

編寫用戶詳情服務:

  • 測試用例:
 @Test
    public void whenGenInfoSucces() throws Exception {
        mockMvc.perform(MockMvcRequestBuilders.get("/user/1")
                .contentType(MediaType.APPLICATION_JSON_UTF8))
                .andExpect(MockMvcResultMatchers.status().isOk())
                .andExpect(MockMvcResultMatchers.jsonPath("$.username")
                        .value("tom"));
    }

在這裏插入圖片描述
在這裏插入圖片描述

  • 測試
    在這裏插入圖片描述

  • @PathVariable映射url片段到java方法的參數

  • 在url聲明中使用正則表達式
    只接收數字:
    在這裏插入圖片描述

  • @JsonView控制json輸出內容
    使用步驟:
    1.使用接口來聲明多個視圖
    在這裏插入圖片描述

@Data
public class User {
    public interface  UserSimpleView{};
    public interface  UserDetailView extends  UserSimpleView{};
    private String username;
    private String password;
}


2.在值對象的get方法上指定視圖

需要把我們的@Data註解去掉。
在這裏插入圖片描述
3.在Controller方法上指定視圖
在這裏插入圖片描述

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

  • 測試
    在這裏插入圖片描述
    在這裏插入圖片描述

四、用戶創建請求

@RequestBody映射請求體到java方法的參數

  @Test
    public void whenCreateSuccess() throws Exception {
        String content="{\"username\":\"tom\",\"password\":null}";
        mockMvc.perform(MockMvcRequestBuilders.post("/user")
                .contentType(MediaType.APPLICATION_JSON_UTF8)
                .content(content))
                .andExpect(MockMvcResultMatchers.status().isOk())
                .andExpect(MockMvcResultMatchers.jsonPath("$.id").value("1"));
    }

在這裏插入圖片描述

  • controller類:
    在這裏插入圖片描述
  • 測試:
    在這裏插入圖片描述
    在這裏插入圖片描述
    在這裏插入圖片描述

日期類型參數的處理

一般是時間戳,返回給前端。
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

  • 測試:
    在這裏插入圖片描述

@Valid註解和BindingResult驗證請求參數的合法性並處理校驗結果

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

  • 測試
    在這裏插入圖片描述
    在這裏插入圖片描述
    在這裏插入圖片描述

五、修改和刪除請求

  • Test
 @Test
    public void whenCreateSuccess() throws Exception {
        Date date = new Date(LocalDateTime.now()
                .plusYears(1)
                .atZone(ZoneId.systemDefault())
                .toInstant()
                .toEpochMilli()
        );
        System.out.println(date.getTime());

        String content="{\"id\":\"1\",\"username\":\"tom\",\"password\":null,\"birthday\":"+date.getTime()+"}";
        String result = mockMvc.perform(MockMvcRequestBuilders.put("/user/1")
                .contentType(MediaType.APPLICATION_JSON_UTF8)
                .content(content))
                .andExpect(MockMvcResultMatchers.status().isOk())
                .andExpect(MockMvcResultMatchers.jsonPath("$.id").value("1"))
                .andReturn().getResponse().getContentAsString();
        System.out.println(result);
    }
  • 服務
    在這裏插入圖片描述
 @PutMapping("/{id:\\d+}")
    public User update(@Valid @RequestBody User user,BindingResult errors){
        if(errors.hasErrors()){
            errors.getAllErrors()
                    .stream()
                    .forEach(error ->{
                        FieldError fieldError=(FieldError)error;
                        String field = fieldError.getField()+error.getDefaultMessage();
                        System.out.println(field);
                    }
                   );
        }
        user.setId("1");
        return user;
    }

  • 修改我們校驗,提示信息,在實體類裏面定義
    在這裏插入圖片描述
  • 測試:
    運行單元測試方法時報錯:

JDBC連接數據庫時出現的Public Key Retrieval is not allowed錯誤

添加了:

&allowPublicKeyRetrieval=true
   url: jdbc:mysql://127.0.0.1:3306/zcw20200509?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8&useSSL=false&allowPublicKeyRetrieval=true

在這裏插入圖片描述

自定義註解進行校驗javabean:

  • 方便,效率高
package com.zcw.validator;

import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.METHOD,ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy=MyConstraintValidator.class)
public @interface MyConstraint {
    String message();
    Class<?>[] groups() default {};
    Class<? extends Payload> [] payload() default {};
}



package com.zcw.validator;

import com.zcw.web.service.HelloService;
import org.springframework.beans.factory.annotation.Autowired;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

/**
 * @ClassName : MyConstraintValidator
 * @Description :
 * @Author : Zhaocunwei
 * @Date: 2020-06-17 10:11
 */
public class MyConstraintValidator implements ConstraintValidator<MyConstraint,Object> {
    @Autowired
    private HelloService helloService;
    @Override
    public void initialize(MyConstraint myConstraint) {
        System.out.println("my validator init");
    }

    @Override
    public boolean isValid(Object o, ConstraintValidatorContext constraintValidatorContext) {
        //目的,告訴大家,在校驗器中我們可以編寫,我們任何類的,校驗邏輯
        helloService.greeting("tom");
        System.out.println(o);
        return true;
    }
}

  • 編寫測試業務類:

package com.zcw.web.service;


public interface HelloService {
    String greeting(String name);
}


package com.zcw.web.service.impl;

import com.zcw.web.service.HelloService;
import org.springframework.stereotype.Service;

/**
 * @ClassName : HelloServiceImpl
 * @Description :
 * @Author : Zhaocunwei
 * @Date: 2020-06-17 10:17
 */
@Service
public class HelloServiceImpl implements HelloService {
    @Override
    public String greeting(String name) {
        System.out.println("greeting");
        return "hello"+name;
    }
}

在這裏插入圖片描述

  • 測試:
    在這裏插入圖片描述
    在這裏插入圖片描述
    在這裏插入圖片描述

刪除方法:

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

  • 業務代碼
 @DeleteMapping("/{id:\\d+}")
    public void delete(@PathVariable String id){
       System.out.println(id);
   }
  • 測試:
    在這裏插入圖片描述

六、服務異常處理

springboot中默認的錯誤處理機制:

在這裏插入圖片描述

根據狀態碼進行跳轉,默認跳轉。
在這裏插入圖片描述

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>404</title>
</head>
<body>
    您所訪問的頁面不存在
</body>
</html>
  • 測試
    在這裏插入圖片描述

自定義異常處理

package com.zcw.exception;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

import java.util.HashMap;
import java.util.Map;

/**
 * @ClassName : ControllerExceptionHandler
 * @Description : 控制器的錯誤處理器
 * @Author : Zhaocunwei
 * @Date: 2020-06-17 11:51
 */
@ControllerAdvice
public class ControllerExceptionHandler {

    @ExceptionHandler(UserNotExistException.class)
    @ResponseBody
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public Map<String,Object> handleUserNotExistException(UserNotExistException ex){
        Map<String,Object> result = new HashMap<>();
        result.put("id",ex.getId());
        result.put("message",ex.getMessage());
        return result;
    }
}


package com.zcw.exception;

/**
 * @ClassName : UserNotExistException
 * @Description :
 * @Author : Zhaocunwei
 * @Date: 2020-06-17 11:46
 */
public class UserNotExistException extends RuntimeException {
    private String id;
    public UserNotExistException(String id){
        super("user not exist");
        this.id=id;
    }

    public String getId() {
        return id;
    }

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

在這裏插入圖片描述

  • 測試:
    在這裏插入圖片描述
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章