spring统一异常处理的3种方法(含可运行的完整代码)

    技术2022-07-10  149

    代码中一堆try-catch块非常冗余和啰嗦,对阅读也造成了一定的干扰,使注意力很难集中到核心业务上来。

    因此我们使用统一异常处理,将这些重复的try-catch块抽取出来,这样使我们可以更专注于业务逻辑的处理,同时能够使得异常的处理有一个统一的控制。

    1.HandlerExceptionResolver全局异常处理

    使用全局异常处理器只需要两步: 1.实现HandlerExceptionResolver接口。 2.将实现类作为Spring Bean,这样Spring就能扫描到它并作为全局异常处理器加载。

    /** * 全局异常处理 * * @Order(-1000) 为了使优先级最高 * 写@Order(0)也行,-1000保险点 * * @Component 把普通pojo实例化到spring容器中, * 相当于配置文件中的 <bean id="" class=""/> */ @Order(-1000) @Component public class ExceptionResolver implements HandlerExceptionResolver { private static Logger logger = LoggerFactory.getLogger(ExceptionResolver.class); @Override public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { ResultVO result = new ResultVO(); StringBuilder sb = new StringBuilder(); //处理异常 if(ex instanceof BussinessException) { resolverBussinessException(ex, sb, result); } else if (ex instanceof BindException) { resolverBindException(ex, sb, result); } else { resolverOtherException(ex, sb, result); } result.setCode(0); result.setResult(sb); result.setTime(new Date()); response.setContentType(MediaType.APPLICATION_JSON_VALUE); response.setCharacterEncoding("UTF-8"); response.setHeader("Cache-Control", "no-cache, must-revalidate"); try { response.getWriter().write(JSON.toJSONString(result)); } catch (IOException e) { logger.error("与客户端通讯异常:" + e.getMessage(), e); e.printStackTrace(); } logger.debug("异常:" + ex.getMessage(), ex); ex.printStackTrace(); return new ModelAndView(); } /* * 处理业务层异常 */ private void resolverBussinessException(Exception ex, StringBuilder sb, ResultVO result) { BussinessException businessException = (BussinessException) ex; sb.append(businessException.getMsg()); addResult(result, "业务异常"); } /* * 处理参数绑定异常 */ private void resolverBindException(Exception ex, StringBuilder sb, ResultVO result) { BindException be = (BindException) ex; List<FieldError> errorList = be.getBindingResult().getFieldErrors(); for (FieldError error : errorList) { sb.append(error.getObjectName()); sb.append("对象的"); sb.append(error.getField()); sb.append("字段"); sb.append(error.getDefaultMessage()); } addResult(result, "参数传递异常"); } /* * 处理其他异常 */ private void resolverOtherException(Exception ex, StringBuilder sb, ResultVO result) { sb.append(ex.getMessage()); addResult(result, "其他异常"); } /* * 封装code和msg */ private void addResult(ResultVO result, String msg) { result.setMsg(msg); } }

    2. Controller局部异常处理

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

    @RestController public class TestControllerException { @RequestMapping("/conError") public String conError() { int a = 1 / 0; return "this is conError" + a; } /** * 单个controller进行异常处理 * @param e * @return */ @ExceptionHandler(Exception.class) @ResponseBody public String exceptionHandler(Exception e) { System.out.println(e); return "这是controller内的异常处理方法 。。。 "; } }

    mvc-dispatcher-servlet.xml中加

    <context:component-scan base-package="com.example"/>

    3.@ControllerAdvice

    如果单使用2中的@ExceptionHandler,只能在当前Controller中处理异常。但当配合@ControllerAdvice一起使用的时候,则可以全局捕获。

    @ControllerAdvice,是Spring3.2提供的新注解,它是一个Controller增强器,可对controller中被@RequestMapping注解的方法加一些逻辑处理,最常用的就是异常处理。

    需要配合@ExceptionHandler使用。 当将异常抛到controller时,可以对异常进行统一处理,规定返回的json格式或是跳转到一个错误页面。

    @ControllerAdvice public class ControllerExceptionHandler { private Logger logger = LoggerFactory.getLogger(ControllerExceptionHandler.class); @ExceptionHandler(value = Exception.class) @ResponseStatus(HttpStatus.OK) @ResponseBody // 如果使用了@RestControllerAdvice,这里就不需要@ResponseBody了 public Map handler(Exception ex) { logger.error("统一异常处理", ex); Map<String, Object> map = new HashMap<>(); map.put("code", 400); //判断异常的类型,返回不一样的返回值 if(ex instanceof MissingServletRequestParameterException){ map.put("msg","缺少必需参数:"+((MissingServletRequestParameterException) ex).getParameterName()); } else if(ex instanceof BussinessException){ map.put("msg","这是自定义异常"); } return map; } } @RestController public class TestAdvice { @RequestMapping("testException") public String testException() throws Exception{ throw new MissingServletRequestParameterException("name","String"); } @RequestMapping("testBussinessException") public String testMyException() throws BussinessException { throw new BussinessException("i am a BussinessException"); } }

    4.完整项目代码

    可以运行调试的代码:https://github.com/Aiwz1314/StudyDemo/tree/master/StudySpring

    运行效果如下图:

    Processed: 0.068, SQL: 9