本文最后更新于:June 7, 2022 pm
SpringBoot框架中有两个非常重要的策略:开箱即用和约定优于配置。其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。
目录
创建一个SpringBoot项目,并进行相应的配置。
配置文件
application.yml
| ttf: www.tothefor.com
tothefor: name: 墨水记忆 website: tothefor.com description: 最好的记忆不如最淡的墨水 tags: - name: Java description: Java类 - name: C description: C类 - name: PHP description: PHP类
|
配置读取
Controller
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| package com.tothefor.controller;
import io.lettuce.core.output.SocketAddressOutput; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController;
@Controller @RestController public class TestController {
@Value("${ttf}") private String name; @Value("${tothefor.name}") private String web;
@GetMapping("/getInfo") public void show(){ System.out.println(name); System.out.println(web); }
}
|
访问 http://localhost:8080/getInfo 后,查看控制台输出:
Bean读取
通过@ConfigurationProperties
读取配置信息并与 bean 绑定。
配置信息对应的类:(注意一定要写对应的setter和getter)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| package com.tothefor.controller;
import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.ToString; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Configuration; import org.springframework.stereotype.Component;
import java.util.List;
@Data @ToString @AllArgsConstructor @NoArgsConstructor @Component @ConfigurationProperties(prefix = "tothefor") class TestDTO {
private String name; private String website; private String description;
private List<Book> tags;
@Data @ToString @AllArgsConstructor @NoArgsConstructor static class Book{ String name; String description; }
}
|
测试:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| package com.tothefor.controller;
import io.lettuce.core.output.SocketAddressOutput; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController;
@Controller @RestController public class TestController {
@Autowired private TestDTO testDTO;
@GetMapping("/getInfo") public void show(){ System.out.println(testDTO.getName()); System.out.println(testDTO.getWebsite()); System.out.println(testDTO.getDescription()); System.out.println(testDTO.getTags()); }
}
|
输出:
| 墨水记忆 tothefor.com 最好的记忆不如最淡的墨水 [TestDTO.Book(name=Java, description=Java类), TestDTO.Book(name=C, description=C类), TestDTO.Book(name=PHP, description=PHP类)]
|
以下示例均通过Postman进行测试。
参数校验
在前端对数据进行校验的情况下,我们还是要对传入后端的数据再进行一遍校验,避免用户绕过浏览器直接通过一些 HTTP 工具直接向后端请求一些违法数据。
JSR(Java Specification Requests) 是一套 JavaBean 参数校验的标准,它定义了很多常用的校验注解,我们可以直接将这些注解加在我们 JavaBean 的属性上面,这样就可以在需要校验的时候进行校验了,非常方便!而 SpringBoot 项目的 spring-boot-starter-web 依赖中已经有 hibernate-validator 包,不需要引用相关依赖。
注:更新版本的 spring-boot-starter-web 依赖中不再有 hibernate-validator 包(如2.3.11.RELEASE),需要自己引入 spring-boot-starter-validation
依赖。
常用的字段验证的注解
@NotEmpty
被注释的字符串的不能为 null 也不能为空
@NotBlank
被注释的字符串非 null,并且必须包含一个非空白字符
@Null
被注释的元素必须为 null
@NotNull
被注释的元素必须不为 null
@AssertTrue
被注释的元素必须为 true
@AssertFalse
被注释的元素必须为 false
@Pattern(regex=,flag=)
被注释的元素必须符合指定的正则表达式
@Email
被注释的元素必须是 Email 格式。
@Min(value)
被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@Max(value)
被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@DecimalMin(value)
被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@DecimalMax(value)
被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@Size(max=, min=)
被注释的元素的大小必须在指定的范围内
@Digits(integer, fraction)
被注释的元素必须是一个数字,其值必须在可接受的范围内
@Past
被注释的元素必须是一个过去的日期
@Future
被注释的元素必须是一个将来的日期
测试
导入依赖:(注意使用时,是使用的javax
包下的,而不是org
包下的)
| <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency>
|
请求体校验
实体类(RequestBody):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| package com.tothefor.controller;
import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.ToString;
import javax.validation.constraints.*;
@Data @NoArgsConstructor @AllArgsConstructor @ToString public class CheckTestDto {
@NotNull(message = "名称不能为空") @Size(max = 15,min = 5,message = "请输入在5-15范围内的长度") private String name;
@Min(value = 13,message = "最小不得低于13") private Integer minAge; @Max(value = 23,message = "最大不得高于23") private Integer maxAge;
@Email(message = "email 格式不正确") @NotNull(message = "email 不能为空") private String email;
}
|
在需要验证的参数上加上了@Valid
注解,如果验证失败,它将抛出MethodArgumentNotValidException
。
测试:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| package com.tothefor.controller;
import io.lettuce.core.output.SocketAddressOutput; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
@Controller @RestController public class TestController {
@PostMapping("/getInfo") public void show(@RequestBody @Valid CheckTestDto checkTestDto){ System.out.println("参数全部符合要求"); }
}
|
测试样例
全部符合
| { "name":"tothefor", "minAge":13, "maxAge":23, "email":"123456798@qq.com" }
|
正确输出:
minAge不符合
| { "name":"tothefor", "minAge":10, "maxAge":23, "email":"123456798@qq.com" }
|
报错:
| 2022-06-07 15:38:25.731 WARN 1463 --- [nio-8080-exec-3] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument [0] in public void com.tothefor.controller.TestController.show(com.tothefor.controller.CheckTestDto): [Field error in object 'checkTestDto' on field 'minAge': rejected value [10]; codes [Min.checkTestDto.minAge,Min.minAge,Min.java.lang.Integer,Min]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [checkTestDto.minAge,minAge]; arguments []; default message [minAge],13]; default message [最小不得低于13]] ]
|
name不符合
| { "name":"ttf", "minAge":13, "maxAge":23, "email":"123456798@qq.com" }
|
报错:
| 2022-06-07 15:39:34.212 WARN 1463 --- [nio-8080-exec-7] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument [0] in public void com.tothefor.controller.TestController.show(com.tothefor.controller.CheckTestDto): [Field error in object 'checkTestDto' on field 'name': rejected value [ttf]; codes [Size.checkTestDto.name,Size.name,Size.java.lang.String,Size]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [checkTestDto.name,name]; arguments []; default message [name],15,5]; default message [请输入在5-15范围内的长度]] ]
|
其他的情况同理。
请求参数校验
分为Path Variables 和 Request Parameters。一定要在类上加上 @Validated
注解,这个参数可以告诉 Spring 去校验方法参数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| package com.tothefor.controller;
import io.lettuce.core.output.SocketAddressOutput; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Controller; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*;
import javax.validation.Valid; import javax.validation.constraints.Size;
@Controller @RestController @Validated public class TestController {
@PostMapping("/getInfo/{check}") public void show(@Valid @PathVariable("check") @Size(max = 15,min = 5,message = "请输入在5-15范围内的长度") String check){ System.out.println("参数符合要求"); System.out.println(check); }
}
|
测试样例
符合要求
不符合要求
| javax.validation.ConstraintViolationException: show.check: 请输入在5-15范围内的长度
|
上面讲了不符合要求时会抛出异常,现在就简单说一说怎么处理这个异常。
异常处理(Controller)
相关注解:
@ControllerAdvice
:注解定义全局异常处理类
@ExceptionHandler
:注解声明异常处理方法
我拿上面最后一个示例说明:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| package com.tothefor.controller;
import io.lettuce.core.output.SocketAddressOutput; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Controller; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*;
import javax.validation.Valid; import javax.validation.constraints.Size;
@Controller @RestController @Validated public class TestController {
@PostMapping("/getInfo/{check}") public void show(@Valid @PathVariable("check") @Size(max = 15,min = 5,message = "请输入在5-15范围内的长度") String check){ System.out.println("参数符合要求"); System.out.println(check); }
}
|
异常处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| package com.tothefor.controller;
import org.springframework.http.ResponseEntity; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody;
@ControllerAdvice(assignableTypes = {TestController.class}) @ResponseBody public class ExcetipnConfig {
@ExceptionHandler(value = Exception.class) public ResponseEntity<?> exceptionHandler(Exception e) {
if (e instanceof IllegalArgumentException) { System.out.println("IllegalArgumentException"); return ResponseEntity.status(400).body("IllegalArgumentException"); } else if(e instanceof MethodArgumentNotValidException){ System.out.println("MethodArgumentNotValidException"); return ResponseEntity.status(404).body("MethodArgumentNotValidException"); } System.out.println("其他异常"); return null; } }
|