Title

对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("这是自定义错误");
}
posted @ 2021-12-09 18:14  快乐小洋人  阅读(216)  评论(0编辑  收藏  举报