1.什么是统一异常处理?
软件开发过程中,不可避免的是需要处理各种异常,就我自己来说,至少有一半以上的时间都是在处理各种异常情况,所以代码中就会出现大量的try {...} catch {...} finally {...}
代码块,不仅有大量的冗余代码,而且还影响代码的可读性。再回到我们的微服务中,我们也是使用这样的形式处理异常,那么我们导入文件的时候某列的数据不符合我们的标准,我们就可以自定义异常进行处理抛出,用户就会看到我们的友好提示(自定义的异常提醒),而不是看到一些异常信息.
2.怎么进行自定义异常处理?
首先我们得定义自己的异常信息,下面ApplicationException类,然后我们定义一些变量,比如信息类型:1警告 2错误 我们正常导入excel的警告提示,我们是不应该直接抛出异常信息的,这样就需要我们自己做统一异常处理.这儿我们就定义一个字段 是否记录到系统.这儿我们做一个自定义的拦截器来拦截我们项目中的异常抛出,这儿我们定义一个拦截器GlobalDefaultExceptonHandler来处理异常.这儿需要普及一下,我知道处理异常的方式有三种.
第一:使用该注解有一个不好的地方就是:进行异常处理的方法必须与出错的方法在同一个Controller里面。使用如下:
@Controller
2 public class GlobalController {
3
4 /**
5 * 处理myexception异常的方法
6 * @return
7 */
8 @ExceptionHandler({MyException.class})
9 public String exception(MyException e) {
10 System.out.println(e.getMessage());
11 e.printStackTrace();
12 return "exception";
13 }
14
15 @RequestMapping("testMyException")
16 public void test() {
17 throw new MyException("我们自己的异常出问题了!");
18 }
19 }
从上面的简单的应用,我们可以看出, 这种处理异常的方式确实可以使用,但是需要写在出错方法的同一个controller里, 并不是我们想要的统一异常处理pass掉
第二: 使用 @ControllerAdvice+ @ ExceptionHandler 注解 进行异常处理
上面我们说到 @ ExceptionHandler 需要进行异常处理的方法必须与出错的方法在同一个Controller里面。那么当代码加入了 @ControllerAdvice,则不需要必须在同一个 controller 中了。这也是 Spring 3.2 带来的新特性。从名字上可以看出大体意思是控制器增强。 也就是说,@controlleradvice + @ ExceptionHandler 也可以实现全局的异常捕捉。代码演示如下:
1 @ControllerAdvice
2 @ResponseBody
3 public class WebExceptionHandle {
4 private static Logger logger = LoggerFactory.getLogger(WebExceptionHandle.class);
5 /**
6 * 400 - Bad Request
7 */
8 @ResponseStatus(HttpStatus.BAD_REQUEST)
9 @ExceptionHandler(HttpMessageNotReadableException.class)
10 public ServiceResponse handleHttpMessageNotReadableException(HttpMessageNotReadableException e) {
11 logger.error("参数解析失败", e);
12 return ServiceResponseHandle.failed("could_not_read_json");
13 }
14
15 /**
16 * 405 - Method Not Allowed
17 */
18 @ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
19 @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
20 public ServiceResponse handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
21 logger.error("方法不允许", e);
22 return ServiceResponseHandle.failed("request_method_not_supported");
23 }
24
35 /**
36 * 500 - Internal Server Error
37 */
38 @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
39 @ExceptionHandler(Exception.class)
40 public ServiceResponse handleException(Exception e) {
41 if (e instanceof BusinessException){
42 return ServiceResponseHandle.failed("BUSINESS_ERROR", e.getMessage());
43 }
44
45 logger.error("服务器内部异常", e);
46 e.printStackTrace();
47 return ServiceResponseHandle.failed("server_error");
48 }
49 }
第三:实现HandlerExceptionResolver 接口进行异常处理,啥也不用说,看代码纯手敲代码 没有复制过来 可能会敲错)
@RestControllerAdvice
public class GlobalDefaultExceptionHandler implements HandlerExceptionResolver{
@AutoWired
BizCommonService BizCommonService;//处理异常日志service 根据自己的系统需要是否存储
@Override
Public ModelAndView resolveException (HttpServletRequest request,
HttpServletResponse, Object handler, Exception e ){
ModelAndView model = new ModelAndView();
if(hand instanceof HandlerMethod){
HandlerMethod hand = (HandlerMethod)handler;
Method method = hand.getMethod();
String methodName = method.getName();
//通过反射获取该controller方法中是否重写了getMenuName方法 为了获取菜单名
Class<?> beanType = hand.getBeanType;
String menuName ="";
try{
Object newInstance = beanType.newInstance();
Method method2 = beanType.getMethod("getMenuName");
Object invoke = method2.invoke(newInstance);
menuName = invoke.toString();
}catch(Exception eee){
menuName = "未重写获取菜单的方法";
}
if(e instanceof ApplicationException){//ApplicationException属于我们自定义的异常类
//属于自定义异常
}else{
//使用我们自定义的bizCommonService 进行保存异常信息 异常方法 异常claas类 异常信息
}
}
}
}
很显然我们项目中用的是实现HandlerExceptionResolver的方法进行了异常处理。
最后奉献上ApplicationException自定义的异常类