SpringBoot全局异常处理、数据校验

x33g5p2x  于2021-08-09 转载在 Spring  
字(7.7k)|赞(0)|评价(0)|浏览(248)

5.1 SpringBoot异常处理

我们知道在做SpingBoot时,难免会出现很多异常,想要快速解决这些异常必须要知道异常出在何处,又是何种错误,SpringBoot内置的已经有了一些异常处理,例如:RuntimeException、ArithmeticException、NullPointerException等等异常,但是仅仅这些异常是远远不够我们对于异常的断定和处理,所以才会延伸出局部异常处理、全局异常和深度异常处理等等,中心思想还是为了能够更加方便的了解出现异常时,知道是何种错误并快速处理,这样才不会盲目的去改bug。

SpringBoot默认的处理异常的机制,一旦程序中出现了异常会像/error 的 url 发送请求。默认BasicExceptionController 来处理/error 请求,然后跳转到默认显示异常的页面,也可以自定义error.html 页面。

5.1.1 Controller层局部异常处理

先看一段局部异常处理:

package com.kdcrm.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.HashMap;
import java.util.Map;

@Controller
public class ToIndexController { 


    @RequestMapping("/testException")
    public void testException(){ 
        //制造运行时异常
        System.out.println(1/0);
    }

    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public Map exceptionHandler(Exception ex)
    { 
        Map map=new HashMap<>();
        map.put("code",101);
        map.put("msg",ex.toString());
        return map;
    }
 
}

在这里插入图片描述

5.1.2 基于@ControllerAdvice注解的Controller层的全局异常处理

上述类中定义的异常处理,只能处理当前类中的异常,其他类中的捕获不到,所以我们引入了基于 @ControllerAdvice注解 的Controller层的全局异常处理:

package com.kdcrm.controller;

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import java.util.HashMap;
import java.util.Map;


@ControllerAdvice
public class GlobalExceptionHandlerController { 

	/** * 捕获Controller层的所有异常信息 * @param ex * @return */
    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public Map exceptionHandler(Exception ex)
    { 
        Map map=new HashMap<>();
        map.put("code",203);
        map.put("msg",ex.toString());
        return map;
    }
}

在这里插入图片描述
也可以将异常信息跳转到指定页面内,便于管理:
error.html:

<!DOCTYPE html>
<html lang="en" mlns:th="http://www.thymeleaf.org" xmlns:mlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>error页面</title>
</head>
<body>
<!--接收异常信息-->
<h1 th:text="${msg}"></h1>
</body>
</html>

Controller层全局异常处理GlobalExceptionHandlerController:

package com.kdcrm.controller;

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import java.util.HashMap;
import java.util.Map;

@ControllerAdvice
public class GlobalExceptionHandlerController { 
 
    /** * 将异常信息跳转值指定error页面 * @param ex * @return */
    @ExceptionHandler(value = Exception.class)
    public ModelAndView exceptionHandler2(Exception ex){ 
        ModelAndView mav = new ModelAndView();
        mav.addObject("msg",ex.toString());
        mav.setViewName("error");
        return mav;
    }
}

在这里插入图片描述

5.1.3 HandlerExceptionResolver处理异常解析器

上述是通过@ControllerAdvice注解的方式实现的全局异常处理,还有一种是实现HandlerExceptionResolver处理异常解析器接口的方式,两者原理是一样的,根据出现的是何种异常跳转至相应的页面,更加精准些:

package com.kdcrm.controller;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;

@Configuration
public class GlobalExceptionHandlerController implements HandlerExceptionResolver { 
    
    @Override
    public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception ex) { 
        ModelAndView mav = new ModelAndView();
        //判断不同异常类型,做不同的视图跳转
        if(ex instanceof ArithmeticException) { 
            mav.setViewName("ArithmeticError");
        }else if (ex instanceof NullPointerException){ 
            mav.setViewName("NullpointerError");
        }else if (ex instanceof IllegalAccessException){ 
            mav.setViewName("IllegalAccessError");
        }

        mav.addObject("msg",ex.toString());

        return mav;

    }

}

5.2 SpringBoot数据校验

我们可能会经常需要对传入的参数进行校验,如果数据比较少的时候还比较容易处理,但当数据比较多的时候会显得比较麻烦,而且处理不当的时候,还会代码重复。这时候就需要对参数进行校验了,而Spring Boot采用的是Validation对数据进行校验。

  • SpringBoot对表单数据校验的技术特点,使用了Hibernate-validation校验框架。

首先引入校验包依赖文件:

<dependency>
	<groupId>org.hibernate.validator</groupId>
	<artifactId>hibernate-validator</artifactId>
	<version>7.0.0.Final</version>
</dependency>

JSR 303 是Bean验证的规范 ,Hibernate Validator 是该规范的参考实现,它除了实现规范要求的注解外,还额外实现了一些注解。
包括一下注解:

注解 说明 @AsserrtFalse 元素必须为false @AssertTrue 元素必须为true @DecimalMax(value) 元素必须为数字,最大值为指定value @DecimalMin(value) 元素必须为数字,最小值为指定value @Digits(integer,fraction) 元素必须为数字,其值必须在可接受的范围内 @Null 元素必须为null @NotNull 元素必须不为null @Min(value) 元素必须为数字,其值大于等于指定value @Max(value) 元素必须为数字,其值小于等于指定value @Size(min,max,message) 元素大小必须在指定范围内,message加以说明 @Past 元素必须是一个过去的日期 @Furture 元素必须是一个将来的日期 @Pattern 元素符合指定的正则表达式 @Email 元素必须为电子邮箱格式 @Length(min,max,message) 必须是字符串,其值在指定范围内,message加以说明 @NotBlank(message) 字符串不能为null,且trim后不能为空字符串(长度非0),message加以说明 @NotEmpty 被注释的字符串、集合、数组不能为空(长度非0) @Range 元素在合适的范围内 @SafeHtml 元素必须是安全Html @URL 元素必须是有效URL

上述注解只是其中一部分,高亮注解是常用于Bean属性的校验,通过 @ConfigurationProperties(prefix = “user”) 引入配置文件并自动绑定属性:
User类:

package com.kdcrm.pojo;

import org.hibernate.validator.constraints.Length;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.validation.annotation.Validated;
import javax.validation.constraints.*;
import java.util.List;
import java.util.Map;
import java.util.Set;

@Configuration
@ConfigurationProperties(prefix = "user")
@Validated
public class User { 

    /** * @notNull 限制不能为空 * @NotEmpty 元素不能为null,且不为空(字符串和集合的长度不能为0) * @NotBlank(message = "XXX不能为空"),判断字符串是否为null,或者去掉首尾空格是否为空串 * @Length(min = 6,max = 10,message = "最短为6位,最大为10位") * @Min(value = "6") 限制最小值 * @Max(value = "10") 限制最大值 * @Email 判断邮箱是否合法 * @NotEmpty 字符串、集合、数组不能为空(长度非0) */

    @NotNull
    @Length(min = 1,max = 3,message = "名字长度最小为1,最大为3")
    private String name;

    @NotNull
    @Min(value = 6)
    @Max(value = 16)
    private String password;

    @NotNull
    @Size(min = 1,max = 100,message = "最小1岁,最大100岁")
    private int age;

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

    @Email
    private String email;

    @NotEmpty
    private List list;

    @NotEmpty
    private Set set;

    @NotEmpty
    private Map map;

}

application.yml配置文件

user:
  name: wbs
  password: 123456
  age: 21222
  sex: 男男男男
  email: 184519@163.com
  list:
    - dog
    - cat
    - pig
  set:
    - dog
    - cat
    - pig
  map:
    k1: zs
    k2: ls
    k3: ww

Controller层进行对象数据校验,用@Valid注解,通过BindingResult接收校验结果:

package com.kdcrm.controller;

import com.kdcrm.pojo.User;
import com.kdcrm.service.UserService;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import io.swagger.annotations.ResponseHeader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;


/** * @author 一宿君(CSDN : qq_52596258) * @date 2021-08-06 08:52:36 */
@Controller
public class PeopleController { 

    @ResponseBody
    @RequestMapping("/addUser")
    public ModelAndView addUser(@Valid User user, BindingResult result, ModelAndView mav){ 
        if(result.hasErrors()){ 
            //如果有错误,跳转至添加页面
            mav.setViewName("addUser");
            return mav;
        }
        //如果没有错误,则将数据存入到request作用域中
        mav.addObject("user",user);
        mav.setViewName("UserIndex");
        return mav;
    }

}

相关文章