1. 程式人生 > >Spring Boot(三) web進階

Spring Boot(三) web進階

一、表單驗證@Valid

示例:@Min @Valid標識屬性為需要驗證的屬性,BindingResult列印錯誤資訊

Girl實體類:

package com.mlj.girl.domain;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.validation.constraints.Min;

@Entity
public class Girl {

    @Id
    @GeneratedValue
    private Integer id;

    private String cupSize;

    @Min(value = 18,message = "禁止未成年入內!")//規定最小值
    private Integer age;

    public Girl() {
    }
//    必須有無參構造

    public Integer getId() {
        return id;
    }

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

    public String getCupSize() {
        return cupSize;
    }

    public void setCupSize(String cupSize) {
        this.cupSize = cupSize;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}

controller:

package com.mlj.girl.controller;

import com.mlj.girl.Repository.GirlRepository;
import com.mlj.girl.domain.Girl;
import com.mlj.girl.domain.Result;
import com.mlj.girl.service.GirlService;
import com.mlj.girl.utils.ResultUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.List;

@RestController
public class GirlController {

    @Autowired
    private GirlRepository girlRepository;
    @Autowired
    private GirlService girlService;

  * 新增
     *
     * @return
     */
    @PostMapping(value = "/girls")
    public Result<Girl> girlAdd(@Valid Girl girl, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            System.out.println(bindingResult.getFieldError().getDefaultMessage());
//            return ResultUtil.error(1, bindingResult.getFieldError().getDefaultMessage());
            return null;
        }
        System.out.println(girl.getAge().toString());
        Girl girl1 = girlRepository.save(girl);
        return ResultUtil.success(girl1);
    }


}

其他驗證規則:

限制                      說明
@Null                      限制只能為null
@NotNull                    限制必須不為null
@AssertFalse                  限制必須為false
@AssertTrue                  限制必須為true
@DecimalMax(value)              限制必須為一個不大於指定值的數字
@DecimalMin(value)              限制必須為一個不小於指定值的數字
@Digits(integer,fraction)          限制必須為一個小數,且整數部分的位數不能超過integer,小數部分的位數不能超過fraction
@Future                      限制必須是一個將來的日期
@Max(value)                    限制必須為一個不大於指定值的數字
@Min(value)                  限制必須為一個不小於指定值的數字
@Past                     限制必須是一個過去的日期
@Pattern(value)               限制必須符合指定的正則表示式
@Size(max,min)                限制字元長度必須在min到max之間
@Past                      驗證註解的元素值(日期型別)比當前時間早
@NotEmpty                    驗證註解的元素值不為null且不為空(字串長度不為0、集合大小不為0)
@NotBlank                    驗證註解的元素值不為空(不為null、去除首位空格後長度為0),不同於@NotEmpty,@NotBlank只應用於字串且在比較時會去除字串的空格
@Email                      驗證註解的元素值是Email,也可以通過正則表示式和flag指定自定義的email格式

二、使用AOP處理請求

在學習Spring時已經學習了AOP,以日誌處理為例

spring-AOP+自定義註解實現日誌管理(註解方式實現)

三、統一異常處理和統一返回值

Result類:統一返回物件。定義錯誤程式碼,提示資訊,返回具體內容(沒有則為空)

package com.mlj.girl.domain;

public class Result<T> {

    private Integer code;//錯誤碼

    private String msg;//提示資訊

    private T data;//具體內容

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }
}
ResultUtil工具類,減少程式碼重複
package com.mlj.girl.utils;

import com.mlj.girl.domain.Result;

public class ResultUtil {

    /**
     * 成功且有返回值
     *
     * @param object
     * @return
     */
    public static Result success(Object object) {
        Result result = new Result();
        result.setCode(0);
        result.setMsg("成功");
        result.setData(object);
        return result;
    }

    /**
     * 成功無返回值
     *
     * @return
     */
    public static Result success() {
        return success(null);
    }

    /**
     * 失敗
     *
     * @param code
     * @param msg
     * @return
     */
    public static Result error(Integer code, String msg) {
        Result result = new Result();
        result.setCode(code);
        result.setMsg(msg);
        return result;
    }
}

成功時返回:

  /**
     * 新增
     *
     * @return
     */
    @PostMapping(value = "/girls")
    public Result<Girl> girlAdd(@Valid Girl girl, BindingResult bindingResult) {
        Girl girl1 = girlRepository.save(girl);
        return ResultUtil.success(girl1);
    }

失敗時進行異常處理

除了系統異常還有其他非系統異常,比如使用者輸入格式錯誤導致的異常等,需要自定義異常來進行區分

為了將異常資訊與錯誤碼對應起來並且易於管理,這裡使用列舉

ResultEnum
package com.mlj.girl.enums;

public enum ResultEnum {

    UNKONW_ERROR(-1, "未知錯誤"),
    SUCCESS(0, "成功"),
    PRIMARY_SCHOOL(100, "還在上小學"),
    MIDDLE_SCHOOL(101, "還在上初中");

    private Integer code;//錯誤碼

    private String msg;//錯誤資訊

    ResultEnum(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public Integer getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }
}

自定義異常GirlException類

package com.mlj.girl.exception;

import com.mlj.girl.enums.ResultEnum;

public class GirlException extends RuntimeException {

    private Integer code;//錯誤碼

    public GirlException(ResultEnum resultEnum) {
        super(resultEnum.getMsg());
        this.code = resultEnum.getCode();
    }

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }
}

進行異常捕捉,用於捕捉系統丟擲的異常

ExceptionHandle

import com.mlj.girl.domain.Result;
import com.mlj.girl.exception.GirlException;
import com.mlj.girl.utils.ResultUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

@ControllerAdvice
public class ExceptionHandle {

    private final static Logger logger = LoggerFactory.getLogger(ExceptionHandle.class);
    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public Result handle(Exception e) {
//        判斷是否是自定義異常
        if (e instanceof GirlException) {
            GirlException girlException = (GirlException) e;
            return ResultUtil.error(girlException.getCode(), girlException.getMessage());
        } else {
//系統異常在控制檯列印
            logger.error("【系統異常】{}",e);
            return ResultUtil.error(-1, "未知錯誤");
        }

    }
}

製造異常進行測試:

在service中

public void getAge(Integer id) throws Exception {
        Girl girl = girlRepository.findById(id).get();
        Integer age = girl.getAge();
        if (age < 10) {
//丟擲異常,指定異常型別
            throw new GirlException(ResultEnum.PRIMARY_SCHOOL);
        } else if (age > 10 && age < 16) {
            throw new GirlException(ResultEnum.MIDDLE_SCHOOL);
        }

    }

結果:

 
 

四、單元測試

在需要測試的檔案內右鍵=》go to =>test=>creatNewTest

勾選需要測試的方法

自動生成的測試檔案

service層測試:

package com.mlj.girl;

import com.mlj.girl.domain.Girl;
import com.mlj.girl.service.GirlService;
import org.junit.Assert;
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.test.context.junit4.SpringRunner;

//在測試環境下,底層使用junit測試工具
@RunWith(SpringRunner.class)
@SpringBootTest
public class GirlServiceTest {

    @Autowired
    private GirlService girlService;

    @Test
    public void findOneTest() {
        Girl girl = girlService.findOne(17);
        Assert.assertEquals(new Integer(34),girl.getAge());
    }
}

controller層測試:

用到@AutoConfigureMockMvc註解 MockMvc類

package com.mlj.girl.controller;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
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 static org.junit.Assert.*;

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class GirlControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @Test
    public void girlList() throws Exception {
        mockMvc.perform(MockMvcRequestBuilders.get("/girls"))
                .andExpect(MockMvcResultMatchers.status().isOk())
                .andExpect(MockMvcResultMatchers.content().string("aa"));
    }
}

右鍵方法名進行測試:下面清晰的顯示錯誤