springboot参数校验结合全局统一异常处理

在进行练习之前,建议先配置好Swagger,测试更方便。

一、参数校验
1.引入依赖
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
2.常用注解
  • @NotNull 限制传入的值不为null。作用在int,Integer等数值类型上时,在限制不为null的同时也不能为空字符串。作用在String上时,限制不为null但是可以为空字符串。作用在类上时,限制不为null。
  • @NotEmpty 作用于String类型,限制不能为null,且长度不为0,可以是空格字符串。
  • @NotBlank 作用于String类型,限制不能为null,且去掉空格,即trim之后,长度不为0。
  • @Max 作用于数值类型,限制最大值(包含该最大值)
  • @Min 作用于数值类型,限制最小值(包含该最小值)
  • @Email 作用于String类型,验证是否符合email格式
3.DTO层代码使用以上注解进行限制
@Data
public class AddUsersDTO implements Serializable {

    @NotBlank(message = "用户名不能为空")
    private String userName;

    @NotBlank(message = "密码不能为空")
    private String passWord;

    @NotBlank(message = "性别不能为空")
    private String user_sex;

    @NotBlank(message = "昵称不能为空")
    private String nick_name;

    @NotNull(message = "年龄不能为空")
    @Min(value = 0, message = "年龄不能小于 0")
    @Max(value = 200, message = "年龄不能大于 200")
    private Integer age;
}
3.Controller层代码使用@Validated注解进行参数校验
@RestController
@Slf4j
@RequestMapping("/users")
@Api(tags = {"用户管理"})
public class UsersController {

    @Autowired
    private UsersService usersService;

    @PostMapping("/add")
    @ApiOperation("添加用户")
    public ResponseUtil addUesrs(
            @RequestBody @Validated AddUsersDTO addUsersDTO) {
        return usersService.addUsers(addUsersDTO);
    }
}
4.通过Swagger或者postman进行验证

测试数据:将昵称设置为“ ”空格字符串

{
  "age": 0,
  "nick_name": "    ",
  "passWord": "string",
  "userName": "string",
  "user_sex": "string"
}

返回的数据:

{
  "timestamp": "2020-05-21T11:39:07.655+0000",
  "status": 400,
  "error": "Bad Request",
  "errors": [
    {
      "codes": [
        "NotBlank.addUsersDTO.nick_name",
        "NotBlank.nick_name",
        "NotBlank.java.lang.String",
        "NotBlank"
      ],
      "arguments": [
        {
          "codes": [
            "addUsersDTO.nick_name",
            "nick_name"
          ],
          "arguments": null,
          "defaultMessage": "nick_name",
          "code": "nick_name"
        }
      ],
      "defaultMessage": "昵称不能为空",
      "objectName": "addUsersDTO",
      "field": "nick_name",
      "rejectedValue": "  ",
      "bindingFailure": false,
      "code": "NotBlank"
    }
  ],
  "message": "Validation failed for object='addUsersDTO'. Error count: 1",
  "trace": "org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument [0] in public com.xl.exceptiondemo.utils.ResponseUtil com.xl.exceptiondemo.controller.UsersController.addUesrs(com.xl.exceptiondemo.model.AddUsersDTO): [Field error in object 'addUsersDTO' on field 'nick_name': rejected value [  ]; codes [NotBlank.addUsersDTO.nick_name,NotBlank.nick_name,NotBlank.java.lang.String,NotBlank]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [addUsersDTO.nick_name,nick_name]; arguments []; default message [nick_name]]; default message [昵称不能为空]] \n\tat org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.resolveArgument(RequestResponseBodyMethodProcessor.java:139)\n\tat org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:121)\n\tat org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:167)\n\tat org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:134)\n\tat org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106)\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:888)\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:793)\n\tat org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)\n\tat org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)\n\tat org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)\n\tat org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)\n\tat org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)\n\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:660)\n\tat org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)\n\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:741)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\n\tat org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\n\tat org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\n\tat org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\n\tat org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\n\tat org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)\n\tat org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)\n\tat org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:526)\n\tat org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)\n\tat org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)\n\tat org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)\n\tat org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)\n\tat org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408)\n\tat org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)\n\tat org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:861)\n\tat org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1579)\n\tat org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)\n\tat java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)\n\tat java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)\n\tat org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)\n\tat java.lang.Thread.run(Thread.java:748)\n",
  "path": "/users/add"
}

我们看到,这样我们做前后端分离就很不友好,其实我们只需要其中的“昵称不能为空"这条信息就够了,所以我们要进行统一异常处理,返回我们想要的结果。

二、统一异常处理
1.构造响应实体
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ResponseUtil<T> implements Serializable {

    // 响应数据
    private T data;
    // 响应状态码
    private String code;
    // 响应信息
    private String msg;

    public static<T> ResponseUtil<T> succeed(T data, String code, String msg) {
        return new ResponseUtil(data, code, msg);
    }

    public static<T> ResponseUtil<T> failed(T data, String code, String msg) {
        return new ResponseUtil(data, code, msg);
    }
}
2.自定义响应状态码以及响应信息
public interface CommonContants {
    /**
     * 成功响应的 code 以及 msg
     */
    String SUCCESS = "200";
    String SUCCESS_MSG = "SUCCESS";

    /**
     * 失败响应的 code 以及 msg
     */
    String ARGS_ERROR = "E000001";
    String ARGS_ERROR_MSG = "参数错误";
    String SERVER_ERROR = "E000002";
    String SERVER_ERROR_MSG = "服务器异常";
    String ERROR = "E999999";
    String ERROR_MSG = "未知异常";
}
3.编写全局统一异常处理类,使用@ControllerAdvice注解

通过@Validated注解进行参数校验,如果不符合规则,就会抛出MethodArgumentNotValidException异常,所以我们要对MethodArgumentNotValidException异常进行处理。

@ResponseBody // 记得添加此注解,以json格式返回
@ControllerAdvice
public class MyExceptionAdvice {

    /**
     * 参数校验异常统一处理
     * 返回状态码:200
     */
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseUtil handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {

        return ResponseUtil.failed(null, CommonContants.ARGS_ERROR,
                e.getBindingResult().getAllErrors().get(0).getDefaultMessage());
    }

    /**
     * 所有异常统一处理
     * 返回状态码:500
     */
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(Exception.class)
    public ResponseUtil handleException(Exception e) {

        return ResponseUtil.failed(null, CommonContants.SERVER_ERROR,
                CommonContants.SERVER_ERROR_MSG);
    }
}
4.验证

测试数据:将昵称设置为“ ”空格字符串

{
  "age": 0,
  "nick_name": "    ",
  "passWord": "string",
  "userName": "string",
  "user_sex": "string"
}

返回数据:

{
  "data": null,
  "code": "E000001",
  "msg": "昵称不能为空"
}

这样,通过和统一异常处理的结合,可以友好的实现前后端分离。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值