1.首先在pom文件里添加
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2.定义注解
package com.mzd.ces.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LogAnno {
//日志类型 0:登录
String type() default "0";
//介绍
String title() default "我的说明例子";
}
@Target——定义注解使用范围
1.TYPE——用于描述类、接口(包括注解类型) 或enum声明
2.FIELD——用于字段声明(包括枚举常量)
3.METHOD——用于方法声明
4.PARAMETER——用于参数声明
5.CONSTRUCTOR——用于构造函数声明
6.LOCAL_VARIABLE——用于本地变量声明
7.ANNOTATION_TYPE——用于注解类型声明
8.PACKAGE——用于包声明
9.TYPE_PARAMETER—— 用于类型参数声明,JavaSE8引进,可以应用于类的泛型声明之处
10.TYPE_USE——JavaSE8引进,此类型包括类型声明和类型参数声明,是为了方便设计者进行类型检查,例如,如果使用@Target(ElementType.TYPE_USE)对@NonNull进行标记,则类型检查器可以将@NonNull class C {…} C类的所有变量都视为非null
@Retention——定义注解保留阶段
1.RetentionPolicy.SOURCE —— 这种类型的Annotations只在源代码级别保留,编译时就会被忽略
2.RetentionPolicy.CLASS —— 这种类型的Annotations编译时被保留,在class文件中存在,但JVM将会忽略
3.RetentionPolicy.RUNTIME —— 这种类型的Annotations将被JVM保留,所以他们能在运行时被JVM或其他使用反射机制的代码所读取和使用
@Documented
注解标记的元素,Javadoc工具会将此注解标记元素的注解信息包含在javadoc中。默认,注解信息不会包含在Javadoc中。
3.切点声明
package com.mzd.ces.annotation;
import java.lang.reflect.Method;
import javax.servlet.http.HttpServletRequest;
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 org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.mzd.ces.bo.SysOperLogBo;
import lombok.extern.slf4j.Slf4j;
@Aspect
@Component
@Slf4j
public class LogAspect {
/**
* 定义切点 @Pointcut
* 在注解的位置切入代码
*/
@Pointcut("@annotation(com.mzd.ces.annotation.LogAnno)")
public void logPointCut() {
}
/**
* 环绕通知,获取接口调用前后入参及返回值数据
* @param proceedingJoinPoint
* @return
*/
@Around("logPointCut()")
public void saveSysLog(ProceedingJoinPoint proceedingJoinPoint) {
try {
SysOperLogBo operLog = new SysOperLogBo();
//从切面织入点处通过反射机制获取织入点处的方法
MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
//获取切入点所在的方法
Method method = signature.getMethod();
//获取操作
LogAnno myLog = method.getAnnotation(LogAnno.class);
if (myLog != null) {
operLog.setType(myLog.type());
operLog.setTitle(myLog.title());
}
//获取请求的类名
String className = proceedingJoinPoint.getTarget().getClass().getName();
//获取请求的方法名
String methodName = method.getName();
operLog.setMethod(className + "." + methodName+"()");
//请求的参数
Object[] args = proceedingJoinPoint.getArgs();
String params = JSON.toJSONString(args);
JSONArray jsonArray = JSON.parseArray(params);
operLog.setParams(params);
// UserInfo user = JSON.toJavaObject(jsonArray.getJSONObject(0),UserInfo.class);
// operLog.setOperName(user != null ? user.getUserName() != null ? user.getUserName() : user.getMobile() : "");
// operLog.setOperTime(new Date());
//获取用户名
//获取用户ip地址
// 接收到请求,记录请求内容
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
// 记录下请求内容
// operLog.setOperIp(IpUtils.getIpAddr(request));
operLog.setUrl(request.getRequestURI());
//调用service保存SysLog实体类到数据库
// 异步保存日志数据到数据库
// AsyncManager.me().execute(AsyncFactory.recordOper(operLog));
//实际方法运行
Object result = proceedingJoinPoint.proceed();
System.out.println(result);
} catch (Throwable e) {
log.error(e.getMessage());
}
}
}
4.调用
@GetMapping("/test")
@LogAnno(title="title",type="#tpye")
public ResponseResult<String> test(String type){
String url = "hellow ces"+type;
return ResponseResult.success(url);
}
5.补充一个获取客户端ip的方法
package com.mzd.ces.util;
import java.net.InetAddress;
import java.net.UnknownHostException;
import javax.servlet.http.HttpServletRequest;
public class IpUtils {
public static String getIpAddr(HttpServletRequest request) {
String 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(ipAddress.equals("127.0.0.1") || ipAddress.equals("0:0:0:0:0:0:0:1")){
//根据网卡取本机配置的IP
InetAddress inet=null;
try {
inet = InetAddress.getLocalHost();
} catch (UnknownHostException e) {
e.printStackTrace();
}
ipAddress= inet.getHostAddress();
}
}
//对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
if(ipAddress!=null && ipAddress.length()>15){ //"***.***.***.***".length() = 15
if(ipAddress.indexOf(",")>0){
ipAddress = ipAddress.substring(0,ipAddress.indexOf(","));
}
}
return ipAddress;
}
}