SpringBoot注解--05--注解@Valid

news2024/11/16 7:31:28

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 1 前言
    • 1.1 Bean Validation
    • 1.2 @Valid实际案例
    • 1.3 Spring 中的 @valid 注解
  • 2 @Valid 详解
    • 2.1 源码解析
    • 2.2 参数校验使用注解
    • 2.3 具体使用流程
        • ==POST 则可以以实体对象为参数,可以使用 @Valid 方式进行效验==。
        • ==如果效验通过,则进入业务逻辑,否则抛出异常,交由全局异常处理器进行处理==。
  • 3 @Valid 案例
    • 3.1 添加maven依赖(三种方式添加依赖)
    • 3.2 创建request实体类
    • 3.3 创建controller
    • 3.4 postman测试
    • 3.5 嵌套的实体类
        • ==在嵌套类的外层加上@Valid注解==,如下:
  • 4 异常处理
    • 4.1 MethodArgumentNotValidException
        • ==如果效验通过,则进入业务逻辑,否则抛出异常,交由全局异常处理器进行处理==。
        • ==MethodArgumentNotValidException==
    • 4.2 springboot项目中的异常处理


1 前言

  • 在我们日常开发中,数据校验的实现是一件比较痛苦的事情,繁琐且无趣,对于一般的业务而言,极少出现一些过于复杂的校验,常常都是非空,长度,最大最小值,正则,数据关联,定值等等。
  • 我在开发过程中为了减少我写这些代码的coding成本,由此认识了javax.validation包下的 @Valid 注解 和 Java的 Bean Validation 规范。

1.1 Bean Validation

在这里插入图片描述

1.2 @Valid实际案例

下面我们以新增一个员工为功能切入点,以常规写法为背景,慢慢烘托出 @Valid 注解用法详解。
那么,首先,我们会有一个员工对象 Employee,如下 :

/**
 * 员工对象
 * 
 * @author sunnyzyq
 * @since 2019/12/13
 */
public class Employee {
 
    /** 姓名 */
    public String name;
 
    /** 年龄 */
    public Integer age;
 
    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;
    }
 
}

然后 Cotroller 中会有一个对应都新增方法 add(),如下:


@Controller
public class TestController {
 
    @RequestMapping("/add")
    @ResponseBody
    public String add(Employee employee) {
        // TODO 保存到数据库
        return "新增员工成功";
    }
 
}

现在要求:员工的名称不能为空,且长度不能超过10个字符,那么我们以前的做法大致如下:在这里插入图片描述

除了名称外,我们规定年龄也是必填项,且范围在1到100岁,那么此时,我们需要增加对应判定代码如下:
在这里插入图片描述

那么问题来了,现在员工对象 Employee 就 2 个字段,我们就写了 10 多行的代码验证,要是有20个字段,岂不是要写 100多行代码?通常来说,当一个方法中的无效业务代码量过多时,往往代码设计有问题,当然这不是我们所想看到都结果。

1.3 Spring 中的 @valid 注解

如果你是 springboot 项目,那么可以不用引入了,已经引入了,他就存在于最核心的 web 开发包里面。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <version>2.0.5.RELEASE</version>
</dependency>

如果你不是 springboot 项目,那么引入下面依赖即可:

<dependency>
    <groupId>javax.validation</groupId>
    <artifactId>validation-api</artifactId>
    <version>1.1.0.Final</version>
</dependency>
 
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>5.4.1.Final</version>
</dependency>

那么针对上面情景,我们可以对我们的代码进行优化了。首先我们在 Employee 类的属性上打上如下注解:

package com.zyq.beans;
 
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
 
import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.constraints.Range;
 
/**
 * 员工对象
 * 
 * @author sunnyzyq
 * @since 2019/12/13
 */
public class Employee {
 
    /** 姓名 */
    @NotBlank(message = "请输入名称")
    @Length(message = "名称不能超过个 {max} 字符", max = 10)
    public String name;
 
    /** 年龄 */
    @NotNull(message = "请输入年龄")
    @Range(message = "年龄范围为 {min} 到 {max} 之间", min = 1, max = 100)
    public Integer age;
 
    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;
    }
 
}

然后再 Controller 对应方法上,对这个员工标上@Valid 注解,表示我们对这个对象属性需要进行验证
在这里插入图片描述

2 @Valid 详解

2.1 源码解析

通过源码可以看出:

@Valid注解可以作用于:方法、属性(包括枚举中的常量)、构造函数、方法的形参上。

@Target({ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Valid {
}

所属的包

import javax.validation.Valid;

2.2 参数校验使用注解

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.3 具体使用流程

  1. 实体类中添加 @Valid 相关注解
  2. 接口类中添加 @Valid 注解
  3. 全局异常处理类中处理 @Valid 抛出的异常

整个过程如下图所示,用户访问接口,然后进行参数效验,因为 @Valid 不支持平面的参数效验(直接写在参数中字段的效验)所以基于 GET 请求的参数还是按照原先方式进行效验,

POST 则可以以实体对象为参数,可以使用 @Valid 方式进行效验
如果效验通过,则进入业务逻辑,否则抛出异常,交由全局异常处理器进行处理

在这里插入图片描述

3 @Valid 案例

3.1 添加maven依赖(三种方式添加依赖)

			<!--第一种:valid依赖-->
		<dependency>
			<groupId>javax.validation</groupId>
			<artifactId>validation-api</artifactId>
			<version>版本号</version>
		</dependency>

		<!--		第二种:集成于web依赖中(注意版本号)-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
			<version>2.0.5.RELEASE</version>
		</dependency>

		<!--		第三种:springboot的validation-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-validation</artifactId>
		</dependency>

3.2 创建request实体类

import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.Max;
import javax.validation.constraints.NotBlank;

@Data
@NoArgsConstructor
public class TestRequest {

    @NotBlank(message = "name不为空")
    private String name;

    @Length(max = 3,message = "address最大长度是3")
    private String address;

    @Max(value = 5,message = "reqNo最大值是5")
    private String reqNo;

}

3.3 创建controller

@RestController
public class ValidTestController {

    @RequestMapping("/valid/test")
    public void test(@Valid @RequestBody TestRequest request){
        System.out.println(request);
    }

3.4 postman测试

在这里插入图片描述

postman返回结果:

{
    "timestamp": "2022-11-12T09:54:24.202+00:00",
    "status": 400,
    "error": "Bad Request",
    "trace": "org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument [0] in public void com.example.controller.ValidTestController.test(com.example.domain.TestRequest) with 3 errors: [Field error in object 'testRequest' on field 'name': rejected value []; codes [NotBlank.testRequest.name,NotBlank.name,NotBlank.java.lang.String,NotBlank]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [testRequest.name,name]; arguments []; default message [name]]; default message [name不为空]] [Field error in object 'testRequest' on field 'reqNo': rejected value [8]; codes [Max.testRequest.reqNo,Max.reqNo,Max.java.lang.String,Max]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [testRequest.reqNo,reqNo]; arguments []; default message [reqNo],5]; default message [reqNo最大值是5]] [Field error in object 'testRequest' on field 'address': rejected value [gtyjh]; codes [Length.testRequest.address,Length.address,Length.java.lang.String,Length]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [testRequest.address,address]; arguments []; default message [address],3,0]; default message [address最大长度是3]] \r\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.resolveArgument(RequestResponseBodyMethodProcessor.java:141)\r\n\tat org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:122)\r\n\tat org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:179)\r\n\tat org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:146)\r\n\tat org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117)\r\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)\r\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)\r\n\tat org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)\r\n\tat org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1071)\r\n\tat org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:964)\r\n\tat org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)\r\n\tat org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)\r\n\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:681)\r\n\tat org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)\r\n\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:764)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\r\n\tat org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\r\n\tat org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)\r\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\r\n\tat org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)\r\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\r\n\tat org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)\r\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\r\n\tat org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197)\r\n\tat org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)\r\n\tat org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)\r\n\tat org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135)\r\n\tat org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)\r\n\tat org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)\r\n\tat org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:360)\r\n\tat org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399)\r\n\tat org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)\r\n\tat org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:890)\r\n\tat org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1789)\r\n\tat org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)\r\n\tat org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)\r\n\tat org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)\r\n\tat org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)\r\n\tat java.lang.Thread.run(Thread.java:748)\r\n",
    "message": "Validation failed for object='testRequest'. Error count: 3",
    "errors": [
        {
            "codes": [
                "NotBlank.testRequest.name",
                "NotBlank.name",
                "NotBlank.java.lang.String",
                "NotBlank"
            ],
            "arguments": [
                {
                    "codes": [
                        "testRequest.name",
                        "name"
                    ],
                    "arguments": null,
                    "defaultMessage": "name",
                    "code": "name"
                }
            ],
            "defaultMessage": "name不为空",
            "objectName": "testRequest",
            "field": "name",
            "rejectedValue": "",
            "bindingFailure": false,
            "code": "NotBlank"
        },
        {
            "codes": [
                "Max.testRequest.reqNo",
                "Max.reqNo",
                "Max.java.lang.String",
                "Max"
            ],
            "arguments": [
                {
                    "codes": [
                        "testRequest.reqNo",
                        "reqNo"
                    ],
                    "arguments": null,
                    "defaultMessage": "reqNo",
                    "code": "reqNo"
                },
                5
            ],
            "defaultMessage": "reqNo最大值是5",
            "objectName": "testRequest",
            "field": "reqNo",
            "rejectedValue": "8",
            "bindingFailure": false,
            "code": "Max"
        },
        {
            "codes": [
                "Length.testRequest.address",
                "Length.address",
                "Length.java.lang.String",
                "Length"
            ],
            "arguments": [
                {
                    "codes": [
                        "testRequest.address",
                        "address"
                    ],
                    "arguments": null,
                    "defaultMessage": "address",
                    "code": "address"
                },
                3,
                0
            ],
            "defaultMessage": "address最大长度是3",
            "objectName": "testRequest",
            "field": "address",
            "rejectedValue": "gtyjh",
            "bindingFailure": false,
            "code": "Length"
        }
    ],
    "path": "/valid/test"
}

3.5 嵌套的实体类

从后端返回给postman的结果可以看出,三个字段的校验都已经实现。但是,特别情况,RequestBody可能是嵌套的实体,这个时候,对于嵌套的实体类来说,嵌套必须加 @Valid,如果只在字段上添加校验注解嵌套中的验证不生效。

如果只在嵌套类字段上加上校验注解,如下:

import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.Max;
import javax.validation.constraints.NotBlank;

@Data
@NoArgsConstructor
public class TestRequest {

    @NotBlank(message = "name不为空")
    private String name;

    @Length(max = 3, message = "address最大长度是3")
    private String address;

    @Max(value = 5, message = "reqNo最大值是5")
    private String reqNo;

    private TestRequestInner inner;

    @Data
    @NoArgsConstructor
    public static class TestRequestInner {
        @Length(max = 3, message = "最大长度是3")
        private String sonName;

        private Integer sonAge;

        private String schoolNo;
    }
}

在这里插入图片描述
在这里插入图片描述

在嵌套类的外层加上@Valid注解,如下:
@Data
@NoArgsConstructor
public class TestRequest {

    @NotBlank(message = "name不为空")
    private String name;

    @Length(max = 3, message = "address最大长度是3")
    private String address;

    @Max(value = 5, message = "reqNo最大值是5")
    private String reqNo;

    @Valid
    private TestRequestInner inner;
    
//   即使放在list集合里面仍然是需要加上 @Valid 注解
//    @Valid
//    private List<TestRequestInner> inner;

    @Data
    @NoArgsConstructor
    public static class TestRequestInner {
        @Length(max = 3, message = "最大长度是3")
        private String sonName;

        private Integer sonAge;

        private String schoolNo;
    }
}

在这里插入图片描述

4 异常处理

4.1 MethodArgumentNotValidException

如果效验通过,则进入业务逻辑,否则抛出异常,交由全局异常处理器进行处理

刚才的测试我们看到,校验注解全部生效,但是所有的异常全部抛出给postman,从控制台可以看出:
在这里插入图片描述
代码如下:

实体类如上不变,controller接口方法改为返回string:

 @RequestMapping("/valid/test")
    public String test(@Valid @RequestBody TestRequest request){
        System.out.println(request);
        return "success";
    }

异常处理类:

我们可以根据上图抛出的异常结构,去get我们想要获得的内容。

MethodArgumentNotValidException
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.util.List;

@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
    /**
     * 自定义验证异常
     * MethodArgumentNotValidException 方法参数无效异常
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST) //设置状态码为 400
    @ExceptionHandler({MethodArgumentNotValidException.class})
    public String paramExceptionHandler(MethodArgumentNotValidException e) {
        BindingResult exceptions = e.getBindingResult();
// 判断异常中是否有错误信息,如果存在就使用异常中的消息,否则使用默认消息
        if (exceptions.hasErrors()) {
            List errors = exceptions.getAllErrors();
            if (!errors.isEmpty()) {
// 这里列出了全部错误参数,按正常逻辑,只需要第一条错误即可
                FieldError fieldError = (FieldError) errors.get(0);
                return fieldError.getDefaultMessage();
            }
        }
        return "请求参数错误";
    }
}

在这里插入图片描述

4.2 springboot项目中的异常处理

上述的异常处理只是一个简单的string返回,但是在实际项目中,返回结构是固定的,下面对于固定的返回结构,做异常处理。

(1)request实体类

import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.validator.constraints.Length;

import javax.validation.Valid;
import javax.validation.constraints.Max;
import javax.validation.constraints.NotBlank;
import java.util.List;

@Data
@NoArgsConstructor
public class TestRequest {

    @NotBlank(message = "name不为空")
    private String name;

    @Length(max = 3, message = "address最大长度是3")
    private String address;

    @Max(value = 5, message = "reqNo最大值是5")
    private String reqNo;

    @Valid
    private List<TestRequestInner> inner;

    @Data
    @NoArgsConstructor
    public static class TestRequestInner {
        @Length(max = 3, message = "最大长度是3")
        private String sonName;

        private Integer sonAge;

        @NotBlank(message = "schoolNo不空")
        private String schoolNo;
    }
}

(2)结果返回实体类

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;

@Data
@NoArgsConstructor
@Builder
@AllArgsConstructor
public class ResponseResult {

    private List<ProvideInfo> provideInfos;

    @Data
    @NoArgsConstructor
    @Builder
    @AllArgsConstructor
    public static class ProvideInfo {
        private String code;
        private String detail;
    }
}

(3)controller接口方法

import com.example.domain.ResponseResult;
import com.example.domain.TestRequest;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;

@RestController
public class ValidTestController {

    @RequestMapping("/valid/test")
    public ResponseEntity<ResponseResult> test(@Valid @RequestBody TestRequest request) {
        System.out.println(request);
        return null;
    }
}

(4)postman测试
在这里插入图片描述

(5)全局异常处理类各种形式
对于全局异常类的处理,涉及到拦截器相关内容,这里不做多说。全局异常类的处理方式有很多种:
方式一:

// Enum枚举类
public enum CodeEnum {
// 根据自己的项目需求更改状态码,这里只是一个示范
    UNKNOW_EXCEPTION(10000,"系统未知错误"),
    VALID_EXCETIPON(10001,"参数格式校验错误");
    private int code;
    private String msg;
    CodeEnum(int code, String msg){
        this.code = code;
        this.msg = msg;
    }

    public int getCode() {
        return code;
    }

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

    public String getMsg() {
        return msg;
    }

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


//异常处理类
@Slf4j
@RestControllerAdvice("com.cbj.db_work.controller") //表明需要处理异常的范围
public class GlobalExceptionHandler {

    @ExceptionHandler(value = MethodArgumentNotValidException.class) // 参数异常抛出的异常类型为MethodArgumentNotValidException,这里捕获这个异常
    // R为统一返回的处理类
    public R validExceptionHandler(MethodArgumentNotValidException e){
        System.out.println("数据异常处理");
        log.error("数据校验出现问题,异常类型:{}",e.getMessage(),e.getClass());
        BindingResult bindingResult = e.getBindingResult();
        Map<String,String> map = new HashMap<>();
        bindingResult.getFieldErrors().forEach((item)->{
            String message = item.getDefaultMessage();
            // 获取错误的属性字段名
            String field = item.getField();
            map.put(field,message);
        });
        return R.error().code(CodeEnum.VALID_EXCETIPON.getCode()).message(CodeEnum.VALID_EXCETIPON.getMsg()).data("errorData",map);
    }
    
}

方式二:

@ControllerAdvice
@RestControllerAdvice
@Slf4j
public class ValidExceptionHandler extends GlobalExceptionHandler {

    // GET请求参数异常处理
    @ExceptionHandler(value = ConstraintViolationException.class)
    public Result<Object> constraintViolationExceptionHandler(ConstraintViolationException e) {
        StringBuilder msg = new StringBuilder();
        Set<ConstraintViolation<?>> constraintViolations = e.getConstraintViolations();
        for (ConstraintViolation<?> constraintViolation : constraintViolations) {
            String message = constraintViolation.getMessage();
            msg.append(message).append(";");
        }
        return ResultResponse.getFailResult(ResultCode.BODY_NOT_MATCH.getResultCode(), msg.toString());
    }

    @ExceptionHandler(ArithmeticException.class)
    public Result<Object> arithmeticExceptionHandler(ArithmeticException e) {
        e.printStackTrace();
        return ResultResponse.getFailResult(ResultCode.NOT_FOUND.getResultCode(), "算术异常!"+e.getMessage());
    }

    // POST请求参数异常处理
    @ExceptionHandler(BindException.class)
    public Result<Object> bindExceptionHandler(BindException e) {
        FieldError fieldError = e.getBindingResult().getFieldError();
        String msg;
        if (Objects.isNull(fieldError)) {
            msg = "POST请求参数异常:" + JSON.toJSONString(e.getBindingResult());
            log.info(msg);
        } else {
            msg = fieldError.getDefaultMessage();
        }
        return ResultResponse.getFailResult(ResultCode.BODY_NOT_MATCH.getResultCode(), msg);
    }

}

特别的,get请求校验:

@RestController
@RequestMapping(value = "/test")
@Slf4j
//@ApiIgnore
@Validated
public class TestController {

    @GetMapping(value = "/test")
    public Result<Object> test(@NotNull(message = "name必传")
                                   @NotBlank(message = "name格式错误")String name) {
        return ResultResponse.getSuccessResult("hello: " + name);
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1430501.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

再谈Redis三种集群模式:主从模式、哨兵模式和Cluster模式

总结经验 redis主从:可实现高并发(读),典型部署方案:一主二从 redis哨兵:可实现高可用,典型部署方案:一主二从三哨兵 redis集群:可同时支持高可用(读与写)、高并发,典型部署方案:三主三从 一、概述 Redis 支持三种集群模式,分别为主从模式、哨兵模式和Cluster模式。…

Java并发基础:CountDownLatch全面解析!

内容概要 CountDownLatch的优点在于能够简洁高效地协调多个线程的执行顺序&#xff0c;确保一组线程都完成后才触发其他线程的执行&#xff0c;适用于资源加载、任务初始化等场景。它提供了清晰的等待/通知机制&#xff0c;易于理解和使用&#xff0c;是提升多线程程序性能和可…

ChatGPT prompt概述

ChatGPT prompt概述 2022年11月30日&#xff0c;由人工智能实验室Open AI发布的对话式大型语言模型ChatGPT一夜爆火。凭借其强大的文字处理和人机交互能力迅速成为炙手可热的新一代人工智能产品。ChatGPT号称史上最强大的人工智能&#xff0c;它通过学习和理解人类语言与我们对…

玩具取名

看到长度是\(200\)&#xff0c;想到区间DP 但在这里说一下&#xff0c;设\(f[i][j]\)表示前\(i\)个字符&#xff0c;转换后以\(j\)结尾的最短长度是推不走的&#xff0c;因为原来的字符串的第\(i\)个字符合并之后产生的新字符有可能继续合并&#xff0c;这是有问题的

【成品论文57页】2024美赛F题成品论文57页+每一小问配套代码数据

基于数据预测下的减少非法野生动物贸易研究 近年来&#xff0c;非法野生动物贸易每年涉及的金额高达 265 亿美元&#xff0c;被认为是全球第四大 非法贸易。本文基于收集的数据&#xff0c; 对非法野生动物贸易进行研究。 问题一&#xff0c;为了确定五年项目的研究对象我们利用…

PXIe-5842第三代PXI矢量信号收发器简介

内容 简介​PXIe-5842 VST的主要特性PXI VST软件工具PXI VST应用结论下一步 简介 NI于2012年引入了矢量信号收发器(VST)的概念。VST将RF信号发生器、RF信号分析仪和功能强大的FPGA集成在单个PXI模块上。PXIe-5842 VST是首款提供30 MHz到26.5 GHz连续频率覆盖范围的VST。PXIe…

百分点科技:《数据科学技术: 文本分析和知识图谱》

科技进步带来的便利已经渗透到工作生活的方方面面&#xff0c;ChatGPT的出现更是掀起了新一波的智能化浪潮&#xff0c;推动更多智能应用的涌现。这背后离不开一个朴素的逻辑&#xff0c;即对数据的收集、治理、建模、分析和应用&#xff0c;这便是数据科学所重点研究的对象——…

Blender 与 3ds Max | 面对面的直接较量(2024)

Blender和3ds Max&#xff0c;哪个动画软件更好&#xff1f;作为一个从事动画领域十年的专业人士&#xff0c;Mark McPherson提供了八条最新建议&#xff0c;帮助你了解哪个软件更适合满足你的3D动画需求。 1.建模 获胜者&#xff1a;3ds Max。3ds Max的建模机制已经被证明是…

Leetcode刷题笔记题解(C++):36. 有效的数独

思路一&#xff1a;暴力破解&#xff0c;两个二维数组记录行、列对应的数字出现的次数&#xff0c;比如rows[i][index]表示的数字index在i行出现的次数&#xff0c;三维数组记录每个块中对应数字出现的次数&#xff0c;比如boxes[i/3][j/3][index]表示的数字index在[i/3][j/3]个…

031 递归

何为递归 示例 public static void main(String[] args) {System.out.println(fn(5)); }static int fn(int a){return a 1 ? 1 : a * fn(a - 1); }

conda虚拟环境基础

【一文搞定最新版Anaconda】Win11 安装 Anaconda&#xff08;2023.9&#xff09;详解&#xff08;不删除旧版情况下下载、安装、注册、登录、设置环境变量、迁移旧环境、配置修改换源等&#xff09;连接Pycharm_win11安装anaconda-CSDN博客 conda命令大全&#xff08;create/in…

基于大数据的淘宝电子产品数据分析的设计与实现

&#xff08;1&#xff09;本次针对开发设计系统并设置了相关的实施方案&#xff0c;利用完整的软件开发流程进行分析&#xff0c;完成了设置不同用户的操作权限和相关功能模块的开发&#xff0c;最后对系统进行测试。 &#xff08;2&#xff09;框架可以帮助程序开发者快速构建…

【Java程序设计】【C00195】基于SSM的影视创作论坛管理系统(论文+PPT)

基于SSM的影视创作论坛管理系统&#xff08;论文PPT&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于ssm的影视创作论坛 本系统分为前台系统、后台管理员和后台会员3个功能模块。 前台系统&#xff1a;当游客打开系统的网址后&#xff0c;首先看…

2024美赛B题Searching for Submersibles原创论文完整版

Searching for Submersibles搜索潜水器 2024美赛B题Searching for Submersibles原创论文&#xff08;共38页&#xff09;部分内容&#xff0c;其余见文末&#xff1a; 整体框架&#xff1a; 1.1 问题背景与问题重述 海上游轮迷你潜水艇公司&#xff08;MCMS&#xff09;&…

前端学习笔记 | HTML5+CSS3静态网页制作的技巧(持续更新)

注&#xff1a;本文的css样式均使用less写法 1、字体居中 &#xff08;1&#xff09;先text-align:center;行内元素水平居中 &#xff08;2&#xff09;再line-heigh:(盒子高度);行内元素垂直居中 text-align: center;line-height: ( 30 / vw ); 2、盒子居中 情景1&#…

Vue引入Axios

1.命令安装axios和vue-axios npm install axios --save npm install vue-axios --save 2.package.json查看版本 3.在main.js中引用 import axios from axios; import VueAxios from vue-axios; Vue.use(VueAxios,axios) 4.如何使用 &#xff08;初始化方法&#xff09; 将下列代…

《统计学习方法:李航》笔记 从原理到实现(基于python)-- 第6章 逻辑斯谛回归与最大熵模型(1)6.1 逻辑斯谛回归模型

文章目录 第6章 逻辑斯谛回归与最大熵模型6.1 逻辑斯谛回归模型6.1.1 逻辑斯谛分布6.1.2 二项逻辑斯谛回归模型6.1.3 模型参数估计6.1.4 多项逻辑斯谛回归 《统计学习方法&#xff1a;李航》笔记 从原理到实现&#xff08;基于python&#xff09;-- 第3章 k邻近邻法 《统计学习…

Spring 事务原理总结三

今天这篇文章&#xff0c;我想梳理一下Spring事务用到的几个核心组件。这些核心组件是我们理解Spring事务原理的基础。通过它们我们可以体会学习一下Spring设计者设计Spring事务时的基本思路。这些组件是&#xff1a;TransactionInfo、TransactionStatus、TransactionManager、…

【Chrono Engine学习总结】2-可视化

由于Chrono的官方教程在一些细节方面解释的并不清楚&#xff0c;自己做了一些尝试&#xff0c;做学习总结。 0、基本概念 类型说明&#xff1a; Chrono的可视化包括两块&#xff1a;实时可视化&#xff0c;以及离线/后处理可视化。 其中&#xff0c;实时可视化&#xff0c;又…

字节测试岗3面都过了,最后因为这个被刷。。。

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 点击文末小卡片 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 说在前面 面试时最好不要虚报工资。本来字节跳动是很想去的&#xff0c;几轮面试也通过了&…