1.自定义注解

/**
 * @Author ZhengQinfeng
 * @Date 2020/10/31 16:33
 * @dec
 */

import java.lang.annotation.*;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface OperLog {
    /**
     * 操作模块
     *
     * @return
     */
    String operModule() default "";

    /**
     * 操作类型
     *
     * @return
     */
    String operType() default "";

    /**
     * 操作描述
     *
     * @return
     */
    String operDesc() default "";
}

2.自定义切面

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
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.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import qinfeng.zheng.anno.OperLog;
import qinfeng.zheng.util.IPUtil;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

/**
 * @Author ZhengQinfeng
 * @Date 2020/10/31 16:33
 * @dec
 */
@Slf4j
@Aspect
@Component
public class OperLogAspect {


    /**
     * 定义日志操作切入点
     */
    @Pointcut("@annotation(qinfeng.zheng.anno.OperLog)")
    public void operLogPointCut() {

    }


    /**
     * 切入点是controller包下的所有方法
     */
    @Pointcut("execution(* qinfeng.zheng.controller..*.*(..))")
    public void exceptionLogPointCut() {

    }

    /**
     * 正常返回通知,如果切入点抛出异常,不会执行
     *
     * @param joinPoint 切入点
     * @param response  返回结果
     */
    @AfterReturning(value = "operLogPointCut()", returning = "response")
    public void saveOperLog(JoinPoint joinPoint, Object response) {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);


        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        // 切入点方法
        Method method = signature.getMethod();


        OperLog operLog = method.getAnnotation(OperLog.class);
        String module = "";
        String type = "";
        String desc = "";
        if (operLog != null) {
            module = operLog.operModule();
            type = operLog.operType();
            desc = operLog.operDesc();
        }

        String className = joinPoint.getTarget().getClass().getSimpleName();


        String methodName = method.getName();


        methodName = className + "." + methodName;

        // 请求URI
        String requestURI = request.getRequestURI();

        // 操作ip
        String operIp = IPUtil.getIpFromRequest(request);

        // 请求参数
        Object[] args = joinPoint.getArgs();

        log.info("模块:{}, 类型:{}, 描述:{},方法:{}, 入参:{}, uri:{}, 请求ip:{}, 响应值:{}", module, type, desc, methodName, args, requestURI, operIp, response);

    }

    @AfterThrowing(pointcut = "exceptionLogPointCut()", throwing = "error")
    public void saveException(JoinPoint joinPoint, Throwable error) {

        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);

        try {

            MethodSignature signature = (MethodSignature) joinPoint.getSignature();

            Method method = signature.getMethod();

            String className = joinPoint.getTarget().getClass().getSimpleName();


            String methodName = method.getName();


            methodName = className + "." + methodName;

            // 请求URI
            String requestURI = request.getRequestURI();

            // 操作ip
            String operIp = IPUtil.getIpFromRequest(request);

            // 请求参数
            Object[] args = joinPoint.getArgs();

            // 获取异常名称
            String exceptionName = error.getClass().getName();

            // 异常信息
            String errorMessage = stackTraceToString(exceptionName, error.getMessage(), error.getStackTrace());


            log.info("方法:{}, 入参:{}, uri:{}, 请求ip:{}, 异常信息:{}", methodName, args, requestURI, operIp, errorMessage);
            
        } catch (Exception e) {
            log.error("{}", e.getMessage(), e);
        }


    }

    public String stackTraceToString(String exceptionName, String exceptionMessage, StackTraceElement[] stackTraceElements) {
        StringBuffer stringBuffer = new StringBuffer();
        for (StackTraceElement traceElement : stackTraceElements) {
            stringBuffer.append(traceElement).append("\n");
        }
        String message = exceptionName + ":" + exceptionMessage + "\n\t" + stringBuffer.toString();
        return message;
    }


}

3.Ip工具类

import org.apache.commons.lang.text.StrTokenizer;

import javax.servlet.http.HttpServletRequest;
import java.util.regex.Pattern;

/**
 * IpV4 获取真实ip地址
 */
public class IPUtil {

    public static final String _255 = "(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)";
    public static final Pattern pattern = Pattern.compile("^(?:" + _255 + "\\.){3}" + _255 + "$");

    /**
     * String类型ip转为Long类型
     * 
     * @param longIp
     * @return String
     */
    public static String longToIpV4(long longIp) {
        int octet3 = (int) ((longIp >> 24) % 256);
        int octet2 = (int) ((longIp >> 16) % 256);
        int octet1 = (int) ((longIp >> 8) % 256);
        int octet0 = (int) ((longIp) % 256);
        return octet3 + "." + octet2 + "." + octet1 + "." + octet0;
    }

    /**
     * Long类型ip转为String类型
     * 
     * @param ip
     * @return Long
     */
    public static long ipV4ToLong(String ip) {
        String[] octets = ip.split("\\.");
        return (Long.parseLong(octets[0]) << 24) + (Integer.parseInt(octets[1]) << 16)
                + (Integer.parseInt(octets[2]) << 8) + Integer.parseInt(octets[3]);
    }

    /**
     * @param ip
     * @return boolean
     */
    public static boolean isIPv4Private(String ip) {
        long longIp = ipV4ToLong(ip);
        return (longIp >= ipV4ToLong("10.0.0.0") && longIp <= ipV4ToLong("10.255.255.255"))
                || (longIp >= ipV4ToLong("172.16.0.0") && longIp <= ipV4ToLong("172.31.255.255"))
                || longIp >= ipV4ToLong("192.168.0.0") && longIp <= ipV4ToLong("192.168.255.255");
    }

    public static boolean isIPv4Valid(String ip) {
        return pattern.matcher(ip).matches();
    }

    /**
     * 获取String类型真实ip地址,基于反向代理。
     * 
     * @param request
     * @return
     * 在反向代理中将X-Forward-For替换为remote_addr,即,真实的IP地址。
     */
    public static String getIpFromRequest(HttpServletRequest request) {
        String ip;
        boolean found = false;
        if ((ip = request.getHeader("x-forwarded-for")) != null) {
            StrTokenizer tokenizer = new StrTokenizer(ip, ",");
            while (tokenizer.hasNext()) {
                ip = tokenizer.nextToken().trim();
                if (isIPv4Valid(ip) && !isIPv4Private(ip)) {
                    found = true;
                    break;
                }
            }
        }
        if (!found) {
            ip = request.getRemoteAddr();// 获得ip地址
        }
        return ip;
    }
}

4.测试类

import org.springframework.web.bind.annotation.*;
import qinfeng.zheng.anno.OperLog;
import qinfeng.zheng.vo.UserInfo;

import java.util.ArrayList;
        import java.util.List;

/**
 * @Author ZhengQinfeng
 * @Date 2020/10/31 20:16
 * @dec
 */
@RestController
public class TestController {

    @OperLog(operModule = "测试模块", operType = "新增", operDesc = "新增用户")
    @PostMapping("/index")
    public List<UserInfo> index(@RequestBody UserInfo userInfo) {
        List<UserInfo> rets = new ArrayList<>();
        rets.add(userInfo);
        rets.add(userInfo);
        return rets;
    }

    @OperLog(operModule = "测试模块", operType = "错误信息", operDesc = "测试异常打印信息")
    @GetMapping("/error/{number}")
    public Integer index(@PathVariable Integer number) {
        return 10 / number;
    }
}

posted on 2020-10-31 21:07  显示账号  阅读(697)  评论(0编辑  收藏  举报