0x01.需求
- 記錄訪問者的訪問時間,執行時間。
- 記錄訪問者的用戶名,用戶的ip。
- 記錄訪問的url,訪問的具體方法(方法級別)。
- 將相應的數據存入數據庫,統一管理。
- 在相應的界面展示。
0x02.核心解決思路
-
整體是在SSM環境下進行。
-
配置Spring AOP 的切面,切入所有web層的方法。
- 在前置通知中:
- 確定訪問時間。
- 根據反射獲取訪問的類名,方法名。
- 在後置通知中:
- 確定執行時間(此時的時間-訪問時間)。
- 根據反射獲取具體的url。
- 注入一個
request
,通過request
獲取ip地址。 - 通過
SecurityContext
獲取訪問者的用戶名。
- 封裝這些數據,通過
service
–>dao
存入。
- 在前置通知中:
-
編寫
Controller
層,請求findAll()
方法,調用service
,service
調用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;
}
}
- 相應的界面這裏沒有提供。