├── .gitignore
├── README.md
├── pom.xml
└── src
├── main
├── java
│ └── com
│ │ └── github
│ │ └── chentianming11
│ │ └── spring
│ │ └── validation
│ │ ├── SpringValidationApplication.java
│ │ ├── base
│ │ ├── BusinessCode.java
│ │ ├── CommonExceptionHandler.java
│ │ ├── EnvironmentConfig.java
│ │ ├── Result.java
│ │ ├── ReturnCode.java
│ │ ├── Swagger2Config.java
│ │ └── Validation
│ │ │ ├── EncryptId.java
│ │ │ ├── EncryptIdValidator.java
│ │ │ └── ValidationList.java
│ │ ├── controller
│ │ ├── DegradeController.java
│ │ ├── PersonController.java
│ │ └── UserController.java
│ │ ├── http
│ │ ├── HttpDegradeApi.java
│ │ ├── HttpDegradeFallback.java
│ │ ├── HttpDegradeFallbackFactory.java
│ │ └── HttpTestAPI.java
│ │ └── pojo
│ │ ├── PersonVO.java
│ │ ├── SavePersonDTO.java
│ │ ├── UpdatePersonDTO.java
│ │ └── dto
│ │ └── UserDTO.java
└── resources
│ ├── application-local.yml
│ └── application.yml
└── test
└── java
└── com
└── github
└── chentianming11
└── spring
└── validation
├── DegradeTest.java
└── SpringValidationApplicationTests.java
/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | target/
3 | !.mvn/wrapper/maven-wrapper.jar
4 | !**/src/main/**/target/
5 | !**/src/test/**/target/
6 |
7 | ### STS ###
8 | .apt_generated
9 | .classpath
10 | .factorypath
11 | .project
12 | .settings
13 | .springBeans
14 | .sts4-cache
15 |
16 | ### IntelliJ IDEA ###
17 | .idea
18 | *.iws
19 | *.iml
20 | *.ipr
21 |
22 | ### NetBeans ###
23 | /nbproject/private/
24 | /nbbuild/
25 | /dist/
26 | /nbdist/
27 | /.nb-gradle/
28 | build/
29 | !**/src/main/**/build/
30 | !**/src/test/**/build/
31 |
32 | ### VS Code ###
33 | .vscode/
34 |
35 | ### maven ###
36 | mvnw
37 | mvnw.cmd
38 | .mvn
39 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # spring-Validation
2 | 彻底搞懂spring-Validation
3 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | org.springframework.boot
7 | spring-boot-starter-parent
8 | 2.2.0.RELEASE
9 |
10 |
11 | com.github.chentianming11
12 | spring-validation
13 | 0.0.1-SNAPSHOT
14 | spring-validation
15 | 彻底搞懂spring-validation
16 |
17 |
18 | 1.8
19 |
20 |
21 |
22 |
23 | org.projectlombok
24 | lombok
25 | 1.18.6
26 |
27 |
28 | com.github.lianjiatech
29 | retrofit-spring-boot-starter
30 | 2.2.1
31 |
32 |
33 | org.springframework.boot
34 | spring-boot-starter
35 |
36 |
37 |
38 | org.springframework.boot
39 | spring-boot-starter-test
40 | test
41 |
42 |
43 |
44 | org.springframework.boot
45 | spring-boot-starter-validation
46 |
47 |
48 |
49 | com.alibaba.csp
50 | sentinel-core
51 | 1.6.3
52 |
53 |
54 |
55 | org.springframework.boot
56 | spring-boot-starter-web
57 |
58 |
59 | com.github.xiaoymin
60 | knife4j-spring-boot-starter
61 |
62 | 3.0.2
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 | org.springframework.boot
71 | spring-boot-maven-plugin
72 |
73 |
74 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/src/main/java/com/github/chentianming11/spring/validation/SpringValidationApplication.java:
--------------------------------------------------------------------------------
1 | package com.github.chentianming11.spring.validation;
2 |
3 | import org.hibernate.validator.HibernateValidator;
4 | import org.springframework.boot.SpringApplication;
5 | import org.springframework.boot.autoconfigure.SpringBootApplication;
6 | import org.springframework.context.annotation.Bean;
7 |
8 | import javax.validation.Validation;
9 | import javax.validation.Validator;
10 | import javax.validation.ValidatorFactory;
11 |
12 | @SpringBootApplication
13 | public class SpringValidationApplication {
14 |
15 | // test代码 t
16 |
17 | public static void main(String[] args) {
18 | SpringApplication.run(SpringValidationApplication.class, args);
19 | }
20 |
21 |
22 | @Bean
23 | public Validator validator() {
24 | ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class)
25 | .configure()
26 | // 快速失败模式
27 | .failFast(true)
28 | .buildValidatorFactory();
29 | return validatorFactory.getValidator();
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/com/github/chentianming11/spring/validation/base/BusinessCode.java:
--------------------------------------------------------------------------------
1 | package com.github.chentianming11.spring.validation.base;
2 |
3 | /**
4 | * @author 陈添明
5 | * @date 2019/3/5
6 | */
7 | public enum BusinessCode implements ReturnCode {
8 |
9 |
10 | 成功(0, "success"),
11 | 未知系统错误(10000, "未知系统错误"),
12 | 缺少参数(10001, "缺少参数"),
13 | 参数类型不匹配(10002, "参数类型不匹配"),
14 | 文件上传错误(10003, "文件上传错误"),
15 | 参数校验失败(10004, "参数校验失败"),
16 | 未知业务失败(20000, "未知业务失败");
17 |
18 | /**
19 | * 业务编号
20 | */
21 | private int code;
22 |
23 | /**
24 | * 业务值
25 | */
26 | private String message;
27 |
28 | BusinessCode(int code, String message) {
29 | this.code = code;
30 | this.message = message;
31 | }
32 |
33 | /**
34 | * 获取返回编码
35 | *
36 | * @return code
37 | */
38 | @Override
39 | public int code() {
40 | return code;
41 | }
42 |
43 | /**
44 | * 获取返回描述信息
45 | *
46 | * @return message
47 | */
48 | @Override
49 | public String message() {
50 | return message;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/main/java/com/github/chentianming11/spring/validation/base/CommonExceptionHandler.java:
--------------------------------------------------------------------------------
1 | package com.github.chentianming11.spring.validation.base;
2 |
3 | import lombok.extern.slf4j.Slf4j;
4 | import org.springframework.beans.NotReadablePropertyException;
5 | import org.springframework.http.HttpStatus;
6 | import org.springframework.validation.BindingResult;
7 | import org.springframework.validation.FieldError;
8 | import org.springframework.web.bind.MethodArgumentNotValidException;
9 | import org.springframework.web.bind.annotation.ExceptionHandler;
10 | import org.springframework.web.bind.annotation.ResponseBody;
11 | import org.springframework.web.bind.annotation.ResponseStatus;
12 | import org.springframework.web.bind.annotation.RestControllerAdvice;
13 |
14 | import javax.validation.ConstraintViolationException;
15 |
16 | /**
17 | * @author 陈添明
18 | */
19 | @RestControllerAdvice
20 | @Slf4j
21 | public class CommonExceptionHandler {
22 |
23 | @ExceptionHandler({MethodArgumentNotValidException.class})
24 | @ResponseStatus(HttpStatus.OK)
25 | @ResponseBody
26 | public Result handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) {
27 | BindingResult bindingResult = ex.getBindingResult();
28 | StringBuilder sb = new StringBuilder("校验失败:");
29 | for (FieldError fieldError : bindingResult.getFieldErrors()) {
30 | sb.append(fieldError.getField()).append(":").append(fieldError.getDefaultMessage()).append(", ");
31 | }
32 | String msg = sb.toString();
33 | return Result.fail(BusinessCode.参数校验失败, msg);
34 | }
35 |
36 | @ExceptionHandler({ConstraintViolationException.class})
37 | @ResponseStatus(HttpStatus.OK)
38 | @ResponseBody
39 | public Result handleConstraintViolationException(ConstraintViolationException ex) {
40 | return Result.fail(BusinessCode.参数校验失败, ex.getMessage());
41 | }
42 |
43 | @ExceptionHandler({NotReadablePropertyException.class})
44 | @ResponseStatus(HttpStatus.OK)
45 | @ResponseBody
46 | public Result handleNotReadablePropertyException(NotReadablePropertyException ex) {
47 | return Result.fail(BusinessCode.参数校验失败, ex.getMessage());
48 | }
49 |
50 |
51 | @ExceptionHandler({Exception.class})
52 | @ResponseStatus(HttpStatus.OK)
53 | @ResponseBody
54 | public Result handleException(Exception ex) {
55 | log.error("未知系统错误", ex);
56 | return Result.fail(BusinessCode.未知系统错误, ex.getMessage());
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/main/java/com/github/chentianming11/spring/validation/base/EnvironmentConfig.java:
--------------------------------------------------------------------------------
1 | package com.github.chentianming11.spring.validation.base;
2 |
3 | import org.springframework.context.EnvironmentAware;
4 | import org.springframework.context.annotation.Configuration;
5 | import org.springframework.core.env.Environment;
6 |
7 | /**
8 | * @author 陈添明
9 | */
10 | @Configuration
11 | public class EnvironmentConfig implements EnvironmentAware {
12 | /**
13 | * Set the {@code Environment} that this component runs in.
14 | *
15 | * @param environment
16 | */
17 | @Override
18 | public void setEnvironment(Environment environment) {
19 | System.out.println(environment);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/com/github/chentianming11/spring/validation/base/Result.java:
--------------------------------------------------------------------------------
1 | package com.github.chentianming11.spring.validation.base;
2 |
3 | import lombok.Data;
4 | import lombok.experimental.Accessors;
5 |
6 | import java.io.Serializable;
7 |
8 | /**
9 | * @author 陈添明
10 | * @date 2019/3/5
11 | */
12 | @Data
13 | @Accessors(chain = true)
14 | public class Result implements Serializable {
15 |
16 | private static final long serialVersionUID = -504027247149928390L;
17 |
18 | private int code;
19 | private String msg;
20 | private String exceptionMsg;
21 | private T body;
22 |
23 | public static Result ok(T body) {
24 | return new Result<>()
25 | .setBody(body)
26 | .setCode(BusinessCode.成功.code())
27 | .setMsg(BusinessCode.成功.message());
28 | }
29 |
30 | public static Result ok() {
31 | return new Result<>()
32 | .setCode(BusinessCode.成功.code())
33 | .setMsg(BusinessCode.成功.message());
34 | }
35 |
36 | public static Result fail(ReturnCode returnCode) {
37 | return new Result<>()
38 | .setCode(returnCode.code())
39 | .setMsg(returnCode.message());
40 | }
41 |
42 | public static Result fail(ReturnCode returnCode, String exceptionMsg) {
43 | return new Result<>()
44 | .setCode(returnCode.code())
45 | .setMsg(returnCode.message())
46 | .setExceptionMsg(exceptionMsg);
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/main/java/com/github/chentianming11/spring/validation/base/ReturnCode.java:
--------------------------------------------------------------------------------
1 | package com.github.chentianming11.spring.validation.base;
2 |
3 | /**
4 | * 如果需要自定义错误编码,需要继承ReturnCode接口
5 | */
6 | public interface ReturnCode {
7 |
8 | /**
9 | * 获取返回编码
10 | * @return code
11 | */
12 | int code();
13 |
14 | /**
15 | * 获取返回描述信息
16 | * @return message
17 | */
18 | String message();
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/java/com/github/chentianming11/spring/validation/base/Swagger2Config.java:
--------------------------------------------------------------------------------
1 | //package com.github.chentianming11.spring.validation.base;
2 | //
3 | //import org.springframework.context.annotation.Bean;
4 | //import org.springframework.context.annotation.Configuration;
5 | //import springfox.documentation.builders.ApiInfoBuilder;
6 | //import springfox.documentation.builders.PathSelectors;
7 | //import springfox.documentation.builders.RequestHandlerSelectors;
8 | //import springfox.documentation.spi.DocumentationType;
9 | //import springfox.documentation.spring.web.plugins.Docket;
10 | //import springfox.documentation.swagger2.annotations.EnableSwagger2;
11 | //
12 | //@Configuration
13 | //@EnableSwagger2
14 | //public class Swagger2Config {
15 | //
16 | //
17 | // @Bean(value = "defaultApi2")
18 | // public Docket defaultApi2() {
19 | // Docket docket=new Docket(DocumentationType.SWAGGER_2)
20 | // .apiInfo(new ApiInfoBuilder()
21 | // .title("交易助手后台接口文档")
22 | // .description("# helicarrier RESTful APIs")
23 | // .termsOfServiceUrl("http://dora.shtest.ke.com/")
24 | // .version("1.0")
25 | // .build())
26 | // //分组名称
27 | // .select()
28 | // //这里指定Controller扫描包路径
29 | // .apis(RequestHandlerSelectors.basePackage("com.github.chentianming11.spring.validation"))
30 | // .paths(PathSelectors.any())
31 | // .build();
32 | // return docket;
33 | // }
34 | //}
--------------------------------------------------------------------------------
/src/main/java/com/github/chentianming11/spring/validation/base/Validation/EncryptId.java:
--------------------------------------------------------------------------------
1 | package com.github.chentianming11.spring.validation.base.Validation;
2 |
3 | import javax.validation.Constraint;
4 | import javax.validation.Payload;
5 | import java.lang.annotation.Documented;
6 | import java.lang.annotation.Retention;
7 | import java.lang.annotation.Target;
8 |
9 | import static java.lang.annotation.ElementType.*;
10 | import static java.lang.annotation.RetentionPolicy.RUNTIME;
11 |
12 | @Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER})
13 | @Retention(RUNTIME)
14 | @Documented
15 | @Constraint(validatedBy = {EncryptIdValidator.class})
16 | public @interface EncryptId {
17 |
18 | // 默认错误消息
19 | String message() default "加密id格式错误";
20 |
21 | // 分组
22 | Class>[] groups() default {};
23 |
24 | // 负载
25 | Class extends Payload>[] payload() default {};
26 | }
--------------------------------------------------------------------------------
/src/main/java/com/github/chentianming11/spring/validation/base/Validation/EncryptIdValidator.java:
--------------------------------------------------------------------------------
1 | package com.github.chentianming11.spring.validation.base.Validation;
2 |
3 | import javax.validation.ConstraintValidator;
4 | import javax.validation.ConstraintValidatorContext;
5 | import java.util.regex.Matcher;
6 | import java.util.regex.Pattern;
7 |
8 | public class EncryptIdValidator implements ConstraintValidator {
9 |
10 | private static final Pattern PATTERN = Pattern.compile("^[a-f\\d]{32,256}$");
11 |
12 | @Override
13 | public boolean isValid(String value, ConstraintValidatorContext context) {
14 | // 不为null才进行校验
15 | if (value != null) {
16 | Matcher matcher = PATTERN.matcher(value);
17 | return matcher.find();
18 | }
19 | return true;
20 | }
21 | }
--------------------------------------------------------------------------------
/src/main/java/com/github/chentianming11/spring/validation/base/Validation/ValidationList.java:
--------------------------------------------------------------------------------
1 | package com.github.chentianming11.spring.validation.base.Validation;
2 |
3 | import lombok.experimental.Delegate;
4 |
5 | import javax.validation.Valid;
6 | import java.util.ArrayList;
7 | import java.util.List;
8 |
9 | public class ValidationList implements List {
10 |
11 | @Delegate
12 | @Valid // 一定要加@Valid注解
13 | public List list = new ArrayList<>();
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/com/github/chentianming11/spring/validation/controller/DegradeController.java:
--------------------------------------------------------------------------------
1 | package com.github.chentianming11.spring.validation.controller;
2 |
3 | import com.github.chentianming11.spring.validation.base.Result;
4 | import com.github.chentianming11.spring.validation.http.HttpDegradeApi;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.web.bind.annotation.GetMapping;
7 | import org.springframework.web.bind.annotation.RequestMapping;
8 | import org.springframework.web.bind.annotation.RestController;
9 |
10 | import java.util.Random;
11 |
12 | /**
13 | * @author 陈添明
14 | */
15 | @RequestMapping("/api/degrade")
16 | @RestController
17 | public class DegradeController {
18 |
19 | @Autowired
20 | HttpDegradeApi httpDegradeApi;
21 |
22 |
23 | @GetMapping("/test")
24 | public Result test() throws InterruptedException {
25 | Random random = new Random(System.currentTimeMillis());
26 | int i = random.nextInt(1_000);
27 | Thread.sleep(i);
28 | return Result.ok(i);
29 | }
30 |
31 |
32 | @GetMapping("/test2")
33 | public Result test2() throws InterruptedException {
34 | Random random = new Random(System.currentTimeMillis());
35 | int i = random.nextInt(2_000);
36 | Thread.sleep(i);
37 | return Result.ok(i);
38 | }
39 |
40 | @GetMapping("/test3")
41 | public Result test3() throws InterruptedException {
42 | Random random = new Random(System.currentTimeMillis());
43 | int i = random.nextInt(3_000);
44 | Thread.sleep(i);
45 | return Result.ok(i);
46 | }
47 |
48 |
49 | @GetMapping("/test/execute")
50 | public Result testExecute() throws InterruptedException {
51 | Result test = httpDegradeApi.test();
52 | return Result.ok(test);
53 | }
54 |
55 | @GetMapping("/test2/execute")
56 | public Result test2Execute() throws InterruptedException {
57 | Result integerResult = httpDegradeApi.test2();
58 | return Result.ok(integerResult);
59 | }
60 |
61 | @GetMapping("/test3/execute")
62 | public Result test3Execute() throws InterruptedException {
63 | Result integerResult = httpDegradeApi.test3();
64 | return Result.ok(integerResult);
65 | }
66 |
67 |
68 |
69 | }
70 |
--------------------------------------------------------------------------------
/src/main/java/com/github/chentianming11/spring/validation/controller/PersonController.java:
--------------------------------------------------------------------------------
1 | package com.github.chentianming11.spring.validation.controller;
2 |
3 | import com.github.chentianming11.spring.validation.base.Result;
4 | import com.github.chentianming11.spring.validation.pojo.PersonVO;
5 | import com.github.chentianming11.spring.validation.pojo.SavePersonDTO;
6 | import com.github.chentianming11.spring.validation.pojo.UpdatePersonDTO;
7 | import io.swagger.annotations.Api;
8 | import io.swagger.annotations.ApiOperation;
9 | import io.swagger.annotations.ApiParam;
10 | import org.springframework.validation.annotation.Validated;
11 | import org.springframework.web.bind.annotation.*;
12 |
13 | import javax.validation.Valid;
14 | import javax.validation.constraints.*;
15 | import java.util.ArrayList;
16 | import java.util.List;
17 |
18 | /**
19 | * @author 陈添明
20 | */
21 | @RestController
22 | @RequestMapping("/api/person")
23 | @Validated
24 | @Api(tags = "Person管理")
25 | public class PersonController {
26 |
27 |
28 | @ApiOperation("保存用户")
29 | @PostMapping("savePerson")
30 | public Result savePerson(@RequestBody @Valid SavePersonDTO person) {
31 | PersonVO personVO = new PersonVO().setAge(10).setEmail("xxxxx").setId(1L).setName("哈哈");
32 | return Result.ok(personVO);
33 | }
34 |
35 | @ApiOperation("更新用户")
36 | @PostMapping("updatePerson")
37 | public Result updatePerson(@RequestBody @Valid UpdatePersonDTO person) {
38 | PersonVO personVO = new PersonVO().setAge(10).setEmail("xxxxx").setId(1L).setName("哈哈");
39 | return Result.ok(personVO);
40 | }
41 |
42 |
43 | @ApiOperation("查询person")
44 | @GetMapping("queryPerson")
45 | public Result> queryPerson(
46 | @ApiParam("用户id") @Min(1000) @Max(10000000) Long id,
47 | @ApiParam("姓名") @NotNull @Size(min = 2, max = 10) String name,
48 | @ApiParam("年龄") @NotNull @Max(200) Integer age,
49 | @ApiParam("邮箱") @Pattern(regexp = "^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$") String email) {
50 | List list = new ArrayList<>();
51 | list.add(new PersonVO().setAge(10).setEmail("xxxxx").setId(1L).setName("哈哈"));
52 | return Result.ok(list);
53 | }
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/src/main/java/com/github/chentianming11/spring/validation/controller/UserController.java:
--------------------------------------------------------------------------------
1 | package com.github.chentianming11.spring.validation.controller;
2 |
3 | import com.github.chentianming11.spring.validation.base.Result;
4 | import com.github.chentianming11.spring.validation.base.Validation.ValidationList;
5 | import com.github.chentianming11.spring.validation.http.HttpTestAPI;
6 | import com.github.chentianming11.spring.validation.pojo.dto.UserDTO;
7 | import io.swagger.annotations.Api;
8 | import io.swagger.annotations.ApiOperation;
9 | import io.swagger.annotations.ApiParam;
10 | import org.hibernate.validator.constraints.Length;
11 | import org.springframework.beans.factory.annotation.Autowired;
12 | import org.springframework.validation.annotation.Validated;
13 | import org.springframework.web.bind.annotation.*;
14 |
15 | import javax.validation.ConstraintViolation;
16 | import javax.validation.Valid;
17 | import javax.validation.constraints.Min;
18 | import javax.validation.constraints.NotNull;
19 | import java.util.Set;
20 |
21 | /**
22 | * @author 陈添明
23 | */
24 | @RequestMapping("/api/user")
25 | @RestController
26 | @Validated
27 | @Api("用户管理")
28 | public class UserController {
29 |
30 | @Autowired
31 | private javax.validation.Validator globalValidator;
32 |
33 | @Autowired
34 | private HttpTestAPI httpTestAPI;
35 |
36 | // 编程式校验
37 | @PostMapping("/saveWithCodingValidate")
38 | @ApiOperation("编程式校验保存")
39 | public Result saveWithCodingValidate(@RequestBody @Valid UserDTO userDTO) {
40 | Set> validate = globalValidator.validate(userDTO, UserDTO.Save.class);
41 | // 如果校验通过,validate为空;否则,validate包含未校验通过项
42 | if (validate.isEmpty()) {
43 | // 校验通过,才会执行业务逻辑处理
44 |
45 | } else {
46 | for (ConstraintViolation userDTOConstraintViolation : validate) {
47 | // 校验失败,做其它逻辑
48 | System.out.println(userDTOConstraintViolation);
49 | }
50 | }
51 | return Result.ok();
52 | }
53 |
54 | @PostMapping("/save")
55 | @ApiOperation("保存用户")
56 | public Result saveUser(@RequestBody @Validated(UserDTO.Save.class) UserDTO userDTO) {
57 | // 校验通过,才会执行业务逻辑处理
58 | return Result.ok();
59 | }
60 |
61 | @PostMapping("/saveList")
62 | @ApiOperation("批量保存")
63 | public Result saveList(@RequestBody @Validated(UserDTO.Save.class) ValidationList userList) {
64 | // 校验通过,才会执行业务逻辑处理
65 | return Result.ok();
66 | }
67 |
68 | @PostMapping("/update")
69 | @ApiOperation("更新用户信息")
70 | public Result updateUser(@RequestBody @Validated(UserDTO.Update.class) UserDTO userDTO) {
71 | // 校验通过,才会执行业务逻辑处理
72 | return Result.ok();
73 | }
74 |
75 |
76 | // 路径变量
77 | @GetMapping("{userId}")
78 | @ApiOperation("根据userId查询用户信息")
79 | public Result detail(@PathVariable("userId") @Min(10000000000000000L) @ApiParam("用户id") Long userId) {
80 | // 校验通过,才会执行业务逻辑处理
81 | UserDTO userDTO = new UserDTO();
82 | userDTO.setUserId(userId);
83 | userDTO.setAccount("11111111111111111");
84 | userDTO.setUserName("xixi");
85 | userDTO.setAccount("11111111111111111");
86 | return Result.ok(userDTO);
87 | }
88 |
89 | // 查询参数
90 | @GetMapping("getByAccount")
91 | @ApiOperation("根据account查询用户信息")
92 | public Result getByAccount(@Length(min = 6, max = 20) @NotNull @ApiParam("账号") String account) {
93 | // 校验通过,才会执行业务逻辑处理
94 | UserDTO userDTO = new UserDTO();
95 | userDTO.setUserId(10000000000000003L);
96 | userDTO.setAccount(account);
97 | userDTO.setUserName("xixi");
98 | userDTO.setAccount("11111111111111111");
99 | return Result.ok(userDTO);
100 | }
101 |
102 | @GetMapping("/httpTest")
103 | public Result httpTest() {
104 | Result account123 = httpTestAPI.getByAccount("account123");
105 | System.out.println(account123);
106 | return Result.ok(account123);
107 | }
108 |
109 | @GetMapping("/throw404Exception")
110 | public Result throw404Exception() {
111 | Result account123 = null;
112 | try {
113 | account123 = httpTestAPI.throw404Exception("account123");
114 | } catch (Throwable e) {
115 | while (true) {
116 | if (e != null) {
117 | System.out.println(e.getClass());
118 | e = e.getCause();
119 | }
120 | }
121 | }
122 | return Result.ok(account123);
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/src/main/java/com/github/chentianming11/spring/validation/http/HttpDegradeApi.java:
--------------------------------------------------------------------------------
1 | package com.github.chentianming11.spring.validation.http;
2 |
3 | import com.github.chentianming11.spring.validation.base.Result;
4 | import com.github.lianjiatech.retrofit.spring.boot.annotation.RetrofitClient;
5 | import com.github.lianjiatech.retrofit.spring.boot.degrade.Degrade;
6 | import retrofit2.http.GET;
7 |
8 | /**
9 | * @author 陈添明
10 | */
11 | @RetrofitClient(baseUrl = "http://localhost:8080/api/degrade", fallbackFactory = HttpDegradeFallbackFactory.class)
12 | @Degrade(count = 300, timeWindow = 3)
13 | public interface HttpDegradeApi {
14 |
15 |
16 | @GET("test")
17 | @Degrade(count = 500, timeWindow = 3)
18 | Result test();
19 |
20 | @GET("test2")
21 | @Degrade(count = 500, timeWindow = 3)
22 | Result test2();
23 |
24 | @GET("test3")
25 | Result test3();
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/com/github/chentianming11/spring/validation/http/HttpDegradeFallback.java:
--------------------------------------------------------------------------------
1 | package com.github.chentianming11.spring.validation.http;
2 |
3 | import com.github.chentianming11.spring.validation.base.Result;
4 | import lombok.extern.slf4j.Slf4j;
5 | import org.springframework.stereotype.Service;
6 |
7 | /**
8 | * @author 陈添明
9 | */
10 | @Slf4j
11 | @Service
12 | public class HttpDegradeFallback implements HttpDegradeApi {
13 |
14 |
15 | @Override
16 | public Result test() {
17 | Result fallback = new Result<>();
18 | fallback.setCode(100)
19 | .setMsg("fallback")
20 | .setBody(1000000);
21 | return fallback;
22 | }
23 |
24 | @Override
25 | public Result test2() {
26 | Result fallback = new Result<>();
27 | fallback.setCode(100)
28 | .setMsg("fallback")
29 | .setBody(1000000);
30 | return fallback;
31 | }
32 |
33 | @Override
34 | public Result test3() {
35 | Result fallback = new Result<>();
36 | fallback.setCode(100)
37 | .setMsg("fallback")
38 | .setBody(1000000);
39 | return fallback;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/java/com/github/chentianming11/spring/validation/http/HttpDegradeFallbackFactory.java:
--------------------------------------------------------------------------------
1 | package com.github.chentianming11.spring.validation.http;
2 |
3 | import com.github.chentianming11.spring.validation.base.Result;
4 | import com.github.lianjiatech.retrofit.spring.boot.degrade.FallbackFactory;
5 | import lombok.extern.slf4j.Slf4j;
6 | import org.springframework.stereotype.Service;
7 |
8 | /**
9 | * @author 陈添明
10 | */
11 | @Slf4j
12 | @Service
13 | public class HttpDegradeFallbackFactory implements FallbackFactory {
14 |
15 | /**
16 | * Returns an instance of the fallback appropriate for the given cause
17 | *
18 | * @param cause fallback cause
19 | * @return 实现了retrofit接口的实例。an instance that implements the retrofit interface.
20 | */
21 | @Override
22 | public HttpDegradeApi create(Throwable cause) {
23 |
24 | log.error("触发熔断了! ", cause.getMessage(), cause);
25 |
26 | return new HttpDegradeApi() {
27 | @Override
28 | public Result test() {
29 | Result fallback = new Result<>();
30 | fallback.setCode(100)
31 | .setMsg("fallback")
32 | .setBody(1000000);
33 | return fallback;
34 | }
35 |
36 | @Override
37 | public Result test2() {
38 | Result fallback = new Result<>();
39 | fallback.setCode(100)
40 | .setMsg("fallback")
41 | .setBody(1000000);
42 | return fallback;
43 | }
44 |
45 | @Override
46 | public Result test3() {
47 | Result fallback = new Result<>();
48 | fallback.setCode(100)
49 | .setMsg("fallback")
50 | .setBody(1000000);
51 | return fallback;
52 | }
53 | };
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/main/java/com/github/chentianming11/spring/validation/http/HttpTestAPI.java:
--------------------------------------------------------------------------------
1 | package com.github.chentianming11.spring.validation.http;
2 |
3 | import com.github.chentianming11.spring.validation.base.Result;
4 | import com.github.chentianming11.spring.validation.pojo.dto.UserDTO;
5 | import com.github.lianjiatech.retrofit.spring.boot.annotation.RetrofitClient;
6 | import retrofit2.http.GET;
7 | import retrofit2.http.Query;
8 |
9 | /**
10 | * @author 陈添明
11 | */
12 | @RetrofitClient(baseUrl = "http://localhost:8080/api/user")
13 | public interface HttpTestAPI {
14 |
15 | @GET("getByAccount")
16 | Result getByAccount(@Query("account") String account);
17 |
18 | @GET("getByAccount/notExist")
19 | Result throw404Exception(@Query("account") String account);
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/com/github/chentianming11/spring/validation/pojo/PersonVO.java:
--------------------------------------------------------------------------------
1 | package com.github.chentianming11.spring.validation.pojo;
2 |
3 | import io.swagger.annotations.ApiModel;
4 | import io.swagger.annotations.ApiModelProperty;
5 | import lombok.Data;
6 | import lombok.experimental.Accessors;
7 |
8 | /**
9 | * @author 陈添明
10 | */
11 |
12 | @Data
13 | @Accessors(chain = true)
14 | @ApiModel("用户VO类")
15 | public class PersonVO {
16 |
17 | @ApiModelProperty("用户id")
18 | private Long id;
19 |
20 | @ApiModelProperty("姓名")
21 | private String name;
22 |
23 | @ApiModelProperty("年龄")
24 | private Integer age;
25 |
26 | @ApiModelProperty("邮箱")
27 | private String email;
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/com/github/chentianming11/spring/validation/pojo/SavePersonDTO.java:
--------------------------------------------------------------------------------
1 | package com.github.chentianming11.spring.validation.pojo;
2 |
3 | import io.swagger.annotations.ApiModel;
4 | import io.swagger.annotations.ApiModelProperty;
5 | import lombok.Data;
6 | import lombok.experimental.Accessors;
7 |
8 | import javax.validation.constraints.Max;
9 | import javax.validation.constraints.NotNull;
10 | import javax.validation.constraints.Pattern;
11 | import javax.validation.constraints.Size;
12 |
13 | /**
14 | * @author 陈添明
15 | */
16 | @Data
17 | @Accessors(chain = true)
18 | @ApiModel("保存用户DTO类")
19 | public class SavePersonDTO {
20 |
21 | @ApiModelProperty("姓名")
22 | @NotNull
23 | @Size(min = 2, max = 10)
24 | private String name;
25 |
26 | @ApiModelProperty("年龄")
27 | @NotNull
28 | @Max(200)
29 | private Integer age;
30 |
31 | @ApiModelProperty("邮箱")
32 | @Pattern(regexp = "^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$")
33 | private String email;
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/com/github/chentianming11/spring/validation/pojo/UpdatePersonDTO.java:
--------------------------------------------------------------------------------
1 | package com.github.chentianming11.spring.validation.pojo;
2 |
3 | import io.swagger.annotations.ApiModel;
4 | import io.swagger.annotations.ApiModelProperty;
5 | import lombok.Data;
6 | import lombok.experimental.Accessors;
7 |
8 | import javax.validation.constraints.Max;
9 | import javax.validation.constraints.NotNull;
10 | import javax.validation.constraints.Pattern;
11 | import javax.validation.constraints.Size;
12 |
13 | /**
14 | * @author 陈添明
15 | */
16 | @Data
17 | @Accessors(chain = true)
18 | @ApiModel("更新用户DTO类")
19 | public class UpdatePersonDTO {
20 |
21 |
22 | @ApiModelProperty("用户id")
23 | @NotNull
24 | private Long id;
25 |
26 | @ApiModelProperty("姓名")
27 | @Size(min = 2, max = 10)
28 | private String name;
29 |
30 | @ApiModelProperty("年龄")
31 | @Max(200)
32 | private Integer age;
33 |
34 | @ApiModelProperty("邮箱")
35 | @Pattern(regexp = "^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$")
36 | private String email;
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/java/com/github/chentianming11/spring/validation/pojo/dto/UserDTO.java:
--------------------------------------------------------------------------------
1 | package com.github.chentianming11.spring.validation.pojo.dto;
2 |
3 | import io.swagger.annotations.ApiModel;
4 | import io.swagger.annotations.ApiModelProperty;
5 | import lombok.Data;
6 | import org.hibernate.validator.constraints.Length;
7 |
8 | import javax.validation.Valid;
9 | import javax.validation.constraints.Min;
10 | import javax.validation.constraints.NotNull;
11 |
12 | /**
13 | * @author 陈添明
14 | */
15 | @Data
16 | @ApiModel("用户实体类")
17 | public class UserDTO {
18 |
19 | @ApiModelProperty("用户id")
20 | @Min(value = 10000000000000000L, groups = Update.class)
21 | private Long userId;
22 |
23 | @ApiModelProperty("用户名")
24 | @NotNull(groups = {Save.class, Update.class})
25 | @Length(min = 2, max = 10, groups = {Save.class, Update.class})
26 | private String userName;
27 |
28 | @ApiModelProperty("账号")
29 | @NotNull(groups = {Save.class, Update.class})
30 | @Length(min = 6, max = 20, groups = {Save.class, Update.class})
31 | private String account;
32 |
33 | @ApiModelProperty("密码")
34 | @NotNull(groups = {Save.class, Update.class})
35 | @Length(min = 6, max = 20, groups = {Save.class, Update.class})
36 | private String password;
37 |
38 | @ApiModelProperty("工作")
39 | @NotNull(groups = {Save.class, Update.class})
40 | @Valid
41 | private Job job;
42 |
43 | @Data
44 | @ApiModel("工作实体类")
45 | public static class Job {
46 |
47 | @ApiModelProperty("工作id")
48 | @Min(value = 1, groups = Update.class)
49 | private Long jobId;
50 |
51 | @ApiModelProperty("工作名称")
52 | @NotNull(groups = {Save.class, Update.class})
53 | @Length(min = 2, max = 10, groups = {Save.class, Update.class})
54 | private String jobName;
55 |
56 | @ApiModelProperty("岗位")
57 | @NotNull(groups = {Save.class, Update.class})
58 | @Length(min = 2, max = 10, groups = {Save.class, Update.class})
59 | private String position;
60 | }
61 |
62 | /**
63 | * 保存的时候校验分组
64 | */
65 | public interface Save {
66 | }
67 |
68 | /**
69 | * 更新的时候校验分组
70 | */
71 | public interface Update {
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/src/main/resources/application-local.yml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | test:
5 | local: local
6 |
7 |
8 |
--------------------------------------------------------------------------------
/src/main/resources/application.yml:
--------------------------------------------------------------------------------
1 | retrofit:
2 | # \u542F\u7528\u65E5\u5FD7\u6253\u5370
3 | enable-log: true
4 | # \u8FDE\u63A5\u6C60\u914D\u7F6E
5 | pool:
6 | test1:
7 | max-idle-connections: 3
8 | keep-alive-second: 100
9 | test2:
10 | max-idle-connections: 5
11 | keep-alive-second: 50
12 | # \u7981\u7528void\u8FD4\u56DE\u503C\u7C7B\u578B
13 | disable-void-return-type: false
14 | # \u65E5\u5FD7\u6253\u5370\u62E6\u622A\u5668
15 | logging-interceptor: com.github.lianjiatech.retrofit.spring.boot.interceptor.DefaultLoggingInterceptor
16 | # \u8BF7\u6C42\u91CD\u8BD5\u62E6\u622A\u5668
17 | retry-interceptor: com.github.lianjiatech.retrofit.spring.boot.retry.DefaultRetryInterceptor
18 | # \u5168\u5C40\u8F6C\u6362\u5668\u5DE5\u5382
19 | global-converter-factories:
20 | - retrofit2.converter.jackson.JacksonConverterFactory
21 | # \u5168\u5C40\u8C03\u7528\u9002\u914D\u5668\u5DE5\u5382
22 | global-call-adapter-factories:
23 | - com.github.lianjiatech.retrofit.spring.boot.core.BodyCallAdapterFactory
24 | - com.github.lianjiatech.retrofit.spring.boot.core.ResponseCallAdapterFactory
25 | enable-degrade: true
26 | degrade-type: sentinel
27 | resource-name-parser: com.github.lianjiatech.retrofit.spring.boot.degrade.DefaultResourceNameParser
28 |
29 |
30 | #spring:
31 | # application:
32 | # name: jy-helicarrier-api
33 | # profiles:
34 | # active: local
--------------------------------------------------------------------------------
/src/test/java/com/github/chentianming11/spring/validation/DegradeTest.java:
--------------------------------------------------------------------------------
1 | package com.github.chentianming11.spring.validation;
2 |
3 | import okhttp3.OkHttpClient;
4 | import okhttp3.Request;
5 | import okhttp3.Response;
6 | import org.junit.Test;
7 |
8 | import java.io.IOException;
9 | import java.util.concurrent.ExecutorService;
10 | import java.util.concurrent.Executors;
11 |
12 | /**
13 | * @author 陈添明
14 | */
15 | public class DegradeTest {
16 |
17 |
18 | @Test
19 | public void test1() throws IOException, InterruptedException {
20 | OkHttpClient httpClient = new OkHttpClient.Builder()
21 | .build();
22 |
23 | Request request = new Request.Builder()
24 | .url("http://api-dora.shoff.ke.com/keApi/test/http")
25 | .build();
26 |
27 | ExecutorService executorService = Executors.newFixedThreadPool(100);
28 |
29 | executorService.execute(() -> {
30 | for (int i = 0; i < 50; i++) {
31 | Response response = null;
32 | try {
33 | response = httpClient.newCall(request).execute();
34 | } catch (IOException e) {
35 | e.printStackTrace();
36 | }
37 | String string = null;
38 | try {
39 | string = response.body().string();
40 | } catch (IOException e) {
41 | e.printStackTrace();
42 | }
43 | System.out.println(string);
44 | }
45 | });
46 |
47 | executorService.execute(() -> {
48 | for (int i = 0; i < 50; i++) {
49 | Response response = null;
50 | try {
51 | response = httpClient.newCall(request).execute();
52 | } catch (IOException e) {
53 | e.printStackTrace();
54 | }
55 | String string = null;
56 | try {
57 | string = response.body().string();
58 | } catch (IOException e) {
59 | e.printStackTrace();
60 | }
61 | System.out.println(string);
62 | }
63 | });
64 |
65 | executorService.execute(() -> {
66 | for (int i = 0; i < 50; i++) {
67 | Response response = null;
68 | try {
69 | response = httpClient.newCall(request).execute();
70 | } catch (IOException e) {
71 | e.printStackTrace();
72 | }
73 | String string = null;
74 | try {
75 | string = response.body().string();
76 | } catch (IOException e) {
77 | e.printStackTrace();
78 | }
79 | System.out.println(string);
80 | }
81 | });
82 |
83 | executorService.execute(() -> {
84 | for (int i = 0; i < 50; i++) {
85 | Response response = null;
86 | try {
87 | response = httpClient.newCall(request).execute();
88 | } catch (IOException e) {
89 | e.printStackTrace();
90 | }
91 | String string = null;
92 | try {
93 | string = response.body().string();
94 | } catch (IOException e) {
95 | e.printStackTrace();
96 | }
97 | System.out.println(string);
98 | }
99 | });
100 |
101 |
102 | executorService.execute(() -> {
103 | for (int i = 0; i < 50; i++) {
104 | Response response = null;
105 | try {
106 | response = httpClient.newCall(request).execute();
107 | } catch (IOException e) {
108 | e.printStackTrace();
109 | }
110 | String string = null;
111 | try {
112 | string = response.body().string();
113 | } catch (IOException e) {
114 | e.printStackTrace();
115 | }
116 | System.out.println(string);
117 | }
118 | });
119 |
120 |
121 | executorService.execute(() -> {
122 | for (int i = 0; i < 50; i++) {
123 | Response response = null;
124 | try {
125 | response = httpClient.newCall(request).execute();
126 | } catch (IOException e) {
127 | e.printStackTrace();
128 | }
129 | String string = null;
130 | try {
131 | string = response.body().string();
132 | } catch (IOException e) {
133 | e.printStackTrace();
134 | }
135 | System.out.println(string);
136 | }
137 | });
138 |
139 | executorService.execute(() -> {
140 | for (int i = 0; i < 50; i++) {
141 | Response response = null;
142 | try {
143 | response = httpClient.newCall(request).execute();
144 | } catch (IOException e) {
145 | e.printStackTrace();
146 | }
147 | String string = null;
148 | try {
149 | string = response.body().string();
150 | } catch (IOException e) {
151 | e.printStackTrace();
152 | }
153 | System.out.println(string);
154 | }
155 | });
156 |
157 | executorService.execute(() -> {
158 | for (int i = 0; i < 50; i++) {
159 | Response response = null;
160 | try {
161 | response = httpClient.newCall(request).execute();
162 | } catch (IOException e) {
163 | e.printStackTrace();
164 | }
165 | String string = null;
166 | try {
167 | string = response.body().string();
168 | } catch (IOException e) {
169 | e.printStackTrace();
170 | }
171 | System.out.println(string);
172 | }
173 | });
174 |
175 |
176 | executorService.execute(() -> {
177 | for (int i = 0; i < 50; i++) {
178 | Response response = null;
179 | try {
180 | response = httpClient.newCall(request).execute();
181 | } catch (IOException e) {
182 | e.printStackTrace();
183 | }
184 | String string = null;
185 | try {
186 | string = response.body().string();
187 | } catch (IOException e) {
188 | e.printStackTrace();
189 | }
190 | System.out.println(string);
191 | }
192 | });
193 |
194 |
195 | executorService.execute(() -> {
196 | for (int i = 0; i < 50; i++) {
197 | Response response = null;
198 | try {
199 | response = httpClient.newCall(request).execute();
200 | } catch (IOException e) {
201 | e.printStackTrace();
202 | }
203 | String string = null;
204 | try {
205 | string = response.body().string();
206 | } catch (IOException e) {
207 | e.printStackTrace();
208 | }
209 | System.out.println(string);
210 | }
211 | });
212 |
213 | executorService.execute(() -> {
214 | for (int i = 0; i < 50; i++) {
215 | Response response = null;
216 | try {
217 | response = httpClient.newCall(request).execute();
218 | } catch (IOException e) {
219 | e.printStackTrace();
220 | }
221 | String string = null;
222 | try {
223 | string = response.body().string();
224 | } catch (IOException e) {
225 | e.printStackTrace();
226 | }
227 | System.out.println(string);
228 | }
229 | });
230 |
231 |
232 |
233 |
234 | Thread.currentThread().join();
235 |
236 |
237 | }
238 | }
239 |
--------------------------------------------------------------------------------
/src/test/java/com/github/chentianming11/spring/validation/SpringValidationApplicationTests.java:
--------------------------------------------------------------------------------
1 | package com.github.chentianming11.spring.validation;
2 |
3 | import org.junit.Test;
4 | import org.junit.runner.RunWith;
5 | import org.springframework.boot.test.context.SpringBootTest;
6 | import org.springframework.test.context.junit4.SpringRunner;
7 |
8 | @RunWith(SpringRunner.class)
9 | @SpringBootTest
10 | public class SpringValidationApplicationTests {
11 |
12 | @Test
13 | public void contextLoads() {
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------