欢迎访问昆山宝鼎软件有限公司网站! 设为首页 | 网站地图 | XML | RSS订阅 | 宝鼎邮箱 | 后台管理


新闻资讯

MENU

软件开发知识
原文出处: Frapples

在详细的SSM项目开拓中,由于Controller层为处于请求处理惩罚的最顶层,再往上就是框架代码的。因此,必定需要在Controller捕捉所有异常,而且做适当处理惩罚,返回给前端一个友好的错误码。

不外,Controller一多,昆山软件开发,我们发明每个Controller里都有大量反复的、冗余的异常处理惩罚代码,极端烦琐。可否将这些反复的部门抽取出来,这样担保Controller层更专注于业务逻辑的处理惩罚,同时可以或许使得异常的处理惩罚有一个统一的节制中心点。

1. 全局异常处理惩罚

1.1. HandlerExceptionResolver接口

public interface HandlerExceptionResolver {
	/**
	 * Try to resolve the given exception that got thrown during on handler execution,
	 * returning a ModelAndView that represents a specific error page if appropriate.
	 * <p>The returned ModelAndView may be {@linkplain ModelAndView#isEmpty() empty}
	 * to indicate that the exception has been resolved successfully but that no view
	 * should be rendered, for instance by setting a status code.
	 * @param request current HTTP request
	 * @param response current HTTP response
	 * @param handler the executed handler, or {@code null} if none chosen at the
	 * time of the exception (for example, if multipart resolution failed)
	 * @param ex the exception that got thrown during handler execution
	 * @return a corresponding ModelAndView to forward to,
	 * or {@code null} for default processing
	 */
	ModelAndView resolveException(
			HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex);
}

利用全局异常处理惩罚器只需要两步:

  1. 实现HandlerExceptionResolver接口。
  2. 将实现类作为Spring Bean,这样Spring就能扫描到它并作为全局异常处理惩罚器加载。

在 resolveException 中实现异常处理惩罚逻辑。从参数上,可以看到,不只可以或许拿到产生异常的函数和异常工具,还可以或许拿到 HttpServletResponse工具,从而节制本次请求返回给前端的行为。

另外,函数还可以返回一个 ModelAndView 工具,暗示渲染一个视图,例如说错误页面。不外,在前后端疏散为主流架构的本日,这个很罕用了。假如函数返回的视图为空,则暗示不需要视图。

1.2. 利用示例

来看一个例子:

@Component
@Slf4j
public class CustomHandlerExceptionResolver implements HandlerExceptionResolver {
    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        Method method = null;
        if (handler != null && handler instanceof HandlerMethod) {
            method = ((HandlerMethod) handler).getMethod();
        }
        log.error("[{}] system error", method, ex);
        ResponseDTO response = ResponseDTO.builder()
        .errorCode(ErrorCode.SYSTEM_ERROR)
        .build();
        byte[] bytes = JSON.toJSONString(response).getBytes(StandardCharsets.UTF_8));
        try {
            FileCopyUtils.copy(bytes, response.getOutputStream());
        } catch (IOException e) {
            log.error("error", e);
            throw new RuntimeException(e);
        }
        return new ModelAndView();
    }
}

逻辑很显然,在产生异常时,将 ResponseDTO 序列化为 json 给前端。

1.3. Controller局部异常处理惩罚

1.3.1. 利用示例

这种异常处理惩罚只局部于某个 Controller 内,如:

@Controller
@Slf4j
@RequestMapping("/api/demo")
public class DemoController {
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public ResponseDTO<?> exceptionHandler(Exception e) {
        log.error("[{}] system error", e);
        return ResponseDTO.builder()
        .errorCode(ErrorCode.SYSTEM_ERROR)
        .build();
    }
}
  1. 所有 Controller 要领(即被 RequestMapping 注解的要领)抛出的异常,会被该异常处理惩罚要领处理惩罚。
  2. 利用上,在 Controller 内部,用 @ExceptionHandler 注解的要领,就会作为该Controller内部的异常处理惩罚要领。
  3. 而且,它的参数中可以注入如 WebRequest、NativeWebRequest 等,用来拿到请求相关的数据。
  4. 它可以返回 String 代表一个 view 名称,也可以返回一个工具而且用 @ResponseBody 修饰,由框架的其它机制帮你序列化。

另外,它还可以或许对异常范例举办细粒度的节制,通过注解可以有选择的指定异常处理惩罚要领应用的异常范例:

@ExceptionHandler({BusinessException.class, DataBaseError.class })

固然说全局异常处理惩罚HandlerExceptionResolver通过条件判定也能做到,可是利用这种注解方法明明更具有可读性。

1.3.2. 一个问题

适才说到异常处理惩罚函数可以用 @ResponseBody 修饰,就像一般的Controller要领一样。