一、参数校验错误

1. 注解校验注解校验的常见形式是,在JavaBean类中添加javax.validation校验注解,在控制器方法参数前添加@Validated注解,当Spring MVC将请求参数解析为控制器方法参数时会触发校验:

@Datapublic class User {    @NotEmpty    private String name;    @Email    private String email;}@Controller@RequestMapping("/user")public class UserController {    @PostMapping    public String create(@Validated User user) {        // other code        return "success-page";    }}

当参数校验失败时,默认会抛出BindingException异常。可以选择全局处理该异常,但更简单灵活的方法是使用绑定结果上下文BindingResult。在具有@Validated注解的参数后定义BindingResult参数,Spring MVC便会将校验结果保存在该参数中,而不是抛出异常。随后,可以在控制器方法中获取校验结果并处理它:

@PostMappingpublic String create(@Validated User user, BindingResult br) {    // 如果参数无效,则转发至当前页面    if(br.hasErrors()) {        return "user-registration";    }    // other code    return "success-page";}

BindingResult实例会自动保存在Model中。使用模板引擎时,可以在模板中轻松获取并渲染错误信息。例如在thymeleaf模板中,使用下述模板语法判断是否校验失败,并显示所有错误信息:

if="${#fields.hasErrors('*')}"> "err : ${#fields.errors('*')}" th:text="${err}">

或是为输入非法值的文本框添加一个错误CSS类,并在文本框下显式对应的错误信息:

type=
"*{name}">

2. 业务校验

注解校验足够简洁易用,但不适合处理复杂的校验逻辑。当业务逻辑复杂时,不可避免的需要编写额外的校验代码。当校验失败时,可以向BindingResult注入错误信息,使自定义的校验代码与注解校验统一:

@PostMappingpublic String create(@Validated User user, BindingResult br) {    // 如果参数无效,则转发至当前页面    if (br.hasErrors()) {        return "user-registration";    }    if ("张三".equals(user.getName())) {        // 注入与字段相关的错误消息        br.rejectValue("name", "FIELD-MSG-0001");        return "user-registration";    }    if ("李四".equals(user.getName()) && Objects.isNull(user.getEmail())) {        // 注入全局的错误消息        br.reject("GLOBAL-MSG-0001");        return "user-registration";    }    // other code    return "success-page";}

BindingResult会在MessageSource中找到错误码对应的消息:

# messages.propertiesFIELD-MSG-0001      = 张三被系统拉黑了。GLOBAL-MSG-0001     = 李四没有邮箱。

二、 业务层异常

每个业务层方法通常是一个事务单元。在业务校验失败时,需要抛出异常回滚事务:

@Getterpublic class BussinessException extends RuntimeException {  private static final long serialVersionUID = -3087418646815345707L;  private String errorCode;  public BussinessException(String errorCode) {    super("发生了业务异常:" + errorCode);    this.errorCode = errorCode;  }}@Servicepublic class UserService {        @Autowired    private UserMapper mapper;        @Transactional    public void createUser(User user) {        User existingUser = mapper.selectByName(user.getName());        if(Objects.nonNull(existingUser)) {            throw new BusinessException("BUSINESS-ERROR-0001");        }        mapper.insert(user);    }}

如果不显式的捕获异常,Spring MVC会丢弃当前的Model,防止处于错误状态的数据被继续使用。接下来,Spring Boot会将请求转发到错误页面,并将状态码设定为500。对于有状态服务端,如果只是希望停留在当前页面,并向用户反馈错误信息,需要在Web层显式的捕获异常并处理:

@PostMappingpublic String create(@Validated User user, BindingResult br) {    if (br.hasErrors()) {        return "user-registration";    }    // 发生业务异常时,注入错误消息,转发至当前页面    try {        service.createUser(user);    } catch (BusinessException e) {        br.reject(e.getErrorCode());        return "user-registration";    }    // other code    return "success-page";}

三、全局异常Spring Boot提供了异常处理控制器BasicErrorController映射到/error,它以一种明智的方式处理从Web层抛出的异常:对于媒体类型为HTML的请求,它将返回错误页面;如果是其他的媒体类型(通常是JSON),它将返回JSON格式的错误信息。1、定制错误页面首先在控制器中写一段会抛出空指针异常的代码:

@PostMappingpublic String create(User user) {    String a = null;    a.getBytes();    return "success-page";}

以post方法访问/user,该控制器抛出空指针异常后,请求被转发至/error,由BasicErrorController处理,返回whitelabel视图作为错误页面:

这是由于BasicErrorController在创建错误视图时,资源路径下寻找名为error.html的视图文件。如果没有找到,则返回“whitelabel”视图。因此,可以通过提供error.html定制错误页面的视图:

<html xmlns:th="http://www.thymeleaf.org"><head>  <title>自定义的错误页面title>head><body><h1>status: [[${status}]]h1><h5>错误信息:[[${message}]]h5>body>html>

重启服务后,再次以post方法访问/user,会返回定制的错误页面:

视图文件既可以是存放于templates目录下的模板文件,也可以是存放在static目录下的静态html文件。Spring Boot还提供了错误视图解析器DefaultErrorViewResolver,用于根据Http状态码使用不同的错误视图。DefaultErrorViewResolver在/templates/error或/static/error下匹配视图,具有两种匹配模式:

  • 视图文件名是具体的Http状态码。例如404.html,当发生404错误时,使用该视图文件。

  • 视图文件名以某一类Http状态码开头,例如5xx.html。当发生5开头的错误时(例如500),使用该视图文件。

在templates下创建错误视图目录error,在error下创建404错误专用的视图模板404.html,和5开头的错误通用的视图模板5xx.html:

<html xmlns:th="http://www.thymeleaf.org"><head>  <title>404title>head><body>页面未找到!body>html><html xmlns:th="http://www.thymeleaf.org"><head>  <title>5xxtitle>head><body>服务端错误:[[${status}]]body>html>

启动服务,访问不存在的路径时,显示404页面:以post方法访问/user,显示5xx页面:综上所述,当发生异常时,Spring Boot首先根据Http状态码寻找匹配的视图,如果没找到,再寻找名为error的视图,如果仍没有找到,则返回whitelabel视图。2、JSON响应当Content-Type为application/json的请求发生异常时,Spring Boot将响应JSON格式的错误信息。使用JQuery的ajaxError函数处理全局ajax异常:

    $( document ).ajaxError(function( event, request, settings, thrownError) {      var res = request.responseJSON;      // 在body中输出json错误信息      $('body').html('
'

+ JSON.stringify(res, null, 4) + ' });

创建submit事件监听器,向/user发起ajax请求:

    $(document).on('submit', function() {        $.ajax({            type: "POST",            url: 'user',            contentType: "application/json; charset=utf-8",            data: JSON.stringify({}),            success: function (res) {                alert("成功!");            }        });        return false;    });

提交后,请求被转发至/error由BasicErrorController处理,它将响应json格式的错误信息:


四、处理特定异常

在具有@Controller或@ControllerAdvice注解的类中,可以使用@ExceptionHandler定制特定于某种异常的处理,而不是使用BasicErrorController。

例如,发生特定异常时,在跳转到错误页面前打印日志:

@ControllerAdvice@Slf4jpublic class GlobalControllerAdvice {  @Autowired private MessageSource messageSource;  @ExceptionHandler(BussinessException.class)  public String handleBussinessException(      BussinessException e, HandlerMethod method, Locale locale) {    var methodName = method.getShortLogMessage();    var exName = e.getClass().getName();    log.warn(MessageFormat.format("在{0}中发生了{1}异常", methodName, exName));    var errorCode = e.getErrorCode();    var message = messageSource.getMessage(e.getErrorCode(), null, locale);    log.warn(MessageFormat.format("[{0}]{1}", errorCode, message));    return "/bussiness-error";  }}

发生异常时,将打印下述log:

2020-11-14 17:07:24.423  WARN 15768 --- [nio-8080-exec-3] c.c.w.d.w.c.GlobalControllerAdvice       : 在com.cn.wjw.demo.web.controller.UserController#create[0 args]中发生了com.cn.wjw.demo.exception.BussinessException异常2020-11-14 17:07:24.423  WARN 15768 --- [nio-8080-exec-3] c.c.w.d.w.c.GlobalControllerAdvice       : [E00001]其他用户已经更新了数据,请刷新页面。

当然,也可以继续利用BasicErrorController,但在向客户端响应之前做额外的处理。只需要在@ExceptionHandler中实现额外的处理,最后将请求转发到/error,或是将正在处理的异常重新抛出:

  @ExceptionHandler(Throwable.class)  public void handleException(Throwable t) throws Throwable {    // TODO 在这里实现额外的逻辑,然后重新抛出异常    throw t;  }

springboot 404_Spring Boot(四) 异常处理相关推荐

  1. springboot 上传异常捕获_Spring Boot 全局异常处理(下)

    可以搜索微信公众号[Jet 与编程]查看更多精彩文章 背景 在上篇[链接]中介绍了 Spring Boot 全局异常处理的一种方式,但那是一种全局性的容错机制,目的是把 Spring Boot 默认的 ...

  2. springboot 详解 (四)redis filter

    ---------------------------------------------------------------------------------------------------- ...

  3. SpringBoot入门(四)——自动配置

    本文来自网易云社区 SpringBoot之所以能够快速构建项目,得益于它的2个新特性,一个是起步依赖前面已经介绍过,另外一个则是自动配置.起步依赖用于降低项目依赖的复杂度,自动配置负责减少人工配置的工 ...

  4. Spring Boot默认异常处理BasicErrorController源码解读

    小伙伴们是不是刚接触Spring Boot做网页开发的时候,如果代码发生异常,会返回一个错误信息页面,如下图 那么这个页面是怎么返回的呢,这里就要接触到一个Spring Boot类BasicError ...

  5. spring boot(四):thymeleaf使用详解

    spring boot(四):thymeleaf使用详解 在上篇文章springboot(二):web综合开发中简单介绍了一下thymeleaf,这篇文章将更加全面详细的介绍thymeleaf的使用. ...

  6. springboot整合之统一异常处理

    特别说明:本次项目整合基于idea进行的,如果使用Eclipse可能操作会略有不同,不过总的来说不影响. springboot整合之如何选择版本及项目搭建 springboot整合之版本号统一管理  ...

  7. spring boot 四:全局异常捕捉

    spring boot 四:全局异常捕捉 1 前言 希望定制错误,比如一般springboot的500错误展示如下(trace等可以通过配置application.yml来决定隐藏还是具有): app ...

  8. springboot aop + logback + 统一异常处理 打印日志

    springboot aop + logback + 统一异常处理 打印日志 参考文章: (1)springboot aop + logback + 统一异常处理 打印日志 (2)https://ww ...

  9. java实验四结果,java实验四异常处理.doc

    java实验四异常处理.doc 实验四异常处理一.实验目的1.掌握异常的概念和Java异常处理机制.2.掌握异常的定义.抛出和捕捉处理.二.实验内容与要求1.仔细读下面的JAVA语言源程序,自己给出程 ...

最新文章

  1. Web服务器的工作原理
  2. flutter能开发游戏吗_游戏开发者都擅长“打自己的游戏”吗?
  3. Android 系统(11)---android 系统权限大全
  4. python fetchall()转化为数据框_python 操作mysql数据中fetchone()和fetchall()方式
  5. [论文阅读] BCNet: Bidirectional collaboration network for edge-guided salient object detection
  6. 【HDFS】HDFS与getconf结合使用,获取配置信息
  7. 三、K8s常见操作命令
  8. 第1章 操作系统引论课后答案
  9. 2020年9月中国旅游行业网络关注度分析报告
  10. C#毕业设计——基于C#+ASP.NET+SQL Server的酒店入住信息管理系统设计与实现(毕业论文+程序源码)——酒店入住信息管理系统
  11. 手把带你学会红外避障循迹模块
  12. 量子力学随机矩阵理论
  13. Java 在线编辑 Excel
  14. mongoTemplate查询指定字段
  15. 关于eSIM的一些简单介绍
  16. ubuntu大于4T分区 12T硬盘分区
  17. new指针后,地址相同
  18. 安装Debian lenny教程
  19. 使用前嗅ForeSpider采集需要登陆的网页内容
  20. 如何把editplus设置成中文

热门文章

  1. 演练 课程导航 1002 html
  2. python-对象-验证对象与类的关系
  3. python-字符串转义符号
  4. 用户访问一个网站的全部过程
  5. linux批量替换文件夹中所有文件内容
  6. C#设计模式:迭代器模式(Iterator Pattern)
  7. 引用和可触及性的强度
  8. if和switch以及for
  9. 在Ubuntu下面编译WizNote Qt Project
  10. TryCatchFinallyProcessHelper