【java异常】 @ControllerAdvice+@ExceptionHandler全局异常处理

查看 @ControllerAdvice源码可见,添加了@Component;
则@ControllerAdvice是spring的一个组件,可理解为一个实体Bean,
可被 <context:component-scan base-package="com.hesvit" />
扫描到即可;

@ControllerAdvice 可以实现三个方面的功能:

本文主要介绍全局异常处理
在之前的SpringMVC项目中,经常是用try…catch…来进行异常处理,实例代码如下:

@RequestMapping(value="/testException")
	public RestBaseResult<Object> testExceptionLogin(@RequestParam String name,@RequestParam String password) {
		RestBaseResult<Object> result = new RestBaseResult<Object>();
		try {
		    if (!password.equals("123456")) {
		    	result.setCode(100011);
				result.setMsg("密码错误");
            } 
            
			doSomething..........

		sdOrderService.testExceptionLogin(name,password);
		} catch (Exception e) {
			logger.error("----controller.login.errorInfo>:{}",e);
			result.setCode(-1);
			result.setMsg("服务器内部错误");
		}
		return result;
	}

try…catch…异常的缺点: 代码冗余,不利于维护,在拦截器中的定义的错误消息无法返回到页面

接下来介绍一个@ControllerAdvice + @ExceptionHandler 进行全局的 Controller 层异常处理

一、优缺点
优点:
异常进行统一处理;
减少模板代码,减少编码量,提升扩展性和可维护性;
Interceptor(拦截器)层的异常也可以被处理
缺点:
只能处理 未捕获(往外抛)的异常,对于 过滤器(Filter),Spring 框架层的异常,就无能为力了。

为了测试,所有的类都定义在exception包下:
过滤器和拦截器的配置为贴出来了
在这里插入图片描述

/**
 * 全局异常处理类
 *
 */
@ControllerAdvice
public class GlobalExceptionHandler {

	private Logger logger = LoggerFactory.getLogger(this.getClass());
	
	@ResponseStatus(code=HttpStatus.INTERNAL_SERVER_ERROR)  //自定义浏览器返回状态码,通常不需要自定义
	@ExceptionHandler()
	public @ResponseBody ExceptionResult handleException(Exception e,
			HttpServletRequest request, HttpServletResponse response) {
		// TODO 记录log日志
        e.printStackTrace();
        logger.error("---------GlobalExceptionHandler.Exception.errorinfo>:{}",e);
        
        ExceptionResult result = new ExceptionResult();
        result.setData(e.getMessage());
        return result;
	}
	

	@ExceptionHandler({BusinessException.class})
	public @ResponseBody ExceptionResult handleServiceException(BusinessException e,
			HttpServletRequest request, HttpServletResponse response) {
		// TODO 记录log日志
        e.printStackTrace();
        logger.error("---------GlobalExceptionHandler.BusinessException.errorinfo>:{}",e);
        
		ExceptionResult result = new ExceptionResult();
		result.setCode(e.getCode());
		result.setMsg(e.getMsg());
		result.setData(e.getMessage());
		return result;
	}
	
	
	@ExceptionHandler({NullPointerException.class})
	public @ResponseBody ExceptionResult handleServiceException(NullPointerException e,
			HttpServletRequest request, HttpServletResponse response) {
		// 记录log日志
		e.printStackTrace();
		logger.error("---------GlobalExceptionHandler.NullPointerException.errorinfo>:{}",e);
		
		ExceptionResult result = new ExceptionResult();
		result.setMsg("空指针异常");
		result.setData(e.getMessage());
		return result;
	}

}
/**
 * -------------------BusinessException.java----------------------------------------------------
 * 业务异常
 */
@Data
@EqualsAndHashCode(callSuper=false)
public class BusinessException extends RuntimeException {

	private static final long serialVersionUID = 1L;
	
	/** 异常码 */
	private int code;
	/** 异常提示内容 */
	private String msg;
	
	
	public BusinessException() {
		super();
	}
	public BusinessException(String msg) {
		super(msg);
	}
	public BusinessException(int code,String msg) {
		this.code = code;
		this.msg = msg;
	}
}
/**
 * -------------------ExceptionCode.java----------------------------------------------------
 * 自定义异常码
 */
public class ExceptionCode {
	
	/** 用户名错误 */
	public static final int USERNAME_ERROR = 100010;
	/** 密码错误 */
	public static final int PWD_ERROR = 100011;
	/**
	 * 根据code获取MSG
	 * @param code
	 * @return
	 */
	public static String getMsgByCode(int code) {
		String msg = "Server internal error";
		switch (code) {
			case USERNAME_ERROR:
				msg = "用户名错误";
				break;
			case PWD_ERROR:
				msg = "密码错误";
				break;

			default:
				break;
		}
		return msg;
	}
}
/**
 * --------------------------异常结果----------------------------
 *
 */
@Data
public class ExceptionResult implements Serializable{
	
	private static final long serialVersionUID = 1L;
	
	// -- 返回代码定义 --//
	// 按项目的规则进行定义, 比如4xx代表客户端参数错误,5xx代表服务端业务错误等.
	public static final int SUCCESS = 0;
	public static final int PARAMETER_ERROR = -1;
	public static final int SYSTEM_ERROR = 500;
	public static final String SYSTEM_SUCCESS_MESSAGE = "operate success";
	public static final String SYSTEM_ERROR_MESSAGE = "Runtime unknown internal error.";

	// -- WsResult基本属性 --//
	private int code = PARAMETER_ERROR;
	private String msg = SYSTEM_ERROR_MESSAGE;
	private String currentTime = DateUtils.convertDateToString(DateUtils.DATETIME, new Date());
	private Object data;
}
/**
 * ---------------过滤器
 */
public class TestFilter implements Filter {

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {}

	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		String name = request.getParameter("name");
		if (!name.equals("admin")) {
			throw new BusinessException(222, "用户名错误");
		} 
		chain.doFilter(request, response);// 调用接口
	}

	@Override
	public void destroy() {}

}
/**
 * ---------------拦截器
 */
public class TestInterceptor implements HandlerInterceptor {
	
	protected Logger logger = LoggerFactory.getLogger(getClass());
	
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		
		Map<String,String[]> map = request.getParameterMap();
		Map<String,String> param = new HashMap<String,String>();
		
		for(Entry<String, String[]> entry : map.entrySet()) {
			String [] values =  entry.getValue();
			String key = entry.getKey();
			if(values[0] != null) {
				param.put(key, values[0]);
			}
		}
		
		String sign = param.get("sign");
		if (!sign.equals("aaaaaaaaa")) {
			throw new BusinessException(333, "签名错误");
		}
		
		return true;
	}

	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {
	}

	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
			throws Exception {
	}
	
}

测试的controller和service如下

@Controller
@RequestMapping("/user")
public class UserController extends BaseController{
	@Autowired
	private UserService userService;
	
	@RequestMapping(value="/testException")
	public RestBaseResult<Object> testExceptionLogin(@RequestParam String name,@RequestParam String password,Model model) {
		
		Map<String, Object> map = model.asMap();
		logger.info("------>:map{}",map);
		
		RestBaseResult<Object> result = new RestBaseResult<Object>();
		if (password.equals("123456")) 
			throw new BusinessException(ExceptionCode.PWD_ERROR,ExceptionCode.getMsgByCode(ExceptionCode.PWD_ERROR));
		
		
		userService.testExceptionLogin(name,password);
		
		return result;
	}
}
----------------service----------------------
@service
public class UserServiceImpl implements UserService {
@Override
	public void testExceptionLogin(String name,String pwd) {
		User user = userDao.selectByName(name);
		if (user == null) {
			throw new BusinessException(ExceptionCode.USERNAME_ERROR,ExceptionCode.getMsgByCode(ExceptionCode.USERNAME_ERROR));
		}
	}
	
}

通过Post满工具测试的结果如下图:
处理Filter中定义的异常无法被@ExceptionHandler处理,其他的都可以,有兴趣的可以试试
在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值