【愚公系列】2023年10月 Java教学课程 159-Spring MVC框架的异常处理

在这里插入图片描述

🏆 作者简介,愚公搬代码
🏆《头衔》:华为云特约编辑,华为云云享专家,华为开发者专家,华为产品云测专家,CSDN博客专家,阿里云专家博主,阿里云签约作者,腾讯云优秀博主,腾讯云内容共创官,掘金优秀博主,51CTO博客专家等。
🏆《近期荣誉》:2022年CSDN博客之星TOP2,2022年华为云十佳博主等。
🏆《博客内容》:.NET、Java、Python、Go、Node、前端、IOS、Android、鸿蒙、Linux、物联网、网络安全、大数据、人工智能、U3D游戏、小程序等相关领域知识。
🏆🎉欢迎 👍点赞✍评论⭐收藏


🚀前言

Spring MVC框架的异常处理是程序在运行过程中出现异常时,如何处理这些异常。在Spring MVC框架中,异常通常包括Java自带的异常,如NullPointerException、IllegalArgumentException等,以及自定义的异常。如果程序没有对异常进行处理,异常将会被抛到Servlet容器的异常处理器中,通常会返回一个错误页面。而Spring MVC框架提供了多种处理异常的方法,可以让开发人员更加灵活地控制异常的处理方式,例如使用@ExceptionHandler注解、@ControllerAdvice注解、SimpleMappingExceptionResolver、HandlerExceptionResolver接口等。这些方法可以方便地进行错误信息的定制、重定向、转发、记录日志等操作,提高了程序的可维护性和用户体验。

🚀一、异常处理

Spring MVC框架的异常处理主要有以下几种:

  1. @ExceptionHandler注解:使用该注解可以在Controller类或方法中声明一个方法,用于处理指定类型的异常。

  2. @ControllerAdvice注解:使用该注解可以在全局范围内声明一个类,用于处理指定类型的异常,可以搭配@ExceptionHandler注解使用。

  3. SimpleMappingExceptionResolver:该类可以将异常映射到指定的视图或URL,并进行相应的处理。

  4. HandlerExceptionResolver接口:该接口可以自定义异常处理器,实现自己的异常处理逻辑。

  5. @ResponseStatus注解:该注解可以在Controller方法中直接指定异常的HTTP状态码和响应消息,用于快速处理一些常规异常。

  6. @ControllerAdvice和@ExceptionHandler注解结合使用:可以在全局范围内声明一个异常处理类,用于处理所有Controller方法中抛出的异常。

🔎1.HandlerExceptionResolver的使用

Spring MVC框架的异常处理是通过HandlerExceptionResolver接口实现的,以下是一个完整的使用案例:

  1. 创建一个自定义异常类CustomException,继承Exception类。
public class CustomException extends Exception {
    private static final long serialVersionUID = 1L;
    private String message;

    public CustomException(String message) {
        super(message);
        this.message = message;
    }

    public String getMessage() {
        return message;
    }
}
  1. 创建一个全局异常处理类GlobalExceptionHandler,继承SimpleMappingExceptionResolver类,并实现HandlerExceptionResolver接口。
public class GlobalExceptionHandler extends SimpleMappingExceptionResolver implements HandlerExceptionResolver {

    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        String viewName = determineViewName(ex, request);
        if (viewName != null) {
            if (!(request.getHeader("accept").contains("application/json") || (request.getHeader("X-Requested-With") != null && request.getHeader("X-Requested-With").contains("XMLHttpRequest")))) {
                //非异步方式请求
                ModelAndView modelAndView = getModelAndView(viewName, ex, request);
                return modelAndView;
            } else {
                //异步方式请求
                try {
                    response.setContentType("text/json;charset=UTF-8");
                    response.setHeader("Cache-Control", "no-cache, must-revalidate");
                    PrintWriter writer = response.getWriter();
                    writer.write(JSON.toJSONString(new ResultBean(false, ex.getMessage())));
                    writer.flush();
                    writer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                return null;
            }
        } else {
            return null;
        }
    }
}
  1. 在Spring的配置文件中配置GlobalExceptionHandler。
<bean id="handlerExceptionResolver" class="com.xxx.exception.GlobalExceptionHandler">
    <property name="exceptionMappings">
        <props>
            <prop key="com.xxx.exception.CustomException">error/customError</prop>
        </props>
    </property>
</bean>
  1. 编写Controller,并抛出CustomException异常。
@RequestMapping("/test")
public String test() throws CustomException {
    throw new CustomException("测试异常");
}
  1. 编写自定义错误页面customError.jsp。
<%@ page contentType="text/html; charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8"/>
    <title>错误页面</title>
</head>
<body>
<h1>出错了!</h1>
<c:out value="${exception.message}"/>
</body>
</html>

🔎2.@ControllerAdvice和@ExceptionHandler注解结合使用

@ControllerAdvice和@ExceptionHandler是Spring MVC框架中常用的全局异常处理方式,可以帮助开发者处理应用程序而产生的异常,并且可以提高程序的健壮性和可靠性。

@ControllerAdvice注解

@ControllerAdvice注解是一个标记性注解,用于定义一个控制器通知类,被标记的类将作为全局异常处理器,用于捕获和处理应用程序中的异常。@ControllerAdvice可以定义拦截哪些异常的方法,以及如何处理这些异常。通常情况下,@ControllerAdvice标记的类包含多个@ExceptionHandler方法,用于处理不同类型的异常。

@ExceptionHandler注解

@ExceptionHandler注解用于定义一个方法,用于处理应用程序中出现的某种类型的异常。如果在控制器或其任何子类中抛出此类异常,则该方法将自动被调用。@ExceptionHandler注解可以定义要处理的异常的类型,并定义该方法返回的视图或错误消息。

完整使用案例

  1. 创建CustomException异常类
public class CustomException extends Exception {

    private static final long serialVersionUID = 1L;
    private String message;

    public CustomException(String message) {
        super(message);
        this.message = message;
    }

    public String getMessage() {
        return message;
    }
}
  1. 创建一个全局异常处理类GlobalExceptionHandler,使用@ControllerAdvice注解标注该类,并在该类中定义需要捕获的异常类型和异常处理方法。
@ControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 捕获 CustomException 异常
     * @param ex
     * @param request
     * @return
     */
    @ExceptionHandler(CustomException.class)
    public ModelAndView customExceptionHandler(CustomException ex, HttpServletRequest request) {
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("message", ex.getMessage());
        modelAndView.setViewName("error/customError");
        return modelAndView;
    }

    /**
     * 捕获其他异常
     * @param ex
     * @param request
     * @return
     */
    @ExceptionHandler(Exception.class)
    public ModelAndView defaultExceptionHandler(Exception ex, HttpServletRequest request) {
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("message", "系统异常,请稍后再试!");
        modelAndView.setViewName("error/defaultError");
        return modelAndView;
    }
}
  1. 编写Controller,并抛出CustomException异常。
@RequestMapping("/test")
public String test() throws CustomException {
    throw new CustomException("测试异常");
}
  1. 编写自定义错误页面customError.jsp和默认错误页面defaultError.jsp。

customError.jsp:

<%@ page contentType="text/html; charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8"/>
    <title>自定义异常页面</title>
</head>
<body>
<h1>出错了!</h1>
${message}
</body>
</html>

defaultError.jsp:

<%@ page contentType="text/html; charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8"/>
    <title>默认异常页面</title>
</head>
<body>
<h1>系统异常,请稍后再试!</h1>
</body>
</html>

🔎3.@ResponseStatus的使用

@ResponseStatus注解为Spring MVC框架中的一个注解,用于指定处理请求时,在遇到某些特殊的异常时返回指定的HTTP状态码和自定义的错误消息。通过这个注解,我们可以很方便地将系统中的异常处理和HTTP响应合并在一起。

假设我们有一个Web应用程序,在处理订单时可能会抛出一个特殊的异常:OrderNotFoundException,如果我们想在遇到这个异常时,返回HTTP状态码为404,并在响应中添加一些自定义消息,我们可以在处理这个异常的方法上使用@ResponseStatus注解。

定义OrderNotFoundException异常类:

@ResponseStatus(HttpStatus.NOT_FOUND)
public class OrderNotFoundException extends RuntimeException {

    public OrderNotFoundException(String message) {
        super(message);
    }
}

在处理订单的Controller中,当发现订单不存在时抛出OrderNotFoundException异常:

@RequestMapping("/orders/{id}")
public Order getOrder(@PathVariable("id") Long id) {
    Order order = orderService.getOrderById(id);
    if (order == null) {
        throw new OrderNotFoundException("Order not found, id=" + id);
    }
    return order;
}

在上面的代码中,当orderService.getOrderById(id)方法返回null时,我们会抛出一个OrderNotFoundException异常。这个异常会被Spring MVC框架捕获,并根据@ResponseStatus注解的定义返回一个HTTP 404状态码,以及自定义的错误消息。

如果我们在Web浏览器中请求/orders/123,而123号订单不存在,我们会得到一个JSON格式的响应:

{
    "status": "NOT_FOUND",
    "message": "Order not found, id=123",
    "timestamp": "2020-01-01T00:00:00.000+00:00"
}

🔎4.自定义异常

以下是一个完整的使用Spring MVC框架自定义异常的案例:

  1. 自定义异常类

首先,我们需要定义自己的异常类,可以继承自RuntimeException或者其他异常类。在本例中,我们定义了一个CustomException异常类。

public class CustomException extends RuntimeException{
    private static final long serialVersionUID = 1L;
    private String message;

    public CustomException(String message){
        this.message = message;
    }

    public String getMessage(){
        return message;
    }
}
  1. 统一异常处理类

接下来,我们需要定义一个统一的异常处理类,用于捕获所有的异常并返回统一格式的错误信息。在本例中,我们定义了一个GlobalExceptionHandler类。

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(value = CustomException.class)
    @ResponseBody
    public JsonResult handlerCustomException(CustomException ex){
        return JsonResult.error(ex.getMessage());
    }

    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public JsonResult handlerException(Exception ex){
        ex.printStackTrace();
        return JsonResult.error("系统异常,请稍后重试");
    }
}

在该类中,我们使用@ControllerAdvice注解来标记该类为统一异常处理类,并定义了两个异常处理方法:

  • handlerCustomException方法,用于处理CustomException异常,返回一个JsonResult对象,其中包含了自定义的错误信息。
  • handlerException方法,用于处理其他所有的异常,返回一个JsonResult对象,其中包含了统一格式的错误信息。
  1. 控制器方法

最后,我们需要在控制器方法中抛出CustomException异常,以便测试我们的异常处理流程。在本例中,我们定义了一个UserController控制器类,并在其中的login方法中抛出了CustomException异常。

@Controller
@RequestMapping("/user")
public class UserController {

    @RequestMapping("/login")
    @ResponseBody
    public JsonResult login(){
        throw new CustomException("用户名或密码错误");
    }

}
  1. 测试

现在,我们可以启动Spring MVC应用程序,并访问/user/login接口来测试我们的异常处理流程。当我们访问该接口时,控制器方法会抛出CustomException异常,然后被GlobalExceptionHandler类捕获并返回一个包含自定义错误信息的JsonResult对象。最终,我们的客户端可以根据返回的JsonResult对象来判断登录是否成功。

{
    "code":500,
    "msg":"用户名或密码错误",
    "data":null
}

🚀感谢:给读者的一封信

亲爱的读者,

我在这篇文章中投入了大量的心血和时间,希望为您提供有价值的内容。这篇文章包含了深入的研究和个人经验,我相信这些信息对您非常有帮助。

如果您觉得这篇文章对您有所帮助,我诚恳地请求您考虑赞赏1元钱的支持。这个金额不会对您的财务状况造成负担,但它会对我继续创作高质量的内容产生积极的影响。

我之所以写这篇文章,是因为我热爱分享有用的知识和见解。您的支持将帮助我继续这个使命,也鼓励我花更多的时间和精力创作更多有价值的内容。

如果您愿意支持我的创作,请扫描下面二维码,您的支持将不胜感激。同时,如果您有任何反馈或建议,也欢迎与我分享。

在这里插入图片描述

再次感谢您的阅读和支持!

最诚挚的问候, “愚公搬代码”

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

愚公搬代码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值