在后台数据管理系统中进行AOP日志记录?

0x01.需求

  • 记录访问者的访问时间,执行时间。
  • 记录访问者的用户名,用户的ip。
  • 记录访问的url,访问的具体方法(方法级别)。
  • 将相应的数据存入数据库,统一管理。
  • 在相应的界面展示。

0x02.核心解决思路

  • 整体是在SSM环境下进行。

  • 配置Spring AOP 的切面,切入所有web层的方法。

    • 在前置通知中:
      • 确定访问时间。
      • 根据反射获取访问的类名,方法名。
    • 在后置通知中:
      • 确定执行时间(此时的时间-访问时间)。
      • 根据反射获取具体的url。
      • 注入一个request,通过request获取ip地址。
      • 通过SecurityContext获取访问者的用户名。
    • 封装这些数据,通过service–>dao存入。
  • 编写Controller层,请求findAll()方法,调用serviceservice调用dao,完成查询。

0x03.解决代码

1.建表Sql语句:(Oracle数据库)

 CREATE TABLE sysLog(
 	 id VARCHAR2(32) default SYS_GUID() PRIMARY KEY,  
 	 visitTime timestamp,
	 username VARCHAR2(50),
	 ip VARCHAR2(30),
	 url VARCHAR2(50),
	 executionTime int,
	 method VARCHAR2(200)
);

2.实体类:(SysLog)

public class SysLog {
    private String id;
    private Date visitTime;
    private String visitTimeStr;
    private String username;
    private String ip;
    private String url;
    private Long executionTime;
    private String method;
   
   // getters and setters

    @Override
   // override toString method
}

3.编写核心切面类:(LogAop)

  • Controller层。
  • 完成所有信息的获取。
@Component
@Aspect
public class LogAop {
    @Autowired
    private HttpServletRequest request;

    @Autowired
    private SysLogService sysLogService;

    private Date visitTime;//开始访问的时间
    private Class clazz;//访问的类
    private Method method;//访问的方法
    //前置通知
    @Before("execution(* com.atfwus.controller.*.*(..))")
    public void doBefore(JoinPoint jp) throws NoSuchMethodException {
        visitTime=new Date();
        clazz=jp.getTarget().getClass();
        String methodName=jp.getSignature().getName();
        Object[] args = jp.getArgs();
        if(args==null||args.length==0){
            method=clazz.getMethod(methodName);
        }else{
            Class[] classArgs=new Class[args.length];
            for(int i=0;i<args.length;i++){
                classArgs[i]=args[i].getClass();
            }
            clazz.getMethod(methodName,classArgs);
        }

    }
    //后置通知
    @After("execution(* com.atfwus.controller.*.*(..))")
    public void doAfter(JoinPoint pt) throws Exception {
        long time=new Date().getTime()-visitTime.getTime();//获取访问时长

        String url="";
        //获取url
        if(clazz!=null&&method!=null&&clazz!=LogAop.class){
            //1.获取类上的RequestMapping值
            RequestMapping classAnnotation =(RequestMapping) clazz.getAnnotation(RequestMapping.class);
            if(classAnnotation!=null){
                String[] classValue=classAnnotation.value();

                //2.获取mapping值
                RequestMapping methodAnnotation = method.getAnnotation(RequestMapping.class);
                    if(methodAnnotation!=null){
                        String[] methodValue=methodAnnotation.value();

                        url=classValue[0]+methodValue[0];

                        //获取访问的ip地址
                        String ip=request.getRemoteAddr();

                        //获取当前操作用户
                        SecurityContext context= SecurityContextHolder.getContext();
                        User user=(User)context.getAuthentication().getPrincipal();
                        String username=user.getUsername();


                        //封装日志信息
                        SysLog sysLog=new SysLog();
                        sysLog.setExecutionTime(time);
                        sysLog.setIp(ip);
                    	sysLog.setUrl(url);
                    	sysLog.setUsername(username);
                    	sysLog.setVisitTime(visitTime);
                   	    sysLog.setMethod("[类名] "+clazz.getName()
                   	    +"[方法名] "+method.getName() );

                    //记录操作
                    sysLogService.save(sysLog);
                }
            }
        }

    }
}

4.编写Service层:(SysLogService)

  • 提供保存日志信息,搜索全部信息的方法。

  • 接口:

public interface SysLogService {
    public void save(SysLog sysLog) throws Exception;

    public List<SysLog> findAll() throws Exception;
}
  • 实现类:
@Service
@Transactional
public class SysLogServiceImpl implements SysLogService {
    @Autowired
    private SysLogDao sysLogDao;

    @Override
    public void save(SysLog sysLog) throws Exception {
        sysLogDao.save(sysLog);
    }

    @Override
    public List<SysLog> findAll() throws Exception {
        return sysLogDao.findAll();
    }
}

5.编写Dao层:(SysLogDao)

  • MyBatis下进行:
public interface SysLogDao {
    @Insert("insert into syslog(visitTime,username,ip,url,executionTime,method) 
    values(#{visitTime},#{username},#{ip},#{url},#{executionTime},#{method})")
    public void save(SysLog sysLog) throws Exception;

    @Select("select * from sysLog")
    public List<SysLog> findAll() throws Exception;
}

6.Controller提供相应的findAll:(SysLogController)

  • 请求路径为/sysLog/findAll.do即可获取所有数据。
  • 获取完存入sysLogs,可以通过模板引擎,jsp等获取。
  • 请求完跳转sysLog-list进行展示数据,只需编写相应的界面即可。
@Controller
@RequestMapping("/sysLog")
public class SysLogController {

    @Autowired
    private SysLogService sysLogService;

    @RequestMapping("/findAll.do")
    public ModelAndView findAll() throws Exception {
        ModelAndView mv=new ModelAndView();
        List<SysLog> list=sysLogService.findAll();
        mv.addObject("sysLogs",list);
        mv.setViewName("syslog-list");
        return mv;
    }
}
  • 相应的界面这里没有提供。

0x04.效果展示

在这里插入图片描述

原创文章 248 获赞 288 访问量 4万+

猜你喜欢

转载自blog.csdn.net/ATFWUS/article/details/106089860