注解ControllerAdvice配合ExceptionHandler实现全局异常处理。当将异常抛出时,可以对异常进行统一处理,规定返回的json格式或是跳转到一个错误页面。
- 第一步,定义一个全局异常处理Hanlder
@ControllerAdvice
public class GlobalExceptionHanlder {
//
// @Autowired
// private Tracer tracer;
private static final Logger LOGGER = LoggerFactory.getLogger(GlobalExceptionHanlder.class);
@ResponseStatus(HttpStatus.OK)
@ExceptionHandler(value = Throwable.class)
@ResponseBody
public RestResponse<Object> handler(HttpServletRequest req, Throwable throwable){
LOGGER.error(throwable.getMessage(),throwable);
// tracer.addTag(Span.SPAN_ERROR_TAG_NAME, ExceptionUtils.getExceptionMessage(throwable));
// System.out.println(tracer.getCurrentSpan().getTraceId());
RestCode restCode = Exception2CodeRepo.getCode(throwable);
RestResponse<Object> response = new RestResponse<Object>(restCode.code,restCode.msg);
return response;
}
}
- 第二步,定义异常类型转换返回代码类
public class Exception2CodeRepo {
private static final ImmutableMap<Object, RestCode> MAP = ImmutableMap.<Object, RestCode>builder()
.put(IllegalParamsException.Type.WRONG_PAGE_NUM,RestCode.WRONG_PAGE)
.put(IllegalStateException.class,RestCode.UNKNOWN_ERROR)
.put(UserException.Type.USER_NOT_LOGIN,RestCode.TOKEN_INVALID)
.put(UserException.Type.USER_NOT_FOUND,RestCode.USER_NOT_EXIST)
.put(UserException.Type.USER_AUTH_FAIL,RestCode.USER_NOT_EXIST).build();
private static Object getType(Throwable throwable){
try {
return FieldUtils.readDeclaredField(throwable, "type", true);
} catch (Exception e) {
return null;
}
}
public static RestCode getCode(Throwable throwable) {
if (throwable == null) {
return RestCode.UNKNOWN_ERROR;
}
Object target = throwable;
if (throwable instanceof WithTypeException) {
Object type = getType(throwable);
if (type != null ) {
target = type;
}
}
RestCode restCode = MAP.get(target);
if (restCode != null) {
return restCode;
}
Throwable rootCause = ExceptionUtils.getRootCause(throwable);
if (rootCause != null) {
return getCode(rootCause);
}
return restCode.UNKNOWN_ERROR;
}
}
- 第三步,自定义异常类,继承RuntimeException
public class IllegalParamsException extends RuntimeException implements WithTypeException{
private static final long serialVersionUID = 1L;
private Type type;
public IllegalParamsException(){
}
public IllegalParamsException(Type type,String msg){
super(msg);
this.type = type;
}
public Type type(){
return type;
}
public enum Type{
WRONG_PAGE_NUM,WRONG_TYPE
}
}
public class UserException extends RuntimeException implements WithTypeException{
private static final long serialVersionUID = 1L;
private Type type;
public UserException(String message) {
super(message);
this.type = Type.LACK_PARAMTER;
}
public UserException(Type type, String message) {
super(message);
this.type = type;
}
public Type type(){
return type;
}
public enum Type{
WRONG_PAGE_NUM,LACK_PARAMTER,USER_NOT_LOGIN,USER_NOT_FOUND,USER_AUTH_FAIL;
}
}
/**
* 包含类型的异常
*/
public interface WithTypeException {
}
- 第四步,定义返回值枚举类
public enum RestCode {
OK(0,"ok"),
UNKNOWN_ERROR(1,"未知异常"),
TOKEN_INVALID(2,"TOKEN失效"),
USER_NOT_EXIST(3,"用户不存在"),
WRONG_PAGE(10100,"页码不合法"),
LACK_PARAMS(10101,"缺少参数");
public final int code;
public final String msg;
private RestCode(int code,String msg){
this.code = code;
this.msg = msg;
}
}
- 第五步,业务代码中异常抛出
public User getLoginedUserByToken(String token) {
Map<String, String> map = null;
try {
map = JwtHelper.verifyToken(token);
} catch (Exception e) {
throw new UserException(Type.USER_NOT_LOGIN,"User not login");
}
String email = map.get("email");
Long expired = redisTemplate.getExpire(email);
if (expired > 0L) {
renewToken(token, email);
User user = getUserByEmail(email);
user.setToken(token);
return user;
}
throw new UserException(Type.USER_NOT_LOGIN,"user not login");
}
结果:{"code":2,"msg":"TOKEN失效","result":null}