当前位置: 移动技术网 > IT编程>开发语言>Java > java基于spring注解AOP的异常处理的方法

java基于spring注解AOP的异常处理的方法

2019年07月22日  | 移动技术网IT编程  | 我要评论

一、前言

项目刚刚开发的时候,并没有做好充足的准备。开发到一定程度的时候才会想到还有一些问题没有解决。就比如今天我要说的一个问题:异常的处理。写程序的时候一般都会通过try...catch...finally对异常进行处理,但是我们真的能在写程序的时候处理掉所有可能发生的异常吗? 以及发生异常的时候执行什么逻辑,返回什么提示信息,跳转到什么页面,这些都是要考虑到的。

二、基于@controlleradvice(加强的控制器)的异常处理

@controlleradvice注解内部使用@exceptionhandler、@initbinder、@modelattribute注解的方法应用到所有的 @requestmapping注解的方法。本例子中使用exceptionhandler应用到所有@requestmapping注解的方法,处理发生的异常。

示例代码:

import org.slf4j.logger;
import org.slf4j.loggerfactory;
import org.springframework.http.httpheaders;
import org.springframework.http.httpstatus;
import org.springframework.http.responseentity;
import org.springframework.util.stringutils;
import org.springframework.web.bind.annotation.controlleradvice;
import org.springframework.web.bind.annotation.exceptionhandler;
import org.springframework.web.bind.annotation.responsebody;

import com.hjz.exception.serviceexception;
import com.hjz.exception.utils.exceptionutils;

@responsebody
public class exceptionadvice {
 private static final logger logger = loggerfactory.getlogger(exceptionadvice.class);

 /**
  * 拦截web层异常,记录异常日志,并返回友好信息到前端
  * 目前只拦截exception,是否要拦截error需再做考虑
  *
  * @param e 异常对象
  * @return 异常提示
  */
 @exceptionhandler(exception.class)
 public responseentity<string> handleexception(exception e) {
  //不需要再记录serviceexception,因为在service异常切面中已经记录过
  if (!(e instanceof serviceexception)) {
   logger.error(exceptionutils.getexctrace(e));
  }

  httpheaders headers = new httpheaders();
  headers.set("content-type", "text/plain;charset=utf-8");
  headers.add("icop-content-type", "exception");
  string message = stringutils.isempty(e.getmessage()) ? "系统异常!!" : e.getmessage();
  return new responseentity<>(message, headers, httpstatus.ok);
 }
}

如果不起作用,请检查 spring-mvc的配置文件,是否有controlleradvice的如下配置

<context:component-scan base-package="com.sishuok.es" use-default-filters="false"> 
  <context:include-filter type="annotation" expression="org.springframework.stereotype.controller"/> 
  <context:include-filter type="annotation" expression="org.springframework.web.bind.annotation.controlleradvice"/> 
 </context:component-scan> 

三、基于aop的异常处理

1.处理controller层的异常 webexceptionaspect.java

import org.aspectj.lang.annotation.afterthrowing;
import org.aspectj.lang.annotation.aspect;
import org.aspectj.lang.annotation.pointcut;
import org.slf4j.logger;
import org.slf4j.loggerfactory;
import org.springframework.stereotype.component;
import org.springframework.util.stringutils;
import org.springframework.web.context.request.requestcontextholder;
import org.springframework.web.context.request.servletrequestattributes;

import com.hjz.exception.serviceexception;
import com.hjz.exception.utils.exceptionutils;

import javax.servlet.http.httpservletresponse;
import java.io.ioexception;
import java.io.printwriter;

/**
 * web异常切面
 * 默认spring aop不会拦截controller层,使用该类需要在spring公共配置文件中注入改bean,
 * 另外需要配置<aop:aspectj-autoproxy proxy-target-class="true"/>
 */
@aspect
public class webexceptionaspect {
 private static final logger logger = loggerfactory.getlogger(webexceptionaspect.class);

 @pointcut("@annotation(org.springframework.web.bind.annotation.requestmapping)")
 private void webpointcut() {}

 /**
  * 拦截web层异常,记录异常日志,并返回友好信息到前端
  * 目前只拦截exception,是否要拦截error需再做考虑
  *
  * @param e 异常对象
  */
 @afterthrowing(pointcut = "webpointcut()", throwing = "e")
 public void handlethrowing(exception e) {
  //不需要再记录serviceexception,因为在service异常切面中已经记录过
  if (!(e instanceof serviceexception)) {
   logger.error(exceptionutils.getexctrace(e));
  }

  string errormsg = stringutils.isempty(e.getmessage()) ? "系统异常" : e.getmessage();
  writecontent(errormsg);
 }

 /**
  * 将内容输出到浏览器
  *
  * @param content 输出内容
  */
 private void writecontent(string content) {
  httpservletresponse response = ((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");
  printwriter writer = null;
  try {
   writer = response.getwriter();
  } catch (ioexception e) {
   e.printstacktrace();
  }
  writer.print(content);
  writer.flush();
  writer.close();
 }
}

2.处理service层的异常serviceexceptionaspect .java

import org.aspectj.lang.joinpoint;
import org.aspectj.lang.annotation.afterthrowing;
import org.aspectj.lang.annotation.aspect;
import org.aspectj.lang.annotation.pointcut;
import org.slf4j.logger;
import org.slf4j.loggerfactory;
import org.springframework.stereotype.component;
import org.springframework.util.stringutils;

import com.hjz.exception.serviceexception;
import com.hjz.exception.utils.exceptionutils;

@aspect
public class serviceexceptionaspect {
 private static final logger logger = 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 * *(..))")
 private void servicepointcut() {}

 /**
  * 拦截service层异常,记录异常日志,并设置对应的异常信息
  * 目前只拦截exception,是否要拦截error需再做考虑
  *
  * @param e 异常对象
  */
 @afterthrowing(pointcut = "servicepointcut()", throwing = "e")
 public void handle(joinpoint point, exception e) {
  logger.error(exceptionutils.getexctrace(e));

  string signature = point.getsignature().tostring();
  string errormsg = getmessage(signature) == null ? (stringutils.isempty(e.getmessage()) ? "服务异常" : e.getmessage()) : getmessage(signature);
  throw new serviceexception(errormsg, e);
 }

 /**
  * 获取方法签名对应的提示消息
  *
  * @param signature 方法签名
  * @return 提示消息
  */
 private string getmessage(string signature) {
  return null;
 }
}

3.使用方式,在spring的公共配置文件中加入如下配置:

<aop:aspectj-autoproxy proxy-target-class="true" />
<bean class="com.hjz.exception.aspect.serviceexceptionaspect" />
<bean class="com.hjz.exception.aspect.webexceptionaspect" />

或者 自定义一个 注册类,serviceexceptionaspect.java和webexceptionaspect.java都加入@component注解

import org.springframework.context.annotation.componentscan;
import org.springframework.context.annotation.configuration;
import org.springframework.context.annotation.enableaspectjautoproxy;

/**
 * 异常相关bean注册类
 */
@configuration
@enableaspectjautoproxy
@componentscan("com.hjz.exception.aspect")
public class exceptionconfig {

}
@aspect
@component
public class webexceptionaspect {
 .......... 
}


@aspect
@component
public class serviceexceptionaspect {
 .........
}

四、疑惑

@within(org.springframework.stereotype.service),拦截带有 @service 注解的类的所有方法

@annotation(org.springframework.web.bind.annotation.requestmapping),拦截带有@rquestmapping的注解方法

五、测试

分别编写controller层和service层的异常测试类。这个很简单,在方法里简单的抛一下异常就可以了。最后验证一下,异常发生的时候有没有 执行 @afterthrowing对应的方法就好了。具体还是看我写的demo吧,嘿嘿嘿!!!

完整项目下载地址:

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持移动技术网。

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网