Spring 异常处理

Spring3.0 对异常的处理方式总共有两种:

    第一种是使用 HandlerExceptionResolver 接口,并且 Spring 已经提供默认的实现类 SimpleMappingExceptionResolver。

    第二种方法是在 Controller 内部实现,灵活性更高。

这两种方式不能共存。我们一般在项目中使用第一种方法。

下面分别描述一下这两种使用方式:

1.1 基于 HandlerExceptionResolver 接口的方式

    使用这种方式只需要实现 resolveException 方法,该方法返回一个 ModelAndView 对象,在方法内部对异常的类型进行判断,然后返回合适的 ModelAndView 对象,如果该方法返回了 null,则 Spring 会继续寻找其他的实现了 HandlerExceptionResolver 接口的 Bean。换句话说,Spring 会搜索所有注册在其环境中的实现了 HandlerExceptionResolver 接口的 Bean,逐个执行,直到返回了一个 ModelAndView 对象。

@Component
public class CustomExceptionHandler implements HandlerExceptionResolver {

    @Override
    public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
        // 记录异常日志
        Logger logger = LogManager.getLogger();
        logger.error(e.getMessage(), e);

        if(e instanceof IOException){//IO错误
            return new ModelAndView("error/ioException","ex",e);
        }else if(e instanceof SQLException){//SQL错误
            return new ModelAndView("error/sqlException","ex",e);
        }
        return null;
    }
}

    这个类必须声明到 SpringMVC配置文件中,或者在类上使用 @Component 标签,让 Spring 管理它。

    error/ioException.jsp:

<html>
<head><title>Exception!</title></head>
<body>
  <% Exception ex = (Exception) request.getAttribute("ex"); %>
  <H2>Exception: <%=ex.getMessage()%></H2>
  <P><% ex.printStackTrace(new java.io.PrintWriter(out)); %></P>
</body>
</html>

    error/sqlException.jsp:

<html>
<head><title>Exception!</title></head>
<body>
  <% Exception ex = (Exception) request.getAttribute("ex"); %>
  <H2>Exception: <%=ex.getMessage()%></H2>
  <P><% ex.printStackTrace(new java.io.PrintWriter(out)); %></P>
</body>
</html>

1.2 直接使用Spring提供的默认实现类 SimpleMappingExceptionResolver

    只需要使用注入到 Spring 配置文件进行声明即可。

<!-- 默认的实现类注入 -->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">  
    <!-- 
    定义需要特殊处理的异常,用类名或完全路径名作为key,异常页文件名作为值,
    将不同的异常映射到不同的页面上。
   -->  
    <property name="exceptionMappings">  
        <props>  
            <prop key="IOException">error/ioException</prop>  
            <prop key="java.sql.SQLException">error/sqlException</prop>  
        </props>  
    </property>

    <!-- 为所有的异常定义默认的异常处理页面,exceptionMappings未定义的异常使用本默认配置 -->  
    <property name="defaultErrorView" value="error/error"></property>  
    
    <!-- 定义异常处理页面用来获取异常信息的变量名,默认名为exception -->  
    <property name="exceptionAttribute" value="ex"></property>

    <!-- 定义默认返回状态码为500 -->  
    <property name="defaultStatusCode" value="500"></property>
</bean>

    error/ioException.jsp:

<html>
<head><title>Exception!</title></head>
<body>
  <% Exception ex = (Exception) request.getAttribute("ex"); %>
  <H2>Exception: <%=ex.getMessage()%></H2>
  <P><% ex.printStackTrace(new java.io.PrintWriter(out)); %></P>
</body>
</html>

    error/sqlException.jsp:

<html>
<head><title>Exception!</title></head>
<body>
  <% Exception ex = (Exception) request.getAttribute("ex"); %>
  <H2>Exception: <%=ex.getMessage()%></H2>
  <P><% ex.printStackTrace(new java.io.PrintWriter(out)); %></P>
</body>
</html>

    error/error.jsp:

<html>
<head><title>Exception!</title></head>
<body>
  <% Exception ex = (Exception) request.getAttribute("ex"); %>
  <H2>Exception: <%=ex.getMessage()%></H2>
  <P><% ex.printStackTrace(new java.io.PrintWriter(out)); %></P>
</body>
</html>

1.3 覆盖默认实现类SimpleMappingExceptionResolver中的doResolveException方法

<!-- 异常捕获 -->
<bean id="exceptionResolver" class="com.westar.core.web.WebHandlerExceptionResolver">
    <!-- 
    定义需要特殊处理的异常,用类名或完全路径名作为key,异常页文件名作为值,
    将不同的异常映射到不同的页面上。
   -->  
    <property name="exceptionMappings">  
        <props>  
            <prop key="IOException">error/ioException</prop>
        </props>  
    </property>

    <!-- 为所有的异常定义默认的异常处理页面,exceptionMappings未定义的异常使用本默认配置 -->  
    <property name="defaultErrorView" value="error/error"></property>  
    
    <!-- 定义异常处理页面用来获取异常信息的变量名,默认名为exception -->  
    <property name="exceptionAttribute" value="ex"></property>

    <!-- 定义默认返回状态码为500 -->  
    <property name="defaultStatusCode" value="500"></property>
</bean>
@Component
public class WebHandlerExceptionResolver extends SimpleMappingExceptionResolver {
	protected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response, Object object, Exception ex) {
		// 记录异常日志
		Logger logger = LogManager.getLogger();
		logger.error(ex.getMessage(), ex);
		
        if(ex instanceof SQLException){//SQL错误
            return new ModelAndView("error/sqlException","ex",ex);
        }else {//跳转到默认异常处理页面,异常信息变量为默认值
            return super.doResolveException(request, response, handler, ex);
        }
	}
}

    error/ioException.jsp:

<html>
<head><title>Exception!</title></head>
<body>
  <% Exception ex = (Exception) request.getAttribute("ex"); %>
  <H2>Exception: <%=ex.getMessage()%></H2>
  <P><% ex.printStackTrace(new java.io.PrintWriter(out)); %></P>
</body>
</html>

    error/sqlException.jsp:

<html>
<head><title>Exception!</title></head>
<body>
  <% Exception ex = (Exception) request.getAttribute("ex"); %>
  <H2>Exception: <%=ex.getMessage()%></H2>
  <P><% ex.printStackTrace(new java.io.PrintWriter(out)); %></P>
</body>
</html>

    error/error.jsp:

<html>
<head><title>Exception!</title></head>
<body>
  <% Exception ex = (Exception) request.getAttribute("ex"); %>
  <H2>Exception: <%=ex.getMessage()%></H2>
  <P><% ex.printStackTrace(new java.io.PrintWriter(out)); %></P>
</body>
</html>

1.4自定义实现类与默认的实现类同时使用。

    XML配置:

<bean class="com.core.service.WebExceptionHandler">
   <!--
      定义此处无须处理的异常集合,直接返回null,交由其他的异常处理类处理
   -->
   <property name="excludedExceptions">
      <list>
         <value>java.io.IOException</value>
         <value>java.sql.SQLException</value>
      </list>
   </property>

   <!-- 为所有的异常定义默认的异常处理页面,exceptionMappings未定义的异常使用本默认配置 -->
   <property name="defaultErrorView" value="error/error"></property>

   <!-- 定义异常处理页面用来获取异常信息的变量名,默认名为exception -->
   <property name="exceptionAttribute" value="ex"></property>

   <!-- 定义默认返回状态码为500 -->
   <property name="defaultStatusCode" value="500"></property>
</bean>

    自定义异常处理:

@Component
public class CustomExceptionHandler implements HandlerExceptionResolver {

    @Override
    public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
        // 判断是否已进行了异常日志的记录
        String logging=(String)httpServletRequest.getAttribute("logging");
        if(logging==null||logging==""){
            Logger logger = LogManager.getLogger();
            logger.error(e.getMessage(), e);
            httpServletRequest.setAttribute("logging","true");
        }

        if(e instanceof IOException){//IO错误
            return new ModelAndView("error/ioException","ex",e);
        }else if(e instanceof SQLException){//SQL错误
            return new ModelAndView("error/sqlException","ex",e);
        }
        return null;
    }
}

    重写默认异常处理:

public class WebExceptionHandler extends SimpleMappingExceptionResolver {
    @Override
    protected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        // 判断是否已进行了异常日志的记录
        String logging=(String)request.getAttribute("logging");
        if(logging==null||logging==""){
            Logger logger = LogManager.getLogger();
            logger.error(ex.getMessage(), ex);
            request.setAttribute("logging","true");
        }
        return super.doResolveException(request, response, handler, ex);
    }
}

    若先执行自定义异常处理类,先判断是否已记录异常日志,当遇到IO、SQL错误返回到对应的错误页面;其他错误将交由默认异常处理类处理,异常处理类将不再进行日志记录并返回到通用的错误页面;

    若先执行默认异常处理类,先判断是否已记录异常日志,当遇到IO、SQL错误返回null并交由自定义异常处理类,自定义异常处理类将不再进行日志记录并返回对应的错误页面;其他错误由默认异常处理类处理并返回到通用的错误页面;

 

    异常显示界面:

<html>
<head><title>Exception!</title></head>
<body>
  <% Exception ex = (Exception) request.getAttribute("ex"); %>
  <H2>Exception: <%=ex.getMessage()%></H2>
  <P><% ex.printStackTrace(new java.io.PrintWriter(out)); %></P>
</body>
</html>

 

2 Controller 内部单独实现

    该方法需要定义在 Controller 内部,然后创建一个方法并用 @ExceptionHandler 注解来修饰用来处理异常,这个方法基本和 @RequestMapping 修饰的方法差不多,只是可以多一个类型为 Exception 的参数,@ExceptionHandler 中可以添加一个或多个异常的类型,如果为空的话则认为可以触发所有的异常类型错误。

@Controller  
public class ExceptionHandlerController {
    @RequestMapping("test")
    public void Test(){
       System.out.println("aaaaa");
    }

    //如果该类的某一个方法抛出了IOException或IOException,则由该方法处理
    @ExceptionHandler(value={IOException.class,SQLException.class})  
    public String exp(Exception ex,HttpServletRequest request) {  
        request.setAttribute("ex", ex);  
        return "/error.jsp";  
    }  
}

三、相关问题

    HandlerExceptionResolver 和 web.xml 中配置的 error-page 会有冲突吗?

    web.xml 中配置 error-page 同样是配置出现错误时显示的页面:

<error-page>
    <error-code>500</error-code>
    <location>/500.jsp</location>
</error-page>

    如果 resolveException 返回了 ModelAndView,会优先根据返回值中的页面来显示。不过,resolveException 可以返回 null,此时则展示 web.xml 中的 error-page 的500状态码配置的页面。

转载于:https://my.oschina.net/langwanghuangshifu/blog/2052319

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值