【springboot异常处理】用异常信息枚举类处理异常,使用自定义异常封装异常对象,返回统一异常处理结果
1.目录:
#
- 异常信息枚举类
- 自定义异常类
- 自定义响应数据
- 全局异常处理类
- 测试
- 总结
异常信息枚举类
由于在业务中,有很多异常,针对不同的业务,可能给出的提示信息不同,所以为了方便项目异常信息管理,我们一般会定义一个异常信息枚举类。
public enum BusinessMsgEnum {
/** 参数异常*/
PARMETER_EXCEPTION("102", "参数异常!"),
/** 等待超时*/
SERVICE_TIME_OUT("103", "服务调用超时!"),
/** 参数过大*/
PARMETER_BIG_EXCEPTION("102", "输入的图片数量不能超过50 张!"),
/** 500 : 一劳永逸的提示也可以在这定义*/
UNEXPECTED_EXCEPTION("500", "系统发生异常,请联系管理员!");
// 还可以定义更多的业务异常
/** * 消息码 */
private String code;
/** * 消息内容 */
private String msg;
private BusinessMsgEnum(String code, String msg) {
this.code = code;
this.msg = msg;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
// set get 方法
}
自定义异常类
public class BusinessErrorException extends RuntimeException{
private static final long serialVersionUID = -7480022450501760611L;
/** * 异常码 */
private String code;
/** * 异常提示信息 */
private String message;
public BusinessErrorException(BusinessMsgEnum businessMsgEnum) {
this.code = businessMsgEnum.getCode();
this.message = businessMsgEnum.getMsg();
}
// 在构造方法中,传入我们上面自定义的异常枚举类,所以在项目中,如果有新的异常信
// 息需要添加,我们直接在枚举类中添加即可,很方便,做到统一维护,然后再拦截该异
// 常时获取即可。
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
@Override
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
自定义响应数据
@Data
@JsonInclude(value = JsonInclude.Include.NON_NULL)//这样配置了以后为null的数据就不会再返回给前端了。比如data为null时前端不会收到data这一数据
public class JSONResult {
/** * * @Description: 自定义响应数据结构 * 这个类是提供给门户,ios,安卓,微信商城用的 * 门户接受此类数据后需要使用本类的方法转换成对于的数据类型格式(类,或者list) * 其他自行处理 * 200:表示成功 * 500:表示错误,错误信息在msg字段中 * 501:bean验证错误,不管多少个错误都以map形式返回 * 502:拦截器拦截到用户token出错 * 555:异常抛出信息 * Copyright: Copyright (c) 2016 * Company:Nathan.Lee.Salvatore */
// 定义jackson对象
private final ObjectMapper MAPPER = new ObjectMapper();
// 响应业务状态
private Integer status;
// 响应消息
private String msg;
// 响应中的数据
private Object data;
private String ok; // 不使用
public JSONResult build(Integer status, String msg, Object data) {
return new JSONResult(status, msg, data);
}
public JSONResult ok(Object data) {
return new JSONResult(data);
}
public JSONResult ok() {
return new JSONResult(null);
}
public JSONResult errorMsg(String msg) {
return new JSONResult(500, msg, null);
}
public JSONResult errorMap(Object data) {
return new JSONResult(501, "error", data);
}
public JSONResult errorTokenMsg(String msg) {
return new JSONResult(502, msg, null);
}
public JSONResult errorException(String msg) {
return new JSONResult(555, msg, null);
}
public JSONResult() {
}
// public static LeeJSONResult build(Integer status, String msg) {
// return new LeeJSONResult(status, msg, null);
// }
public JSONResult(Integer status, String msg, Object data) {
this.status = status;
this.msg = msg;
this.data = data;
}
public JSONResult(Integer status, String msg) {
this.status = status;
this.msg = msg;
}
public JSONResult(Object data) {
this.status = 200;
this.msg = "OK";
this.data = data;
}
public Boolean isOK() {
return this.status == 200;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
/** * * @Description: 将json结果集转化为LeeJSONResult对象 * 需要转换的对象是一个类 * @param jsonData * @param clazz * @return * */
public JSONResult formatToPojo(String jsonData, Class<?> clazz) {
try {
if (clazz == null) {
return MAPPER.readValue(jsonData, JSONResult.class);
}
JsonNode jsonNode = MAPPER.readTree(jsonData);
JsonNode data = jsonNode.get("data");
Object obj = null;
if (clazz != null) {
if (data.isObject()) {
obj = MAPPER.readValue(data.traverse(), clazz);
} else if (data.isTextual()) {
obj = MAPPER.readValue(data.asText(), clazz);
}
}
return build(jsonNode.get("status").intValue(), jsonNode.get("msg").asText(), obj);
} catch (Exception e) {
return null;
}
}
/** * * @Description: 没有object对象的转化 * @param json * @return * */
public JSONResult format(String json) {
try {
return MAPPER.readValue(json, JSONResult.class);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/** * * @Description: Object是集合转化 * 需要转换的对象是一个list * @param jsonData * @param clazz * @return * */
public JSONResult formatToList(String jsonData, Class<?> clazz) {
try {
JsonNode jsonNode = MAPPER.readTree(jsonData);
JsonNode data = jsonNode.get("data");
Object obj = null;
if (data.isArray() && data.size() > 0) {
obj = MAPPER.readValue(data.traverse(),
MAPPER.getTypeFactory().constructCollectionType(List.class, clazz));
}
return build(jsonNode.get("status").intValue(), jsonNode.get("msg").asText(), obj);
} catch (Exception e) {
return null;
}
}
public String getOk() {
return ok;
}
public void setOk(String ok) {
this.ok = ok;
}
}
全局异常处理类
全局异常处理类,使用@ControllerAdvice来表示它为全局异常
@ControllerAdvice 注解包含了@Component 注解,说明在Spring Boot 启动时,也会把该类作为组件交给Spring 来管理。除此之外,该注解还有个basePackages 属性,该属性是用来拦截哪个包中的异常信息,一般我们不指定这个属性,我们拦截项目工程中的所有异常
@ResponseBody 注解是为了异常处理完之后给调用方输出一个json 格式的封装数据。
在项目中如何使用呢?Spring Boot 中很简单,在方法上通过@ExceptionHandler 注解来指定具体的异常,然后在方法中处理该异常信息,最后将结过统一的json 结构体返回给调用者。
@ControllerAdvice
@ResponseBody
//全局异常处理类,使用@ControllerAdvice来表示它为全局异常
//@ControllerAdvice 注解包含了@Component 注解,说明在Spring Boot 启动时,也会把该类作为组件交给Spring 来管理。除此之外,该注解还有个basePackages 属性,该属性是用来拦截哪个包中的异常信息,一般我们不指定这个属性,我们拦截项目工程中的所有异常
public class GlobalExceptionHandler {
// 打印log
private static final Logger logger =
LoggerFactory.getLogger(ExceptionHandler.class);
/** * 缺少请求参数异常 * @param ex HttpMessageNotReadableException * @return */
@ExceptionHandler(MissingServletRequestParameterException.class)
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
public JSONResult handleHttpMessageNotReadableException(
MissingServletRequestParameterException ex) {
logger.error("缺少请求参数,{}", ex.getMessage());
return new JSONResult(400, "缺少必要的请求参数");
}
@ExceptionHandler(NullPointerException.class)//空指针异常
@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
public JSONResult handleTypeMismatchException(NullPointerException
ex) {
logger.error("空指针异常,{}", ex.getMessage());
return new JSONResult(500, "空指针异常了");
}
/* 自定义异常 */
@ExceptionHandler(BusinessErrorException.class)
@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
public JSONResult handleBusinessError(BusinessErrorException ex) {
String code = ex.getCode();
String message = ex.getMessage();
return new JSONResult(Integer.parseInt(code), message);
}
}
测试
定义一个controller测试类用于测试刚才定义的异常。
@RestController
public class ExceptionController {
private static final Logger logger =
LoggerFactory.getLogger(ExceptionController.class);
// 在业务代码中,我们可以直接模拟一下抛出业务异常,测试一下
@GetMapping("/business")
public JSONResult testException() {
try {
int i = 1 / 0;
} catch (Exception e) {
throw new
BusinessErrorException(BusinessMsgEnum.UNEXPECTED_EXCEPTION);
}
return new JSONResult();
}
}
总结
此文主要讲解了Spring Boot 的全局异常处理,包括异常信息的封装、异常信息的捕获和处理,以及在实际项目中,我们用到的自定义异常枚举类和业务异常的捕获与处理,在项目中运用的非常广泛,基本上每个项目中都需要做全局异常处理。
还没有评论,来说两句吧...