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;
}
}
- 相应的界面这里没有提供。