在後臺數據管理系統中進行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.效果展示

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章