记一次SpringMVC全局异常处理未捕获到异常BUG定位

    技术2022-07-13  66

    前因

    博主在写项目的时候,自定义了一个异常类,继承自运行时异常类:

    /** * 禁止访问异常类 * @author alageek */ public class AccessForbiddenException extends RuntimeException { private static final long serialVersionUID = 7526324512252691698L; public AccessForbiddenException(){ super(); } public AccessForbiddenException(String message, Throwable cause, Boolean enableSuppression, Boolean writableStackTrace){ super(message, cause, enableSuppression, writableStackTrace); } public AccessForbiddenException(String message, Throwable cause){ super(message, cause); } public AccessForbiddenException(Throwable cause){ super(cause); } public AccessForbiddenException(String message){ super(message); } }

    而后在拦截器中,将其抛出:

    /** * 登录拦截 * @author alageek */ public class LoginInterceptor extends HandlerInterceptorAdapter { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { HttpSession session = request.getSession(); Admin admin = (Admin) session.getAttribute(CrowdConstant.ATTR_NAME_LOGIN_ADMIN); if(admin == null){ throw new AccessForbiddenException(CrowdConstant.MESSAGE_ACCESS_FORBIDDEN); } return true; } }

    同时又在SpringMVC中设置了全局异常处理:

    /** * 异常处理机制 * @author alageek * 注解ControllerAdvice表示当前类是基于注解的异常处理器类 */ @ControllerAdvice public class CrowdExceptionResolver { /** * 禁止访问异常处理 * 注解ExceptionHandler将异常类与方法关联 * @param exception 异常对象 * @param request 请求对象 * @param response 响应对象 * @return 若请求为Ajax请求,则返回json类型的错误信息,否则返回错误页面 * @throws IOException ResultEntity对象转json异常 */ @ExceptionHandler(value = AccessForbiddenException.class) public ModelAndView resolveAccessForbiddenException( AccessForbiddenException exception, HttpServletRequest request, HttpServletResponse response) throws IOException { String viewName = "admin-login"; return commonResolve(exception, request, response, viewName); } private ModelAndView commonResolve( Exception exception, HttpServletRequest request, HttpServletResponse response, String viewName) throws IOException { if(CrowdUtil.judgeRequestType(request)){ // Ajax请求 response.getWriter().write(new Gson().toJson(ResultEntity.failed(exception.getMessage()))); return null; } // 普通请求 ModelAndView modelAndView = new ModelAndView(); modelAndView.addObject(CrowdConstant.ATTR_NAME_EXCEPTION, exception); modelAndView.setViewName(viewName); return modelAndView; } }

    最终的启动项目后,发现在拦截器抛出AccessForbiddenException异常时,全局异常处理并未捕获到异常。

    BUG定位

    经过百度SpringMVC全局异常处理的三种方式后,恍然大悟,按上面博主所写的这种方式捕获全局异常,只能捕获到Controller里抛出的异常,想要捕获拦截器里这个异常,需要在SpringMVC的配置文件中进行配置。

    BUG修复

    在SpringMVC配置文件中配置异常机制,如下:

    <!-- 配置基于XML的异常机制 --> <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver" id="simpleMappingExceptionResolver"> <!-- 配置异常类型和具体视图页面的对应关系 --> <property name="exceptionMappings"> <props> <prop key="com.alageek.crowd.exception.AccessForbiddenException">admin-login</prop> </props> </property> </bean>
    Processed: 0.012, SQL: 9