java基于spring注解AOP的异常处理的方法
一、前言
项目刚刚开发的时候,并没有做好充足的准备。开发到一定程度的时候才会想到还有一些问题没有解决。就比如今天我要说的一个问题:异常的处理。写程序的时候一般都会通过try...catch...finally对异常进行处理,但是我们真的能在写程序的时候处理掉所有可能发生的异常吗?以及发生异常的时候执行什么逻辑,返回什么提示信息,跳转到什么页面,这些都是要考虑到的。
二、基于@ControllerAdvice(加强的控制器)的异常处理
@ControllerAdvice注解内部使用@ExceptionHandler、@InitBinder、@ModelAttribute注解的方法应用到所有的@RequestMapping注解的方法。本例子中使用ExceptionHandler应用到所有@RequestMapping注解的方法,处理发生的异常。
示例代码:
importorg.slf4j.Logger; importorg.slf4j.LoggerFactory; importorg.springframework.http.HttpHeaders; importorg.springframework.http.HttpStatus; importorg.springframework.http.ResponseEntity; importorg.springframework.util.StringUtils; importorg.springframework.web.bind.annotation.ControllerAdvice; importorg.springframework.web.bind.annotation.ExceptionHandler; importorg.springframework.web.bind.annotation.ResponseBody; importcom.hjz.exception.ServiceException; importcom.hjz.exception.utils.ExceptionUtils; @ResponseBody publicclassExceptionAdvice{ privatestaticfinalLoggerLOGGER=LoggerFactory.getLogger(ExceptionAdvice.class); /** *拦截web层异常,记录异常日志,并返回友好信息到前端 *目前只拦截Exception,是否要拦截Error需再做考虑 * *@parame异常对象 *@return异常提示 */ @ExceptionHandler(Exception.class) publicResponseEntity<String>handleException(Exceptione){ //不需要再记录ServiceException,因为在service异常切面中已经记录过 if(!(einstanceofServiceException)){ LOGGER.error(ExceptionUtils.getExcTrace(e)); } HttpHeadersheaders=newHttpHeaders(); headers.set("Content-type","text/plain;charset=UTF-8"); headers.add("icop-content-type","exception"); Stringmessage=StringUtils.isEmpty(e.getMessage())?"系统异常!!":e.getMessage(); returnnewResponseEntity<>(message,headers,HttpStatus.OK); } }
如果不起作用,请检查spring-mvc的配置文件,是否有ControllerAdvice的如下配置
<context:component-scanbase-package="com.sishuok.es"use-default-filters="false"> <context:include-filtertype="annotation"expression="org.springframework.stereotype.Controller"/> <context:include-filtertype="annotation"expression="org.springframework.web.bind.annotation.ControllerAdvice"/> </context:component-scan>
三、基于AOP的异常处理
1.处理controller层的异常WebExceptionAspect.java
importorg.aspectj.lang.annotation.AfterThrowing; importorg.aspectj.lang.annotation.Aspect; importorg.aspectj.lang.annotation.Pointcut; importorg.slf4j.Logger; importorg.slf4j.LoggerFactory; importorg.springframework.stereotype.Component; importorg.springframework.util.StringUtils; importorg.springframework.web.context.request.RequestContextHolder; importorg.springframework.web.context.request.ServletRequestAttributes; importcom.hjz.exception.ServiceException; importcom.hjz.exception.utils.ExceptionUtils; importjavax.servlet.http.HttpServletResponse; importjava.io.IOException; importjava.io.PrintWriter; /** *web异常切面 *默认springaop不会拦截controller层,使用该类需要在spring公共配置文件中注入改bean, *另外需要配置<aop:aspectj-autoproxyproxy-target-class="true"/> */ @Aspect publicclassWebExceptionAspect{ privatestaticfinalLoggerLOGGER=LoggerFactory.getLogger(WebExceptionAspect.class); @Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping)") privatevoidwebPointcut(){} /** *拦截web层异常,记录异常日志,并返回友好信息到前端 *目前只拦截Exception,是否要拦截Error需再做考虑 * *@parame异常对象 */ @AfterThrowing(pointcut="webPointcut()",throwing="e") publicvoidhandleThrowing(Exceptione){ //不需要再记录ServiceException,因为在service异常切面中已经记录过 if(!(einstanceofServiceException)){ LOGGER.error(ExceptionUtils.getExcTrace(e)); } StringerrorMsg=StringUtils.isEmpty(e.getMessage())?"系统异常":e.getMessage(); writeContent(errorMsg); } /** *将内容输出到浏览器 * *@paramcontent输出内容 */ privatevoidwriteContent(Stringcontent){ HttpServletResponseresponse=((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getResponse(); response.reset(); response.setCharacterEncoding("UTF-8"); response.setHeader("Content-Type","text/plain;charset=UTF-8"); response.setHeader("icop-content-type","exception"); PrintWriterwriter=null; try{ writer=response.getWriter(); }catch(IOExceptione){ e.printStackTrace(); } writer.print(content); writer.flush(); writer.close(); } }
2.处理service层的异常ServiceExceptionAspect.java
importorg.aspectj.lang.JoinPoint; importorg.aspectj.lang.annotation.AfterThrowing; importorg.aspectj.lang.annotation.Aspect; importorg.aspectj.lang.annotation.Pointcut; importorg.slf4j.Logger; importorg.slf4j.LoggerFactory; importorg.springframework.stereotype.Component; importorg.springframework.util.StringUtils; importcom.hjz.exception.ServiceException; importcom.hjz.exception.utils.ExceptionUtils; @Aspect publicclassServiceExceptionAspect{ privatestaticfinalLoggerLOGGER=LoggerFactory.getLogger(ServiceExceptionAspect.class); /** *@within(org.springframework.stereotype.Service),拦截带有@Service注解的类的所有方法 *@annotation(org.springframework.web.bind.annotation.RequestMapping),拦截带有@RquestMapping的注解方法 */ @Pointcut("@within(org.springframework.stereotype.Service)&&execution(public**(..))") privatevoidservicePointcut(){} /** *拦截service层异常,记录异常日志,并设置对应的异常信息 *目前只拦截Exception,是否要拦截Error需再做考虑 * *@parame异常对象 */ @AfterThrowing(pointcut="servicePointcut()",throwing="e") publicvoidhandle(JoinPointpoint,Exceptione){ LOGGER.error(ExceptionUtils.getExcTrace(e)); Stringsignature=point.getSignature().toString(); StringerrorMsg=getMessage(signature)==null?(StringUtils.isEmpty(e.getMessage())?"服务异常":e.getMessage()):getMessage(signature); thrownewServiceException(errorMsg,e); } /** *获取方法签名对应的提示消息 * *@paramsignature方法签名 *@return提示消息 */ privateStringgetMessage(Stringsignature){ returnnull; } }
3.使用方式,在spring的公共配置文件中加入如下配置:
<aop:aspectj-autoproxyproxy-target-class="true"/> <beanclass="com.hjz.exception.aspect.ServiceExceptionAspect"/> <beanclass="com.hjz.exception.aspect.WebExceptionAspect"/>
或者自定义一个注册类,ServiceExceptionAspect.java和WebExceptionAspect.java都加入@Component注解
importorg.springframework.context.annotation.ComponentScan; importorg.springframework.context.annotation.Configuration; importorg.springframework.context.annotation.EnableAspectJAutoProxy; /** *异常相关bean注册类 */ @Configuration @EnableAspectJAutoProxy @ComponentScan("com.hjz.exception.aspect") publicclassExceptionConfig{ }
@Aspect @Component publicclassWebExceptionAspect{ .......... } @Aspect @Component publicclassServiceExceptionAspect{ ......... }
四、疑惑
@within(org.springframework.stereotype.Service),拦截带有@Service注解的类的所有方法
@annotation(org.springframework.web.bind.annotation.RequestMapping),拦截带有@RquestMapping的注解方法
五、测试
分别编写controller层和service层的异常测试类。这个很简单,在方法里简单的抛一下异常就可以了。最后验证一下,异常发生的时候有没有执行@AfterThrowing对应的方法就好了。具体还是看我写的demo吧,嘿嘿嘿!!!
完整项目下载地址:Spring-AOP_jb51.rar
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。