springboot全局异常处理
springboot全局异常处理
1、AOP日志和异常处理
- pom.xml中添加
<!--aop切面-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
- 切面类
package global_exception.global_exception.demo.config;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
/**
* Aop请求打日志
*/
@Aspect
@Component
public class WebLogAspect {
private static final Logger logger = LoggerFactory.getLogger(WebLogAspect.class);
private static final ThreadLocal<Long> timeTreadLocal = new ThreadLocal<>();
@Pointcut("execution(* global_exception.global_exception.demo..*.*(..)) && @annotation(org.springframework.web.bind.annotation.RequestMapping)")
// @Pointcut("execution(* global_exception.global_exception.demo.timer..*(..))")
public void log() {
}
@Before("log()")
public void before(JoinPoint joinPoint) {
timeTreadLocal.set(System.currentTimeMillis());
// 接收到请求,记录请求内容
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
//获取请求的request
HttpServletRequest request = attributes.getRequest();
//获取所有请求的参数,封装为map对象
// Map<String,Object> parameterMap = getParameterMap(request);
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
//获取被拦截的方法
Method method = methodSignature.getMethod();
//获取被拦截的方法名
String methodName = method.getName();
//被拦截的类
String className = joinPoint.getTarget().getClass().getName();
String[] classNames = className.split("\\.");
className = classNames[classNames.length - 1];
logger.info("请求方法:{}--开始", className + "-->" + methodName);
//获取所有请求参数key和value
String keyValue = getReqParameter(request);
logger.info("请求url = {}", request.getRequestURL().toString());
logger.info("请求方式 = {}", request.getMethod());
// logger.info("请求资源uri = {}", request.getRequestURI());
// logger.info("所有的请求参数 key:value = {}", keyValue);
}
@After("log()")
public void after(JoinPoint joinPoint) {
// logger.info("aop的after()方法");
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
//获取被拦截的方法
Method method = methodSignature.getMethod();
//获取被拦截的方法名
String methodName = method.getName();
//被拦截的类
String className = joinPoint.getTarget().getClass().getName();
String[] classNames = className.split("\\.");
className = classNames[classNames.length - 1];
long startTime = timeTreadLocal.get();
double callTime = (System.currentTimeMillis() - startTime) / 1000.0;
logger.info("请求方法:{}--结束;花费时间time = {}s", className + "-->" + methodName, callTime);
}
//controller请求结束返回时调用
@AfterReturning(returning = "result", pointcut = "log()")
public Object afterReturn(Object result) {
logger.info("AOP afterReturn,返回值result = {}", result.toString());
// System.out.println("返回值="+result.toString());
// long startTime = timeTreadLocal.get();
// double callTime = (System.currentTimeMillis() - startTime) / 1000.0;
// logger.info("调用controller花费时间time = {}s", callTime);
return result;
}
/**
* 异常捕获
*
* @param joinPoint
* @param e
*/
@AfterThrowing(pointcut = "log()", throwing = "e")
// @AfterThrowing(pointcut = "execution(* global_exception.global_exception.demo.timer..*(..))", throwing = "e")
public void handleThrowing(JoinPoint joinPoint, Exception e) {//controller类抛出的异常在这边捕获
String className = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
String[] classNames = className.split("\\.");
className = classNames[classNames.length - 1];
//开始打log
logger.info(className + "-->" + methodName + " 报错");
logger.error(className + "-->" + methodName + " 报错", e);
}
/**
* 获取所有请求参数,封装为map对象
*
* @return
*/
public Map<String, Object> getParameterMap(HttpServletRequest request) {
if (request == null) {
return null;
}
Enumeration<String> enumeration = request.getParameterNames();
Map<String, Object> parameterMap = new HashMap<String, Object>();
StringBuilder stringBuilder = new StringBuilder();
while (enumeration.hasMoreElements()) {
String key = enumeration.nextElement();
String value = request.getParameter(key);
String keyValue = key + " : " + value + " ; ";
stringBuilder.append(keyValue);
parameterMap.put(key, value);
}
return parameterMap;
}
public String getReqParameter(HttpServletRequest request) {
if (request == null) {
return null;
}
Enumeration<String> enumeration = request.getParameterNames();
//StringBuilder stringBuilder = new StringBuilder();
JSONArray jsonArray = new JSONArray();
while (enumeration.hasMoreElements()) {
String key = enumeration.nextElement();
String value = request.getParameter(key);
JSONObject json = new JSONObject();
//String keyValue = key+" : " +value+" ; ";
json.put(key, value);
//stringBuilder.append(keyValue);
jsonArray.add(json);
}
//JSONObject jsonObject = new JSONObject();
//jsonObject.put("请求参数为:",jsonArray.toString());
return jsonArray.toString();
}
}
设置切入点,前切、后切和异常切都已这个切点为入口
另外:方法内捕获了异常,全局就会再去捕获异常了
效果:
浏览器输入:http://localhost:8080/aopExceptionTest/test2
浏览器输入:http://localhost:8080/aopExceptionTest/test1
2、定时器AOP日志和异常
TimerLogAspect切面类
package global_exception.global_exception.demo.config;
import lombok.extern.log4j.Log4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
/**
* 定时器打日志
*/
@Aspect
@Component
public class TimerLogAspect {
private static final Logger logger = LoggerFactory.getLogger(TimerLogAspect.class);
private static final ThreadLocal<Long> timeTreadLocal = new ThreadLocal<>();
/**
* 切入点
*/
@Pointcut("execution(* global_exception.global_exception.demo.timer..*(..))")
public void log() {
}
/**
* 前切
* @param joinPoint
*/
@Before("log()")
public void before(JoinPoint joinPoint) {
timeTreadLocal.set(System.currentTimeMillis());
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
//获取被拦截的方法
Method method = methodSignature.getMethod();
//获取被拦截的方法名
String methodName = method.getName();
//被拦截的类
String className = joinPoint.getTarget().getClass().getName();
String[] classNames = className.split("\\.");
className = classNames[classNames.length - 1];
logger.info("定期器:{}--开始", className + "-->" + methodName);
}
/**
* 后切
* @param joinPoint
*/
@After("log()")
public void after(JoinPoint joinPoint) {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
//获取被拦截的方法
Method method = methodSignature.getMethod();
//获取被拦截的方法名
String methodName = method.getName();
//被拦截的类
String className = joinPoint.getTarget().getClass().getName();
String[] classNames = className.split("\\.");
className = classNames[classNames.length - 1];
long startTime = timeTreadLocal.get();
double callTime = (System.currentTimeMillis() - startTime) / 1000.0;
logger.info("定时器:{}--结束;花费时间time = {}s", className + "-->" + methodName, callTime);
}
/**
* 异常切面
* @param joinPoint
* @param e
*/
@AfterThrowing(pointcut = "execution(* global_exception.global_exception.demo.timer..*(..))", throwing = "e")
public void handleThrowing(JoinPoint joinPoint, Exception e) {//controller类抛出的异常在这边捕获
String className = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
String[] classNames = className.split("\\.");
className = classNames[classNames.length - 1];
//开始打log
logger.info("定时器" + className + "-->" + methodName + " 报错");
logger.error("定时器" + className + "-->" + methodName + " 报错", e);
}
}
效果:
3、请求页面异常捕获
两个页面404.html、500.html
404.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>404页面</h1>
</body>
</html>
500.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>500啦</h1>
</body>
</html>
两个类
NotFoundException.java
package global_exception.global_exception.demo.config;
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
/**
* 捕获404异常
*/
@Controller
public class NotFoundException implements ErrorController {
@Override
public String getErrorPath() {
return "/error";
}
@RequestMapping(value = {"/error"})
// @ResponseBody
public String error(HttpServletRequest request) {
// Map<String, Object> body = new HashMap<>();
// body.put("error", "not found");
// body.put("code", "404");
return "/error/404.html";
}
}
GlobalExceptionHandler.java
enter code herepackage global_exception.global_exception.demo.config;
import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
/**
* 统一异常处理
*/
@ControllerAdvice("global_exception.global_exception.demo")
public class GlobalExceptionHandler {
private Logger logger = LoggerFactory.getLogger(getClass());
@ExceptionHandler(RuntimeException.class)
// @ResponseBody
public String errorMsg(HttpServletRequest request,Exception ex) {
//可以返回页面或json数据
// logger.error("错误链接" + request.getRequestURL().toString());
// Map<String, Object> errorMsgResult = new HashMap<>();
// errorMsgResult.put("code", 500);
// errorMsgResult.put("msg", "系统抛出异常");
return "/error/500.html";
}
}
效果: