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
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。