本文将告诉你一个让测试和开发 知道一个异常出现的时候,导致这个异常出现的原因是谁写的啥方法,入参是什么,达到不扯皮,精确定位的目的,但是如何知道是谁写的呢,我们需要自定义一个注解。
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
@Documented
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RUNTIME)
public @interface Author {
String value() default "";
}
定义一个异常类
package javax.com.vanrui.exception;//必须以Java或者Javax开头包名,否则会出大事,因为我使用的是dubboX
import java.io.Serializable;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/**
* 自定义异常类(继承运行时异常)
* @author yangjiangcai
* @version 2019/01/07
*/
public class MyRuntimeException extends RuntimeException implements Serializable{
private static Logger log = LogManager.getLogger(MyRuntimeException.class.getName());
private static final long serialVersionUID = 1L;
public String author;
public String method;
public String paramJson;
public String message;
public String errorCode;
public MyRuntimeException() {
super();
}
public MyRuntimeException(String message) {
super();
log.error(message);
this.message = message;
}
public MyRuntimeException(String code,String message) {
super();
log.error(message);
this.message = message;
this.errorCode=code;
}
public MyRuntimeException(String author, String method, String paramJson, String message) {
super();
this.author = author;
this.method = method;
this.paramJson = paramJson;
this.message = message;
}
public MyRuntimeException(String author, String method, String paramJson, String message, String code) {
super();
this.author = author;
this.method = method;
this.paramJson = paramJson;
this.message = message;
this.errorCode = code;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public String getMethod() {
return method;
}
public void setMethod(String method) {
this.method = method;
}
public String getParamJson() {
return paramJson;
}
public void setParamJson(String paramJson) {
this.paramJson = paramJson;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getErrorCode() {
return errorCode;
}
public void setErrorCode(String errorCode) {
this.errorCode = errorCode;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("MyRuntimeException [author=");
builder.append(author);
builder.append(", method=");
builder.append(method);
builder.append(", paramJson=");
builder.append(paramJson);
builder.append(", message=");
builder.append(message);
builder.append(", errorCode=");
builder.append(errorCode);
builder.append("]");
return builder.toString();
}
}
定义一个切面
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.io.Serializable;
import java.lang.reflect.Method;
import javax.com.vanrui.exception.MyRuntimeException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import com.alibaba.fastjson.JSONObject;
import com.vanrui.common.annotation.Author;
/**
* @author yangjiangcai
*/
@Aspect
@Component
public class ExceptionInterceptor {
private static Logger log = LogManager.getLogger(ExceptionInterceptor.class.getName());
@Pointcut("execution(* com.vanrui..*(..))")
public void vanrui() {}
@Around("vanrui()")
public Object Interceptor(ProceedingJoinPoint pjp) throws Throwable {
try {
Object result = pjp.proceed();
return result;
} catch (RuntimeException e) {
if (e instanceof MyRuntimeException) { //这段逻辑是想让异常直接抛出,因为这已经不是第一次补抓
throw e;
}
MethodSignature signature = (MethodSignature) pjp.getSignature();
Method method = signature.getMethod();
if (method.isAnnotationPresent(Author.class)) {
String message = getExceptionAllinformation(e);
Author tagert = method.getAnnotationsByType(Author.class)[0];
String author = tagert.value();
Object target2 = pjp.getTarget();
MyRuntimeException myRuntimeException = new MyRuntimeException();
myRuntimeException.setAuthor(author);
myRuntimeException.setMethod(target2.getClass() + "." + method.getName() + "()");
myRuntimeException.setParamJson(getParam(pjp));
myRuntimeException.setStackTrace(e.getStackTrace());
myRuntimeException.setErrorCode(StringUtils.isEmpty(myRuntimeException.getErrorCode())?"1000":myRuntimeException.getErrorCode());
myRuntimeException.setMessage(author+myRuntimeException.getMethod()+myRuntimeException.getParamJson()+message);
log.error(message);
throw myRuntimeException;
} else {
throw e;
}
}
}
private String getParam(ProceedingJoinPoint pjp){
Signature signature = pjp.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
JSONObject result = new JSONObject();
String[] parameterNames = methodSignature.getParameterNames();
Object[] values = pjp.getArgs();
if(parameterNames!=null&¶meterNames.length>0) {
for(int i=0;i<parameterNames.length;i++) {
if(values[i] instanceof Serializable) {
result.put(parameterNames[i], values[i]);
}
}
}
return result.toJSONString();
}
public static String getExceptionAllinformation(Exception ex) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
PrintStream pout = new PrintStream(out);
ex.printStackTrace(pout);
String ret = new String(out.toByteArray());
pout.close();
try {
out.close();
} catch (Exception e) {
}
return ret;
}
定义一个全局异常拦截器
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import javax.com.vanrui.exception.Businessexception;
import javax.com.vanrui.exception.MyRuntimeException;
import javax.servlet.http.HttpServletResponse;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import com.vanrui.common.dto.ResponseDTO;
import com.vanrui.common.enums.ResponseEnum;
@ControllerAdvice
public class GlobalExceptionHandler {
private static Logger log = LogManager.getLogger(GlobalExceptionHandler.class.getName());
@ExceptionHandler(value = Exception.class)
@ResponseBody
public Object jsonExceptionHandler(HttpServletResponse rep, Exception e) {
String message = getExceptionAllinformation(e);
log.error(message);
//e.printStackTrace();
if(e instanceof Businessexception) {
Businessexception businessexception =(Businessexception)e;
return new ResponseDTO(businessexception.errorCode,"代码负责人:"+businessexception.getAuthor()+"; 方法:"+businessexception.getMethod()+"; 参数:"+businessexception.getParamJson()+message,null);
}
if(e instanceof MyRuntimeException) {
MyRuntimeException myRuntimeException =(MyRuntimeException)e;
return new ResponseDTO(myRuntimeException.errorCode,"代码负责人:"+myRuntimeException.getAuthor()+"; 方法:"+myRuntimeException.getMethod()+"; 参数:"+myRuntimeException.getParamJson()+message,null);
}
return new ResponseDTO(ResponseEnum.SYS_ERROR.getCode(),message,null);
}
public static String getExceptionAllinformation(Exception ex) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
PrintStream pout = new PrintStream(out);
ex.printStackTrace(pout);
String ret = new String(out.toByteArray());
pout.close();
try {
out.close();
} catch (Exception e) {
}
return ret;
}
到此,程序员在写业务逻辑的时候在他写的方法上加上@Author(your name)就可以了
打完收工,这出现异常,异常输出中将可以看到输出的异常中的第一行作者是谁,什么类的啥方法,入参是啥,错误,这样测试人员看到直接找那个人,或者开发人员看见就知道是谁的问题,并且可以直接调试,不用再等问题重现了,可以用这里的信息直接单元调试了,因为知道方法和入参了。