package com.property.framework.aspectj;
import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.property.common.utils.ServletUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.http.ResponseEntity;
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.util.Map;
import java.util.StringJoiner;
/**
* @className: OperLogAspect
* @program: property-new-admin
* @description:
* @author: wangliangzhi
* @create: 2022-02-17 17:17
*/
@Aspect
@Slf4j
@Component
public class OperLogAspect {
/**
* 開始時間
*/
private ThreadLocal<Long> startTime = new ThreadLocal<>();
/**
* 日志記錄
*/
private ThreadLocal<String> logApi = new ThreadLocal<>();
// "execution(public * com.property.*.controller.*..*.*(..))" 這里換成你的接口地址
// 也就是隨便找一個 controller 復制他的地址就可以了
@Pointcut("execution(public * com.property.*.controller.*..*.*(..))")
private void pointcut() {
}
@Before("pointcut()")
private void beforeExeApi(JoinPoint joinPoint) {
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (servletRequestAttributes != null) {
HttpServletRequest request = servletRequestAttributes.getRequest();
startTime.set(System.currentTimeMillis());
// ip
String ip = getRemoteHost(request);
// 請求方式
String httpMethod = request.getMethod();
// url附帶的參數
String urlParam = getUrlParam(request);
// body 參數
String bodyParam = "";
if ("POST".equals(httpMethod)) {
bodyParam = JSON.toJSONString(joinPoint.getArgs());
}
Signature signature = joinPoint.getSignature();
// 方法名
String methodName = signature.getName();
// 目標類
String targetClass = joinPoint.getTarget().getClass().getName();
log.info("統一日志記錄: 操作IP:[{}], 請求方式:[{}], 接口地址:[{}], 請求地址:[{}], get請求參數:[{}], post請求參數:[{}]",
ip, httpMethod, targetClass, ServletUtils.getRequest().getRequestURI(), urlParam, bodyParam);
}
}
/**
* @Description 切入點方法執行之后執行,@AfterReturning是在一個Join Point(連接點)正常返回后執行的Advice(增強)
* @Version 1.0
*/
@AfterReturning(value = "pointcut()", returning = "returnValue")
public void afterReturning(JoinPoint joinPoint, Object returnValue) {
// ip
String ip = getRemoteHost(ServletUtils.getRequest());
// 方法名
String methodName = ServletUtils.getRequest().getRequestURI();
// 目標類
String targetClass = joinPoint.getTarget().getClass().getName();
try {
String asString;
long total = System.currentTimeMillis() - startTime.get();
String logv = logApi.get();
logv = StringUtils.join(logv, "統一日志記錄:操作IP:[" + ip + "], 接口地址:[" + targetClass + "], 請求地址:[" + methodName + "],總耗時:" + total + "ms", "\n");
if (total < 5000L) {
// 超過5秒 數據量大沒必要記錄日志
ObjectMapper objectMapper = new ObjectMapper();
if (null == returnValue) {
logv = StringUtils.join(logv, "返回結果:", "\n");
} else if (returnValue instanceof ResponseEntity) {
asString = objectMapper.writeValueAsString(((ResponseEntity) returnValue).getBody());
logv = StringUtils.join(logv, "返回結果:" + (asString.length() > 5000 ? "數據量過大不打印結果" : asString), "\n");
} else {
asString = objectMapper.writeValueAsString(returnValue);
logv = StringUtils.join(logv, "返回結果:" + (asString.length() > 5000 ? "數據量過大不打印結果" : asString), "\n");
}
} else {
logv = StringUtils.join(logv, "耗時過長不打印結果");
}
logApi.set(logv);
log.info(logApi.get());
} catch (Exception e) {
log.error(e.toString());
} finally {
// 釋放資源
logApi.remove();
startTime.remove();
}
}
private String getUrlParam(HttpServletRequest request) {
Map<String, String[]> parameterMap = request.getParameterMap();
StringBuilder paramKv = new StringBuilder();
StringJoiner urlParam = new StringJoiner(", ");
for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
for (String s : entry.getValue()) {
paramKv.append(entry.getKey()).append("=").append(s);
}
urlParam.add(paramKv.toString());
paramKv = new StringBuilder();
}
return urlParam.toString();
}
/**
* 獲取目標主機的ip
*
* @param request
* @return
*/
private String getRemoteHost(HttpServletRequest request) {
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip;
}
}
文中用到的 ServletUtils
package com.property.common.utils;
import com.property.common.constant.FileConstants;
import com.property.common.core.text.Convert;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
/**
* 客戶端工具類
*
* @author wangliangzhi
*/
public class ServletUtils {
/**
* 獲取String參數
*/
public static String getParameter(String name) {
return getRequest().getParameter(name);
}
/**
* 獲取String參數
*/
public static String getParameter(String name, String defaultValue) {
return Convert.toStr(getRequest().getParameter(name), defaultValue);
}
/**
* 獲取Integer參數
*/
public static Integer getParameterToInt(String name) {
return Convert.toInt(getRequest().getParameter(name));
}
/**
* 獲取Integer參數
*/
public static Integer getParameterToInt(String name, Integer defaultValue) {
return Convert.toInt(getRequest().getParameter(name), defaultValue);
}
/**
* 獲取request
*
* @return
*/
public static HttpServletRequest getRequest() {
return getRequestAttributes().getRequest();
}
/**
* 獲取response
*/
public static HttpServletResponse getResponse() {
return getRequestAttributes().getResponse();
}
/**
* 獲取session
*/
public static HttpSession getSession() {
return getRequest().getSession();
}
public static ServletRequestAttributes getRequestAttributes() {
RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
return (ServletRequestAttributes) attributes;
}
/**
* 將字符串渲染到客戶端
*
* @param response 渲染對象
* @param string 待渲染的字符串
* @return null
*/
public static String renderString(HttpServletResponse response, String string) {
try {
response.setStatus(200);
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");
response.getWriter().print(string);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
/**
* 是否是Ajax異步請求
*
* @param request
*/
public static boolean isAjaxRequest(HttpServletRequest request) {
String accept = request.getHeader("accept");
if (accept != null && accept.indexOf("application/json") != -1) {
return true;
}
String xRequestedWith = request.getHeader("X-Requested-With");
if (xRequestedWith != null && xRequestedWith.indexOf("XMLHttpRequest") != -1) {
return true;
}
String uri = request.getRequestURI();
if (StringUtils.inStringIgnoreCase(uri, FileConstants.JSON_SUFFIX, FileConstants.XML_SUFFIX)) {
return true;
}
String ajax = request.getParameter("__ajax");
if (StringUtils.inStringIgnoreCase(ajax, FileConstants.FILE_TYPE_JSON, FileConstants.FILE_TYPE_XML)) {
return true;
}
return false;
}
}