194.237.142.21 - - [18/Sep/2013:06:49:18 +0000] "GET /wp-content/uploads/2013/07/rstudio-git3.png HTTP/1.1" 304 0 "-" "Mozilla/4.0 (compatible;)"
183.49.46.228 - - [18/Sep/2013:06:49:23 +0000] "-" 400 0 "-" "-"
163.177.71.12 - - [18/Sep/2013:06:49:33 +0000] "HEAD / HTTP/1.1" 200 20 "-" "DNSPod-Monitor/1.0"
163.177.71.12 - - [18/Sep/2013:06:49:36 +0000] "HEAD / HTTP/1.1" 200 20 "-" "DNSPod-Monitor/1.0"
101.226.68.137 - - [18/Sep/2013:06:49:42 +0000] "HEAD / HTTP/1.1" 200 20 "-" "DNSPod-Monitor/1.0"
101.226.68.137 - - [18/Sep/2013:06:49:45 +0000] "HEAD / HTTP/1.1" 200 20 "-" "DNSPod-Monitor/1.0"
60.208.6.156 - - [18/Sep/2013:06:49:48 +0000] "GET /wp-content/uploads/2013/07/rcassandra.png HTTP/1.0" 200 185524 "http://cos.name/category/software/packages/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.66 Safari/537.36"
222.68.172.190 - - [18/Sep/2013:06:49:57 +0000] "GET /images/my.jpg HTTP/1.1" 200 19939 "http://www.angularjs.cn/A00n" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.66 Safari/537.36"
222.68.172.190 - - [18/Sep/2013:06:50:08 +0000] "-" 400 0 "-" "-"
数据中的字段分别为:
访客ip地址
访客访问时间
访客请求的url及协议
网站响应码
网站返回数据量
访客的referral url
访客的客户端操作系统及浏览器信息
需求:
1)需要为从访问日志中梳理出每一个session(如果一个用户两次相邻请求之间的时间差<30分钟,则该两次请求都属于同一个session(不考虑不同的URL),否则分属不同的session),并为session中的历次请求打上序号,示意如下:
session号 ip地址 请求时间 请求url 请求次序 其他字段……
session1 ip1 2017-10-11 08:10:30 /a 1 ……
session1 ip1 2017-10-11 08:11:20 /b 2 ……
session2 ip1 2017-10-11 09:10:30 /c 1 ……
步骤分析:
1 读取日志文件,获取用户请求数据,会根据用户的ip进行分组 (Map)
2 将用户的url按照时间排序
3 判断两个相邻的url的时间差值是否是在30分钟内来确定是否是同一个session
4 判断为每个url生成sessionId并打上运行顺序标签
SessionBean数据
public class SessionBean {
**private String sessionId;
private String ip;
private String url;
private Date date;
private int order;**
public String getSessionId() {
return sessionId;
}
public void setSessionId(String sessionId) {
this.sessionId = sessionId;
}
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public int getOrder() {
return order;
}
public void setOrder(int order) {
this.order =order;
}
@Override
public String toString() {
return "SessionBean [sessionId=" + sessionId + ", ip=" + ip + ", url="
+ url + ", date=" + date + ", order=" + order + "]";
}
}
读取用户数据并且存在map中
try(
BufferedReader br = new BufferedReader(new FileReader("f:/access.log.fensi"));
) {
Map<String,List<SessionBean>> map=new HashMap<>();
String line=null;
String ipRex = "(\\d{1,3}+\\.){3}\\d{1,3}";
String timeRex = "\\[.+\\d\\]";
String urlRegex = "(GET|POST){1}\\s(\\S)*\\s";
while((line=br.readLine())!=null){
//在一行里面获取制定规则的数据(调用方法据正则表达式获取内容)
String ip = Myutils.getStrByRex(line, ipRex);
String timestr = Myutils.getStrByRex(line, timeRex);
String url = Myutils.getStrByRex(line,urlRegex);
List<SessionBean> list = map.getOrDefault(ip, new ArrayList<>());
//创建sessionBean 【sessionId order】
SessionBean sessionBean = new SessionBean();
sessionBean.setIp(ip);
sessionBean.setUrl(url);
//将字符串转换为时间对象
//[18/Sep/2013:06:49:42 +0000] 时间格式不是我需要的
//对字符串进行parse
Date date = Myutils.parseDate(timestr);
sessionBean.setDate(date);
list.add(sessionBean);//sessionBean添加到list中去
//更新map数据
map.put(ip, list);//list作为value传入map中
}
**使用正则表达式获取字段的方法:**
public static String getStrByRex(String line,String rex){
String res=null;
Pattern pattern = Pattern.compile(rex);//获取一个pattern对象 并编译正则表达式
Matcher m = pattern.matcher(line);//获取一个macher:匹配器 在这个对象中包含了匹配的结果
//获取匹配的内容
while(m.find()){//返回 boolean类型 判断是否找到
res=m.group();//取内容 不能直接使用 必须要再find方法之后进行执行
}
return res;
}
**将字符串转换成时间对象**
@SuppressWarnings("null")
public static Date parseDate(String dateStr) throws ParseException{
Date d = null ;
/*long t1 = d.getTime();
long t2 = d.getTime();*/
if(dateStr!=null){
String str = dateStr.substring(1, dateStr.length()-1);//截取时间对象
//将字符串 转换成时间对象
SimpleDateFormat format = new SimpleDateFormat("dd/MMM/yyyy:HH:mm:ss" ,Locale.US) ;
d = format.parse(str);
}
return d;
}
对map的value(list)进行排序
Myutils.sortMap(map);//直接调用
对List中的SessionBean按照时间先后顺序排列
public static void sortMap(Map<String,List<SessionBean>>map){
Set<Entry<String, List<SessionBean>>> entrySet = map.entrySet();
for (Entry<String, List<SessionBean>> entry : entrySet) {
String ip = entry.getKey();
List<SessionBean> list = entry.getValue();
//对list排序
if(list!=null&&list.size()>0){
Collections.sort(list,new Comparator<SessionBean>() {
@Override
public int compare(SessionBean o1, SessionBean o2) {
return o1.getDate().compareTo(o2.getDate());
}
});
for (SessionBean entry1 : list) {
//System.out.println(entry1);
}
}
}
}
//生成sessionID和序号并判断结果条件
createdSessionId(map);//调用方法
private static void createdSessionId(Map<String, List<SessionBean>> map) {
Set<Entry<String, List<SessionBean>>> entrySet = map.entrySet();
for (Entry<String, List<SessionBean>> entry : entrySet) {
String ip = entry.getKey();
List<SessionBean> list = entry.getValue();
// 1 list中只有一个数据 sessionid 1
// 2 list中有多条数据 前一个和后一个时间比较 来判断是否是同一个session
if(list.size()==1){
SessionBean bean = list.get(0);
bean.setSessionId(Myutils.createsessionId());//sessionId不能重复(调用方法)
bean.setOrder(1);
}
if(list.size()>1){
for(int i=0;i<list.size()-1;i++){
//判断相邻的数据 判断这个数据是不是同一个session 时间
SessionBean presession = list.get(i);
SessionBean aftersession = list.get(i+1);
//判断是否为同一session
if(Myutils.issamesession(presession, aftersession)){//相同session
//给两条数据设置sessionid和编号
//前面的数据没有sessionId
if(presession.getSessionId()==null){//如果为空直接创建sessionId
presession.setSessionId(Myutils.createsessionId());
}//如果有的话 则直接赋值给后一个数(他两相等)
aftersession.setSessionId(presession.getSessionId());
if(presession.getOrder()==0){
presession.setOrder(1);//定义前一个序号为1
}//有的话 后一个为前一个+1;
aftersession.setOrder(presession.getOrder()+1);
}else{//不同session
if(presession.getSessionId()==null){
presession.setSessionId(Myutils.createsessionId());
}
aftersession.setSessionId(Myutils.createsessionId());
if(presession.getOrder()==0){
presession.setOrder(1);
}
aftersession.setOrder(1);
}
}
}
}
}
**生成SessionID 获取不重复的字符串**
public static String createsessionId(){
UUID uid = UUID.randomUUID();
String idstr = uid.toString();
String sessionId = idstr.replace("-", "");//把"-"替换掉
return sessionId;
}
**//判断两个sessionBean是否是同一个session**
public static boolean issamesession(SessionBean presession,SessionBean aftersession){
boolean flag=false;
Date d1 = presession.getDate();
Date d2 = aftersession.getDate();
//判断两个时间间隔是否在30分钟之内
long res=d2.getTime()-d1.getTime();
if(res>=0&&res<=(30*60*1000)){
flag=true;
}
return flag;
}
遍历结果并打印
Set<Entry<String, List<SessionBean>>> entrySet = map.entrySet();
for (Entry<String, List<SessionBean>> entry : entrySet) {
String ip = entry.getKey();
List<SessionBean> value = entry.getValue();
for (SessionBean sessionBean2 : value) {
//System.out.println(ip+" "+sessionBean2.getSessionId()+" "+sessionBean2.getDate()+" "+sessionBean2.getOrder());
}
}