SpringBoot接口接收json參數解析
SpringBoot接口接收json參數
前言
通常來講,HTTP 方法會映射為 CRUD 動作,但這並不是嚴格的限制,有時候 PUT 也可以用來創建新的資源,POST 也可以用來更新資源。所以在平時的 Web 開發中,你可能常看到method 的值是 GET 和 POST,但是我們需要養成一個好的編碼習慣。
CRUD 動作 | HTTP 方法 |
---|---|
Create | POST |
Read | GET |
Update | PUT(全部資源) 或 PATCH(部分資源) |
Delete | DELETE |
前提
首先在controller上加上註解:@RestController
@RestController @RequestMapping("/user") @Api(tags = "user", description = "用戶控制器") public class UserController { // ... }
詳細介紹
一、GET
1)@PathVariable 獲取路徑參數。即 url/{id} 這種形式。
@GetMapping("/getDetail/{id}") @ApiOperation(value = "根據id獲取用戶") public RbacUser getDetail(@PathVariable Long id) { return userService.getById(id); }
2)@RequestParam 獲取查詢參數。即 url?name=xx 這種形式
主要有參數:
value
:參數名字,即入參的請求參數名字,如username表示請求的參數區中的名字為username的參數的值將傳入;required
:是否必須,默認是true,表示請求中一定要有相應的參數,否則會報錯;
@GetMapping("/getByAccount") @ApiOperation(value = "根據賬號獲取用戶") public RbacUser getByAccount(@RequestParam(required = false) String account) { return userService.getByAccount(account); }
3) 直接封裝DTO參數形式
@GetMapping("/find") @ApiOperation(value = "根據條件獲取用戶") public List<RbacUser> find(RbacUserDTO rbacUserDTO) { return userService.find(rbacUserDTO); }
二、DELETE
@PathVariable 獲取路徑參數。即 url/{id} 這種形式。
@DeleteMapping("/delete/{id}") @ApiOperation(value = "刪除用戶") public void delete(@PathVariable Long id) { userService.delete(id); }
三、POST/PUT/PATCH
@RequestBody 將HTTP請求正文插入方法中,使用適合的 HttpMessageConverter 將請求體寫入某個對象。
@PostMapping("/create") @ApiOperation(value = "創建用戶") public RbacUser getByAccount(@RequestBody @Validated RbacUserDTO rbacUserDTO) { return userService.save(rbacUserDTO); }
@Validated
:對數據進行校驗,以下註解報錯會直接返回,如果校驗類中包含一個對象引用屬性,需要在屬性上加上@Valid註解
具體參數檢驗請參看下面
Springboot restFul 參數檢驗
概述
對請求參數進行檢驗,這在web中開始經常能碰到,如果用一個個if/else去做判斷,相信這樣的代碼可讀性會比較差
JSR-303 是java為bean數據合法性校驗提供的標準框架,是Java EE6中的一項子規范,叫做BeanValidation。JSR303通過在Bean屬性上標註@NotNull、@Max等標準的註解指定校驗規則,並通過這些標準的驗證接口對Bean進行驗證。
規定一些檢驗規范即校驗註解,如@Null, @NotNull, @Pattern,位於javax.validation.constraints包下,隻提供規范 不提供實現。
在Spring中,有兩種方式可以驗證輸入,一是利用Spring自帶的驗證框架,二是利用JSR-303的實現,一般建議使用JSR-303的實現,比如Hibernate-Validator。
Hibernate-Validator是JSR-303的實現。Hibernate Validator提供瞭JSR-303規范中所有內置constraint的實現,除此之外還有一些附加的constraint,如@Email, @Length, @Range等,位於org.hibernate,validator.constraints包下。
spring-boot-starter-web包裡面已經有瞭hibernate-vlidator包,不需要額外引用hibernate validator依賴。
同時Spring為瞭給開發者提供便捷,對Hibernate-Validator進行瞭二次封裝,封裝瞭LocalValidatorFactorBean作為validator的實現,這個類兼容瞭Spring的Validation體系和Hibernate的Validation體系,LocalValidatorFactorBean已經成為瞭Validator的默認實現。
說明:JSR-349是JSR-303的升級版,添加瞭一些新特性
如下圖,是spring boot 2.1.1中hibernate依賴情況:
常用註解
屬性 | 描述 | 舉例 |
@AssertTrue | 應用於boolean屬性,該屬性值必須為true |
@AssertTrue boolean isOkay; |
@AssertFalse | 應用於boolean屬性,該屬性值必須為false |
@AssertFalse boolean isOkay; |
@DecimalMax | 隻能小於或等於指定值 |
@DecimalMax(“1.1”) BigDecimal price; |
@DecimalMin | 隻能大於或等於指定值 |
@DecimalMin(“1.1”) BigDecimal price; |
@Digits | 該屬性值必須在指定范圍內,interger屬性定義該數值的最大整數部分,fraction屬性定義該數值的最大 小數部分 |
@Digits(integer=5, fraction=2) BigDecimal price; |
@Future | 檢查該字段是否是屬於未來的日期 |
@Future Date shippingDate; |
@Max | 該字段的值隻能小於或等於該值 |
@Max(20) int age; |
@Min | 該字段的值隻能大於或等於該值 |
@Min(20) int age; |
@NotNull | 該字段不能為Null |
@NotNull String name; |
@Null | 該字段必須是Null |
@Null String dest; |
@Past | 該字段必須是過去的一個日期 |
@Past Date birthDate; |
@Size | 檢查該字段的size是否在min和max之間,可以是字符串、數組、集合、Map等 |
@Size(min=2, max=10) String description; |
@Pattern | 該屬性值必須與指定的常規表達式相匹配 |
@Pattern(regexp=”\\d{3}”) String areaCode; |
@NotBlank | 隻用於String, 不能為Null且trim()之後size>0 |
@NotBlank String src; |
@NotEmpty | 不能為Null,且size>0 |
@NotEmpty String src; |
被註釋的元素必須是電子郵箱地址 | ||
@Length | 被註釋的字符串String 大小必須在指定范圍內 |
@Length(min=6, max=12, message=”密碼長度必須在6~12″) String src; |
@Range | BigDecimal,BigInteger,CharSequence, byte, short, int, long等原子類型和包裝類型,驗證註解的元素值在最小值和最大值之間 | |
@Valid |
指定遞歸驗證(下篇講)關聯的對象; 如用戶對象中有個地址對象屬性,如果想在驗證用戶對象時一起驗證地址對象的話,在地址對象上加@Valid註解即可級聯驗證 |
簡單應用舉例
需要檢驗的Bean定義:
public class StudentBean implements Serializable{ @NotBlank(message = "用戶名不能為空") private String name; @Min(value = 18, message = "年齡不能小於18歲") private Integer age; @Pattern(regexp = "^((13[0-9])|(14[5,7,9])|(15([0-3]|[5-9]))|(166)|(17[0,1,3,5,6,7,8])|(18[0-9])|(19[8|9]))\\d{8}$", message = "手機號格式錯誤") private String phoneNum; @Email(message = "郵箱格式錯誤") private String email; 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; } public String getPhoneNum() { return phoneNum; } public void setPhoneNum(String phoneNum) { this.phoneNum = phoneNum; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } }
返回錯誤字段定義:
public class ArgumentsInvalidResponseBean { private String argumentName; private String exceptionMsg; public ArgumentsInvalidResponseBean() { } public ArgumentsInvalidResponseBean(String argumentName, String exceptionMsg) { this.argumentName = argumentName; this.exceptionMsg = exceptionMsg; } public String getArgumentName() { return argumentName; } public void setArgumentName(String argumentName) { this.argumentName = argumentName; } public String getExceptionMsg() { return exceptionMsg; } public void setExceptionMsg(String exceptionMsg) { this.exceptionMsg = exceptionMsg; } }
全局異常處理:
@ExceptionHandler(MethodArgumentNotValidException.class) @ResponseBody public List<ArgumentsInvalidResponseBean> methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException ex){ System.out.println("===================methodArgumentNotValidExceptionHandler Occur============"); List<ArgumentsInvalidResponseBean> argumentsInvalidResponseBeanList = new ArrayList<>(); for (FieldError error : ex.getBindingResult().getFieldErrors()){ ArgumentsInvalidResponseBean bean = new ArgumentsInvalidResponseBean(); bean.setArgumentName(error.getField()); bean.setExceptionMsg(error.getDefaultMessage()); argumentsInvalidResponseBeanList.add(bean); } return argumentsInvalidResponseBeanList; }
測試代碼:
@RestController public class CheckController { @PostMapping("stu") public String addStu(@Valid @RequestBody StudentBean studentBean){ return "add student success"; } }
在PostMan中測試:
註意這裡,年齡和郵箱是有錯誤的,運行後查看返回值,具體如下:
自定義校驗
新建註解類 MyConstraint:
@Target({ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @Constraint(validatedBy = MyConstraintValidator.class) public @interface MyConstraint { String message() default "這是一個自定義註解,檢測輸入是否大寫"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; }
實現MyConstraintValidator:
public class MyConstraintValidator implements ConstraintValidator<MyConstraint, String> { @Override public void initialize(MyConstraint constraintAnnotation) { System.out.println("+++++++++++++myConstraint init"); } @Override public boolean isValid(String o, ConstraintValidatorContext constraintValidatorContext) { if (!o.equals(o.toUpperCase())){ System.out.println("輸入信息必須是大寫"); return false; } return true; } }
當輸入信息不是全大寫字符時,則檢驗不通過
使用:
在上面StudentBean中加入檢驗
@MyConstraint private String className;
測試:
結果如下:
這時說明自定義檢驗可以工作瞭
拋出BindException而非MethodArgumentNotValidException
當請求中 Content-Type為“application/x-www-form-urlencoded”時,Spring會把數據解析成 web form data而非json,會使用 FormHttpMessageConverter來轉換post的body 並且異常轉為BindException。
如果我們想要Spring把POST數據認為是json並且使用MappingJackson2HttpMessageConverter來解析數據,可以把Content-Type設置成 application/json
以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。
推薦閱讀:
- SpringBoot開發技巧啟動時配置校驗實現示例
- SpringBoot參數校驗的最佳實戰教程
- SpringBoot參數校驗的方法總結
- @Valid註解的作用及@Valid註解與@Validated的區別
- 如何使用Bean Validation 解決業務中參數校驗