基於Aop實現記錄操作日誌和異常資訊
阿新 • • 發佈:2020-10-31
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;
}
}