今天吃饭时,被公司新来的同事问道:“项目controller层里好多都没写try,catch,难道异常不用处理吗?”。虽然正吃饭时被打扰,让我很讨厌,但是既然他诚心诚意的问了,本着爱护(收服)新员工的责任,我还是面带微笑给他讲解了一番:“是这样,异常@#*%*&~...”
讲完,我爱吃的蒜香烤鱼已经凉了,但是我从同事的眼光中看到了对技术的崇拜和敬仰。哎,程序员就是这么朴实无华,且枯燥~
废话讲完,小二,上菜~~
@ControllerAdvice //表示所有被扫描到的controller都有效,相当于给controller中所有的方法写了try public class ControllerExceptionHandler { //日志 private final Logger log = LoggerFactory.getLogger(this.getClass().getName()); /** * 处理运行时的异常,可优化为自定义异常类 */ @ExceptionHandler(RuntimeException.class) @ResponseBody public ResponseEntity handlerException(RuntimeException ex) { log.error("发生业务异常!原因是:{}", ex.getMessage()); return ResponseEntity.error(ex.getMessage()); } /** * 对方法参数校验异常处理方法(仅对于表单提交有效,对于以json格式提交将会失效) * 如果是表单类型的提交,则spring会采用表单数据的处理类进行处理(进行参数校验错误时会抛出BindException异常) */ @ExceptionHandler(BindException.class) @ResponseBody public ResponseEntity handlerBindException(BindException ex) { log.error("valid参数校验异常,提交参数类型form!原因是: {}", ex.getMessage()); return handlerNotValidException(ex); } /** * 对方法参数校验异常处理方法(前端提交的方式为json格式出现异常时会被该异常类处理) * json格式提交时,spring会采用json数据的数据转换器进行处理(进行参数校验时错误是抛出MethodArgumentNotValidException异常) */ @ExceptionHandler(MethodArgumentNotValidException.class) @ResponseBody public ResponseEntity handlerArgumentNotValidException(MethodArgumentNotValidException ex) { log.error("valid参数校验异常,提交参数类型Json!原因是: {}", ex.getMessage()); return handlerNotValidException(ex); } @ExceptionHandler(Exception.class) @ResponseBody public ResponseEntity handlerException2(Exception ex) { log.error("发生未知异常!原因是: {}", ex.getMessage()); return ResponseEntity.error(ex.getMessage()); } /** * valid校验,其参数错误异常的统一处理 * @param e */ public ResponseEntity handlerNotValidException(Exception e) { log.debug("begin resolve argument exception"); BindingResult result; if (e instanceof BindException) { BindException exception = (BindException) e; result = exception.getBindingResult(); } else { MethodArgumentNotValidException exception = (MethodArgumentNotValidException) e; result = exception.getBindingResult(); } // Map<String, Object> maps = getStringObjectMap(result); List<String> list = getStringObjectList(result); return ResponseEntity.error(list.toString()); } /** * 这里只返回错误原因(建议) * 例子:[ID不能为空] */ private List<String> getStringObjectList(BindingResult result) { List<String> list; if (result.hasErrors()) { List<FieldError> fieldErrors = result.getFieldErrors(); list = new ArrayList<>(fieldErrors.size()); fieldErrors.forEach(error -> { list.add(error.getDefaultMessage()); }); } else { list = Collections.EMPTY_LIST; } return list; } /** * 这里是返回:字段名=错误原因(不建议) */ private Map<String, Object> getStringObjectMap(BindingResult result) { Map<String, Object> maps; if (result.hasErrors()) { List<FieldError> fieldErrors = result.getFieldErrors(); maps = new HashMap<>(fieldErrors.size()); fieldErrors.forEach(error -> { maps.put(error.getField(), error.getDefaultMessage()); }); } else { maps = Collections.EMPTY_MAP; } return maps; } }
我个人比较喜欢使用@Valid注解来校验数据,所以这里全局处理了其相关的异常。对于编写全局异常,非常考验程序员对于java异常的理解和运用。异常哪个地方抛,是谁抛,抛给谁,谁处理,这些都是难点,但是如果能吃透,基本上是个合格的程序员了。期望你能扶摇直上九万里~
作者:杨飞只是太过正经