springBoot,AOP切⾯实现⽇志记录,⾃定义注解,注解属性动态传参SpringBoot,AOP切⾯实现⽇志记录,⾃定义注解,注解属性动态传参
项⽬需求:
需要记录⽤户的操作具体的⽅法,记录当前具体操作的是哪⼀条数据信息,作为参数也⼀并保存起来。
如:更新数据,IP,电脑号,调⽤⽅法,类型为修改,及这条更新的数据具体信息。
⽤SpringAOP + Annotation来实现
⾃定义aop注解类,通⽤⽇志⽂件
import java.lang.annotation.*;
/******************************
* ⽤途说明: 通⽤⽇志⽂件
* 作者姓名: wangqiubo
* 创建时间: 2021/03/24
******************************/
@Target(ElementType.METHOD)//注解放置的⽬标位置,METHOD是可注解在⽅法级别上
@Retention(RetentionPolicy.RUNTIME)//注解在哪个阶段执⾏
@Documented//⽣成⽂档
public @interface MyLog {
/**
* 业务类型,例如:"新增"
*/
String type()default"";
/**
* 业务的操作,例如:"⽤户信息: 新增XXX⽤户"
*/
String name()default"";
}
controller⽅法上,加⼊我们⾃定义的MyLog注解
/**
* 分页查询
*/
@PostMapping("/{pageNum}/{pageSize}")
@ApiOperation(value ="operateLog-ofPage", notes ="分页查询操作⽇志列表")
/**
* 注意:就是下⾯这⼀⾏
* @MyLog 是⾃定义注解, type,name 是我们在⾃定义注解⾥⾯的
* type本⽂是引⽤的常量,name是前端参过来的实体类
* 当然type,name也可以写死如:
* @MyLog(type = "查询", name = "查询所有数据")
*/
@MyLog(type = ConstantList.SELECT, name ="#{sysOperateLogDto.operateType}")
//-----------------------上⾯这⼀⾏--------------------------------------
public CallResult ofPage(@ApiParam(value ="页号", required =true)@PathVariable("pageNum")int pageNum,
@ApiParam(value ="页⼤⼩", required =true)@PathVariable("pageSize")int pageSize,
@ApiParam(value ="条件", required =true)@RequestBody SysOperateLogDto sysOperateLogDto){
log.info("分页查询操作⽇志参数:pageNum: "+ pageNum +"  pageSize: "+ pageSize +"  sysOperateLogDto: "+sysOperateLogDto);        QueryWrapper<SysOperateLog> queryWrapper =new QueryWrapper();
queryWrapper.eq(!StringUtils.OperatorId()),"operator_id",OperatorId()) .eq(!StringUtils.OperateType()),"operate_type",OperateType())
.ge(!StringUtils.StartDate()),"operate_time",StartDate())
.le(!StringUtils.EndDate()),"operate_time",EndDate());
IPage<SysOperateLog> page =new Page<>();
page.setCurrent(pageNum);
page.setSize(pageSize);
page = operateLogService.page(page, queryWrapper);
log.info("返回操作⽇志列表:page: "+ Records().toString());
return CallResult.success("操作⽇志列表", page);
}
定义springAOP切⾯,来获取动态参数,及调⽤⽅法的信息
pc.ller.SysOperateLogController;
pc.psc.manage.domain.SysOperateLog;
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.flect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.t.request.RequestAttributes;
import org.t.request.RequestContextHolder;
import javax.servlet.http.HttpServletRequest;
import flect.Method;
import java.InetAddress;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/******************************
* ⽤途说明: ⽇志AOP切⼊
* 作者姓名: wangqiubo
* 创建时间: 2021/03/24
******************************/
@Aspect
@Component
public class LogAspect {
@Autowired
SysOperateLogController sysOperateLogController;
//定义切点定义切⼊点MyLog(扫描切⼊点路径)
@Pointcut(value ="@pc.fig.sysPperateLog.MyLog)")
public void logPointCut(){
}
//定义切⾯⽇志切⾯
@Around("logPointCut()")
public Object around(ProceedingJoinPoint point)throws Throwable {
RequestAttributes requestAttributes = RequestAttributes();//获取RequestAttributes
HttpServletRequest request =(HttpServletRequest) requestAttributes
.resolveReference(RequestAttributes.REFERENCE_REQUEST);//从RequestAttributes中获取HttpServletRequest的信息
System.out.println("==============================begin==============================");
Object result = point.proceed();//去执⾏被访问的切⾯⽅法
MethodSignature signature =(MethodSignature) Signature();//从切⾯织⼊点处通过反射机制获取织⼊点处的⽅法
Method method = Method();//获取切⼊点所在的⽅法
//        String methodName = Name();                                  //获取⽅法名
//        System.out.println("Method Name:" + methodName);                        //输出⽅法名
springboot aop
//        Map<String, String> rtnMap = ParameterMap());      //请求的参数
//        String className = Target().getClass().getName();              //获取请求的类名
/**
* 获取动态参数值
*/
MyLog log = Annotation(MyLog.class);
System.out.println("type:"+ log.name()+"name:"+ log.name());//输出注解⾥⾯的值
Object type = wInstance().resolver(point, pe());
Object name = wInstance().resolver(point, log.name());
InetAddress addr = LocalHost();//获取主机信息
System.out.println("Local HostAddress: "+HostAddress());//本地主机ip地址
String hostname = HostName();//本地主机名称
System.out.println("Local host name: "+hostname);
System.out.println("++++++++++++++++++++++++++++++end++++++++++++++++++++++++++++++");
//定义操作⽇志实体类
SysOperateLog sysOperateLog =new SysOperateLog();
sysOperateLog.String());//操作类型
sysOperateLog.setMessage("操作信息:"+ String());//操作信息
sysOperateLog.setOperateTime(new Date());//操作时间
sysOperateLog.HostAddress());//主机名(ip)
//调⽤操作⽇志新增⽅法
sysOperateLogController.addOperateLog(sysOperateLog);
return result;
}
/**
* 转换request 请求参数
* @param paramMap request获取的参数数组
*/
public Map<String, String>converMap(Map<String, String[]> paramMap){
Map<String, String> rtnMap =new HashMap<String, String>();
for(String key : paramMap.keySet()){
rtnMap.put(key, (key)[0]);
}
return rtnMap;
}
}
AnnotationResolver 是解析注解类语法的解析器,可以把注解类中的语法直接解析#{⽅法变量名}
import flect.Method;
import org.aspectj.lang.JoinPoint;
import org.flect.MethodSignature;
/
**
* 该类的作⽤可以把⽅法上的参数绑定到注解的变量中,注解的语法#{变量名}
* 能解析类似 "#{sysOperateLogDto.operateType}"
*/
public class AnnotationResolver {
private static AnnotationResolver resolver ;
public static AnnotationResolver newInstance(){
if(resolver == null){
return resolver =new AnnotationResolver();
}else{
return resolver;
}
}
/**
* 解析注解上的值
* @param joinPoint
* @param str 需要解析的字符串
* @return
*/
public Object resolver(JoinPoint joinPoint, String str){
if(str == null)return null ;
Object value = null;
if(str.matches("#\\{\\D*\\}")){// 如果name匹配上了#{},则把内容当作变量
String newStr = placeAll("#\\{","").replaceAll("\\}","");
ains(".")){// 复杂类型
try{
value =complexResolver(joinPoint, newStr);
}catch(Exception e){
e.printStackTrace();
}
}else{
value =simpleResolver(joinPoint, newStr);
}
}else{//⾮变量
value = str;
}
return value;
}
private Object complexResolver(JoinPoint joinPoint, String str)throws Exception {
MethodSignature methodSignature =(MethodSignature) Signature();
String[] names = ParameterNames();
Object[] args = Args();
String[] strs = str.split("\\.");
for(int i =0; i < names.length; i++){
if(strs[0].equals(names[i])){
Object obj = args[i];
Method dmethod = Class().getDeclaredMethod(getMethodName(strs[1]), null);                Object value = dmethod.invoke(args[i]);
return getValue(value,1, strs);
}
}
return null;
}
private Object getValue(Object obj,int index, String[] strs){
try{
if(obj != null && index < strs.length -1){
if(obj != null && index < strs.length -1){
Method method = Class().getDeclaredMethod(getMethodName(strs[index +1]), null);                obj = method.invoke(obj);
getValue(obj, index +1, strs);
}
return obj;
}catch(Exception e){
e.printStackTrace();
return null;
}
}
private String getMethodName(String name){
return"get"+ placeFirst(name.substring(0,1), name.substring(0,1).toUpperCase());
}
private Object simpleResolver(JoinPoint joinPoint, String str){
MethodSignature methodSignature =(MethodSignature) Signature();
String[] names = ParameterNames();
Object[] args = Args();
for(int i =0; i < names.length; i++){
if(str.equals(names[i])){
return args[i];
}
}
return null;
}
}
ConstantList 常量列表,供AOP切⾯使⽤,操作⽇志调⽤
/**
* 常量列表,供AOP切⾯使⽤,操作⽇志调⽤
*/
public class ConstantList {
public static final String SELECT ="查询";
public static final String ADD ="新增";
public static final String UPDATE ="修改";
public static final String DELETE ="删除";
public static final String BATCH_DELETE ="批量删除";
}
到这⾥就全结束了,希望对你有所帮助

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。