通过AOP切面实现自定义注解,完成添加日志记录的操作
1.首先定义公共接口,接口中的方法根据自己的需求自己添加和定义
import javax.validation.constraints.NotNull;
import java.lang.annotation.*;
//Target注解type可以放在类上,method可以放在方法上
@Target({ElementType.TYPE, ElementType.METHOD})
//Retention注解括号中的"RetentionPolicy.RUNTIME"意思是让 MyLog 这个注解的生命周期一直程序运行时都存在
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LogAnnotation {
/**
* 方法名
* @return
*/
@NotNull
String method() default "";
/**
* 操作
* @return
*/
@NotNull
String operate() default "";
}
- 创建一个实体类用来封装并存储具体的数据
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Log {
/**
* 唯一id
*/
private Integer id;
/**
* 操作人员
*/
private Long UserId;
/**
* 模块操作
*/
private String operate;
/**
* 日志内容
*/
private String content;
/**
* 方法名称
*/
private String methodName;
/**
* ip地址
*/
private String ip;
/**
* 操作状态(0正常 1删除)
*/
private String status;
/**
* 操作时间
*/
private Date operateTime;
/**
* 执行时间
*/
private long executeTime;
}
- 再定义一个切面类
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.openservices.shade.org.apache.commons.lang3.ArrayUtils;
import com.dlbcloud.cjd.common.annotation.LogAnnotation;
import com.dlbcloud.cjd.common.utils.HttpContextUtils;
import com.dlbcloud.cjd.common.utils.IPUtils;
import com.dlbcloud.cjd.common.utils.StringUtils;
import com.dlbcloud.cjd.domain.log.domain.OperLog;
import com.dlbcloud.cjd.server.base.enums.BizConstants;
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.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.sql.Timestamp;
import java.util.Optional;
/**
* 日志切面
*/
@Component
@Aspect//定义了切面和切点的关系
@Slf4j
public class LogAspect {
@Resource
UserSercice userService;
@Pointcut("@annotation(放入第一项公共接口的项目全路径)")
public void logPointCut() {
}
/**
* 环绕通知
*/
@Around("logPointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
long beginTime = System.currentTimeMillis();
//执行方法(可以获取到方法执行完毕后返回的参数)
Object result = point.proceed();
//执行时长(毫秒)
long time = System.currentTimeMillis() - beginTime;
//保存日志
dispose(point, time,result);
return result;
}
/**
* 处理过程
*/
private void dispose(ProceedingJoinPoint point, long time,Object result) {
try{
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod();
//获取注解位置请求的参数(logAnnotation可以获取到注解方法的参数)
LogAnnotation logAnnotation = method.getAnnotation(LogAnnotation.class);
log.info("方法名:{}", logAnnotation.method());
log.info("方法描述:{}", logAnnotation.operate());
int type = logAnnotation.type();
//请求的参数
Object[] args = point.getArgs();
String className = point.getTarget().getClass().getName();
String methodName = signature.getName();
log.info("方法名:{}", className + "." + methodName + "()");
//获取request
HttpServletRequest request = HttpContextUtils.getHttpServletRequest();
//解析参数,获取请求参数里面具体的值(需要看args数组里面具体的参数args[?])
String arg = JSONObject.toJSONString(args[0]);
JSONObject jsonObject = JSONObject.parseObject(arg);
//同样方法解析返回的参数
//String re = JSONObject.toJSONString(result);
//JSONObject reObj = JSONObject.parseObject(re);
//JSONObject data = (JSONObject) reObj.get("data");
//实例化对象
Log log = new Log();
String UserId= jsonObject.getString("UserId");
log .setUserId(UserId);
//调自己的接口,保存数据
log.setOperate(logAnnotation.operate());
log.setContent(className + "." + methodName + "()");
log.setMethodName(logAnnotation.operate() + jsonString);
log.setIp(IPUtils.getIpAddr(request));
log.setStatus("0");
log.setOperateTime(new Timestamp(System.currentTimeMillis()));
log.setExecuteTime(time);
userService.save(operLog);
}
}
- 获取Ip的工具包
import lombok.extern.slf4j.Slf4j;
import javax.servlet.http.HttpServletRequest;
@Slf4j
public class IPUtils {
/**
* 获取IP地址
* <p>
* 使用Nginx等反向代理软件, 则不能通过request.getRemoteAddr()获取IP地址
* 如果使用了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP地址,X-Forwarded-For中第一个非unknown的有效IP字符串,则为真实IP地址
*/
public static String getIpAddr(HttpServletRequest request) {
String ip = null, unknown = "unknown", seperator = ",";
int maxLength = 15;
try {
ip = request.getHeader("x-forwarded-for");
if (StringUtils.isEmpty(ip) || unknown.equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (StringUtils.isEmpty(ip) || ip.length() == 0 || unknown.equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (StringUtils.isEmpty(ip) || unknown.equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
}
if (StringUtils.isEmpty(ip) || unknown.equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (StringUtils.isEmpty(ip) || unknown.equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
} catch (Exception e) {
log.error("IpUtils ERROR ", e);
}
// 使用代理,则获取第一个IP地址
if (StringUtils.isEmpty(ip) && ip.length() > maxLength) {
int idx = ip.indexOf(seperator);
if (idx > 0) {
ip = ip.substring(0, idx);
}
}
return ip;
}
}
- 获取request的包
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;
public class HttpContextUtils {
public static HttpServletRequest getHttpServletRequest() {
return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
}
public static HttpServletResponse getHttpServletResponse() {
return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
}
public static HttpSession getHttpSession() {
return getHttpServletRequest().getSession();
}
public static String getDomain() {
HttpServletRequest request = getHttpServletRequest();
StringBuffer url = request.getRequestURL();
String domain = url.delete(url.length() - request.getRequestURI().length(), url.length()).toString();
return domain;
}
public static String getOrigin() {
HttpServletRequest request = getHttpServletRequest();
return request.getHeader("Origin");
}
public static String getIp() {
HttpServletRequest request = getHttpServletRequest();
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.getHeader("HTTP_CLIENT_IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return ip;
}
}