对Controller层方法进行统一异常处理和抓取执行时间
两种方案
1、使用 @ControllerAdvice (或@RestControllerAdvice), @ExceptionHandler 注解实现;
2、使用AOP技术实现;
- 1、使用 @ControllerAdvice (或@RestControllerAdvice), @ExceptionHandler 注解实现;
package com.zl.securitytest.config;
import com.zl.securitytest.common.Result;
import com.zl.securitytest.common.ResultCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
/**
* 统一异常处理
*
* @author zhang
* @date 2021-12-09 17:07
*/
@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
@ExceptionHandler({Exception.class})
@ResponseBody
public Result<?> resolveException(Exception e) {
// 绑定参数校验
BindingResult bindingResult = this.argumentNotValidHandler(e);
if (!Objects.isNull(bindingResult)) {
List<ObjectError> allErrors = bindingResult.getAllErrors();
Iterator var4 = allErrors.iterator();
if (var4.hasNext()) {
ObjectError error = (ObjectError) var4.next();
log.error(error.getDefaultMessage());
return Result.failed(error.getDefaultMessage());
} else {
return Result.failed(e.getMessage());
}
} else {
log.error(e.getMessage(), e);
return Result.failed(ResultCode.FAILED.CODE, ResultCode.FAILED.MSG);
}
}
/**
* 参数验证异常判断
*
* @param e
* @return
*/
private BindingResult argumentNotValidHandler(Exception e) {
if (e instanceof MethodArgumentNotValidException) {
return ((MethodArgumentNotValidException) e).getBindingResult();
} else {
return e instanceof BindException ? ((BindException) e).getBindingResult() : null;
}
}
}
-
2、 使用AOP技术实现;
-
导入AOP依赖
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.8.RC3</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.8.RC3</version>
</dependency>
获取id地址工具类
package com.zl.common.utils;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* 获取请求id地址
*
* @author z
* @date 2022-02-18 23:20
*/
@Slf4j
public class IpUtil {
private static final String UNKNOWN = "unknown";
private static final String LOCALHOST = "127.0.0.1";
private static final String SEPARATOR = ",";
public static String getIpAddr(HttpServletRequest request) {
String ipAddress;
try {
ipAddress = request.getHeader("x-forwarded-for");
if (ipAddress == null || ipAddress.length() == 0 || UNKNOWN.equalsIgnoreCase(ipAddress)) {
ipAddress = request.getHeader("Proxy-Client-IP");
}
if (ipAddress == null || ipAddress.length() == 0 || UNKNOWN.equalsIgnoreCase(ipAddress)) {
ipAddress = request.getHeader("WL-Proxy-Client-IP");
}
if (ipAddress == null || ipAddress.length() == 0 || UNKNOWN.equalsIgnoreCase(ipAddress)) {
ipAddress = request.getRemoteAddr();
if (LOCALHOST.equals(ipAddress)) {
InetAddress inet = null;
try {
inet = InetAddress.getLocalHost();
} catch (UnknownHostException e) {
log.info("{}",e.getStackTrace());
}
ipAddress = inet.getHostAddress();
}
}
// 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
// "***.***.***.***".length()
if (ipAddress != null && ipAddress.length() > 15) {
if (ipAddress.indexOf(SEPARATOR) > 0) {
ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
}
}
} catch (Exception e) {
ipAddress = "";
}
return ipAddress;
}
}
package com.zl.securitytest.config;
import com.zl.securitytest.common.Result;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
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.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
/**
* aop处理
*
* @author zhang
* @date 2021-12-09 17:11
*/
@Aspect
@Component
@Order(1)
@Slf4j
public class GlobalExceptionAspectHandler {
@Pointcut("@within(org.springframework.web.bind.annotation.RestController)")
public void pointCut() {
}
@Around("pointCut()")
public Object around(ProceedingJoinPoint point) {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
long b = System.currentTimeMillis();
Object[] args = point.getArgs();
Object result;
try {
// 执行方法
result = point.proceed(args);
} catch (Throwable var10) {
Result<Object> failed = Result.failed("网络请求失败,请稍后再试!");
result = failed;
log.error(GlobalExceptionAspectHandler.class.getName(), var10);
}
// 抓取ip地址
String ipAddr = IpUtil.getIpAddr(request);
long e = System.currentTimeMillis();
log.info("远程主机: " + ipAddr + " --> 请求接口(" + request.getRequestURL() + ")执行耗时:" + (e - b) + "ms");
return result;
}
}
捕获 Throwable ,它是 Exception 和 Error 的父类
业务异常处理
定义接收异常信息的类
package com.ruoyi.common.core.exception;
/**
* 业务异常
*
* @author ruoyi
*/
public final class ServiceException extends RuntimeException
{
private static final long serialVersionUID = 1L;
/**
* 错误码
*/
private Integer code;
/**
* 错误提示
*/
private String message;
/**
* 错误明细,内部调试错误
*
* 和 {@link CommonResult#getDetailMessage()} 一致的设计
*/
private String detailMessage;
/**
* 空构造方法,避免反序列化问题
*/
public ServiceException()
{
}
public ServiceException(String message)
{
this.message = message;
}
public ServiceException(String message, Integer code)
{
this.message = message;
this.code = code;
}
public String getDetailMessage()
{
return detailMessage;
}
@Override
public String getMessage()
{
return message;
}
public Integer getCode()
{
return code;
}
public ServiceException setMessage(String message)
{
this.message = message;
return this;
}
public ServiceException setDetailMessage(String detailMessage)
{
this.detailMessage = detailMessage;
return this;
}
}
定义一个全局异常处理类
/**
* 全局异常处理器
*
* @author ruoyi
*/
@RestControllerAdvice
public class GlobalExceptionHandler
{
private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
/**
* 业务异常
*/
@ExceptionHandler(ServiceException.class)
public AjaxResult handleServiceException(ServiceException e, HttpServletRequest request)
{
log.error(e.getMessage(), e);
Integer code = e.getCode();
return StringUtils.isNotNull(code) ? AjaxResult.error(code, e.getMessage()) : AjaxResult.error(e.getMessage());
}
}
执行
if(true){
throw new ServiceException("这是自定义错误");
}