一,异常分类
java异常分为"检查"和"非检查"两类,"检查"二字的意思是,代码编译时,编译器会去Check一下有没有进行异常处理(捕获或向上抛),对于归类为需要检查的异常,若没处理,编译就过不去。
初学时常常想exception为啥要这样分类处理呢? 后来才明白,异常不过两种:主观和客观,一个大多数情况下可以避免,一个大多数情况下无法避免。
像NullPointerException这类异常,大多跟程序员素质挂钩(开发好,测试好, 基本不会在系统运行后蹦出来), 基本是可以避免的,java语法当初把它们归类为“非检查”,也算给程序员和编译器省了不少事。
而像IOException这类跟外在环境有关的异常,几乎是不可避免的(指不定哪一天哪一秒网络就挂了),但是当不期而遇时,程序还是要有所作为,所以编译器有必要督促一下程序员,Check一下,看看是否对这些可能不期而至的异常进行了处理。当Exception对象传递到某个节点后,程序就可以执行一些必要措施了,比如:给用户一个友好提示("系统繁忙,请重试")。
二,异常的统一处理
1,服务器处理
下面列举Tomcat和Nginx为例
Tomcat是Servlet容器,主要处理动态请求,在web.xml下配置,按http返回码或Exception类型来处理:
<error-page>
<error-code>404</error-code>
<location>/WEB-INF/views/error/404.jsp</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/WEB-INF/views/error/500.jsp</location>
</error-page>
<error-page>
<exception-type>java.lang.Throwable</exception-type>
<location>/WEB-INF/views/error/throwable.jsp</location>
</error-page>
Nginx,也可以通过Http返回码很方便地指定异常时的返回页面:
server {
listen 80 ;
server_name xx.com ;
root /var/www ;
index index.html ;
error_page 404 /404.html ;
location = /404.html {
root /usr/share/nginx/html;
}
}
2,应用程序框架处理
以Spring boot为例, 在处理接口返回时, 进行全局异常的捕获
1) 自定义业务异常
/**
* 自定义业务异常类
*/
public class BusinessException extends RuntimeException {
private String code;
public BusinessException(String code, String message) {
super(message);
this.code = code;
}
public String getCode() {
return code;
}
public String getMessage() {
return super.getMessage();
}
}
2) 定义接口返回数据结构
/**
* 接口返回数据对象
* @param <T> 业务对象
*/
public class Result<T> implements Serializable {
private String code;
private String message;
private T data;
public Result(String code,String message){
super();
this.code=code;
this.message=message;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
3) 全局捕获处理
@ControllerAdvice
public class ExceptionController {
private Logger logger= LoggerFactory.getLogger(ExceptionController.class);
@ExceptionHandler(value = Exception.class)
@ResponseBody
public Result exceptionOut(Exception e){
logger.error("全局异常捕获,e:{}",e);
Result result=null;
if(e instanceof BusinessException){
result= new Result(((BusinessException) e).getCode(),e.getMessage());
}else{
result= new Result("500","系统异常");
}
return result;
}
}