腾讯会议腾讯课堂考勤工具

2022-02-09 00:00:00 腾讯 课堂 考勤
  • 实习题目3-1 :开发一个考勤工具

项目源码:腾讯会议课堂考勤工具
1.输入数据为Data目录中的所有文件,其中的file-list.txt包含了文件的列表,

序号 文件名 开始时间 结束时间

1. 1.xlsx 2020/04/03 10:00 2020/04/03 11:30

2. Java &.Net -15_851979721.xlsx 2020-05-22 08:30 2020-5-22 10:00

2.输出数据为Summary.txt,基本内容如:

序号 姓名 参加次数 迟到次数 早退次数

1 . 张三 2 1 0

2 . 李四 2 0 2

3.支持腾讯课堂和腾讯会议。

4.支持用户名称智能匹配。比如 ” 111181-2张三”和”张三”按一人统计。

5.晚到超过5分钟算迟到,提前5分钟以上退出算早退。

设计与思路

由于这一次时间比较紧,故简略的讲写的思路与遇到的困难

首先这一题需要用到Excel的读写,故我们首先需要解决的问题是如何做到excel的读写操作,经过一番学习后我了解到了apache.poi这个包里的内容可以帮助我们读写excel,word等文件

Apache POI是Apache软件基金会的开放源码函式库,POI提供API给Java程序对Microsoft Office格式档案读和写的功能。

HSSF 是Horrible SpreadSheet Format的缩写,通过HSSF,你可以用纯Java代码来读取、写入、修改Excel文件。

HSSF 为读取操作提供了两类API:usermodel和eventusermodel,即“用户模型”和“事件-用户模型”。三、POI常用类说明
类名 说明

HSSFWorkbook Excel的文档对象

HSSFSheet Excel的表单

HSSFRow Excel的行

HSSFCell Excel的格子单元

HSSFFont Excel字体

HSSFDataFormat 格子单元的日期格式

HSSFHeader Excel文档Sheet的页眉

HSSFFooter Excel文档Sheet的页脚

HSSFCellStyle 格子单元样式

HSSFDateUtil 日期

HSSFPrintSetup 打印

HSSFErrorConstants 错误信息表

基于此我们便能完成基本的excel文件读写的操作了

然后是设计选择我所需用到的数据结构,我的思路是将腾讯课堂与腾讯会议两者分开分别用不同的处理方式,辨别文件是腾讯课堂还是腾讯会议可以用Excel文件的第一格进行判断,腾讯课堂的第一格是:课程基本数据,腾讯会议的第一格是:预定开始时间,第一格的内容始终不变;然后是对两种Excel格式进行不同的处理:

腾讯课堂:

《腾讯会议腾讯课堂考勤工具》

可以看到腾讯课堂的输出文件结构为:

  • 前五行无用数据

  • 第四列为姓名

  • 第六列为是否观看了直播

  • 第七列为进入的时间

  • 第八列为观看的时长

    我们主要需要处理这些列的数据

    故我们首先忽略前5行,同时定义了一个List<Map<String,String>> 类型的list静态成员,用来将此excel有用数据进行存储,每一个map里存放4个信息,即name,isviewed,entertime,viewtime 对应上面的4种有用的数据

 		Sheet sheet = null;
        Row row = null;
        String cellData = null;
        String columns[] = {"name","isviewed","entertime","viewtime"};
        Workbook wb = readExcel(filePath);
        if(wb != null)
        {
            //用来存放表中数据
            list = new ArrayList<Map<String, String>>();
            //获取第一个sheet
            sheet = wb.getSheetAt(0);
            //获取最大行数
            rownum = sheet.getPhysicalNumberOfRows();
            //获取第一行
            row = sheet.getRow(0);
            if (((String) getCellFormatValue(row.getCell(0))).equals("课程基本数据"))//腾讯课堂
            {
                //获取最大列数
                int colnum = 11;
                for (int i = 5; i < rownum; i++)
                {
                    Map<String, String> map = new LinkedHashMap<String, String>();
                    row = sheet.getRow(i);
                    if (row != null) {
                        cellData = (String) getCellFormatValue(row.getCell(3));
                        map.put("name", cellData);
                        cellData = (String) getCellFormatValue(row.getCell(5));
                        map.put("isviewed", cellData);
                        cellData = (String) getCellFormatValue(row.getCell(6));
                        map.put("entertime", cellData);
                        cellData = (String) getCellFormatValue(row.getCell(7));
                        map.put("viewtime", cellData);
                    } else {
                        break;
                    }
                    list.add(map);
                }

紧接着我们遍历解析出来的list,将人名统一,同时提取时间

因为人名可能会有多个,且由于同学命名规范不一,故这里需要处理人名,同时我也将时间处理了一下,将其变为以秒为单位的整数:

 //遍历解析出来的list,将人名统一,同时提取时间
                for (Map<String, String> map : list)
                {
                    int j = 0;
                    for (Entry<String, String> entry : map.entrySet()) {
                        if (j == 0)//处理人名
                        {
                            entry.setValue(matchChinese(entry.getValue()));
                        }
                        if (j == 2)//处理时间
                        {
                            String[] strArr = entry.getValue().split(" ");
                            entry.setValue(changeTime(strArr[1]));
                        }
                        if (j == 3)//处理观看时间
                        {
                            String[] strArr = entry.getValue().split("分");
                            if (strArr[0].equals("不足一"))
                                entry.setValue("1");
                            else {
                                entry.setValue(strArr[0]);
                            }
                        }
                        j++;
                    }
                }

然后我们需要整合重复的行,同时将信息处理;例如有两个刘淼同学,我们需要将刘淼同学最早进入的时间作为他最终的entertime,将两次进入后观看时长的和作为他最终的viewtime;

 for (int i = 0; i < list.size(); i++)   //整合重复
                {
                    for (int j = i; j < list.size(); j++) {
                        if (i == j) continue;//如果访问的是同一个则继续
                        int firstCount = 0;
                        boolean ifSame = false;
                        for (Entry<String, String> entry1 : list.get(i).entrySet()) {
                            int secondCount = 0;
                            for (Entry<String, String> entry2 : list.get(j).entrySet()) {
                                if (firstCount == 0 && secondCount == 0)
                                {
                                    String first = entry1.getValue();
                                    String second = entry2.getValue();
                                    if (first.equals(second))//同名
                                    {
                                        ifSame = true;
                                    }
                                }
                                if (firstCount == 2 && secondCount == 2 && ifSame == true)//到时间这了同时还同名保头数据
                                {
                                    int time1 = Integer.parseInt(entry1.getValue());
                                    int time2 = Integer.parseInt(entry2.getValue());
                                    if (time1 > time2)
                                        entry1.setValue(Integer.toString(time2));
                                }
                                if (firstCount == 3 && ifSame == true && secondCount == 3)//到了观看时长这了
                                {
                                    int time1 = Integer.parseInt(entry1.getValue());
                                    int time2 = Integer.parseInt(entry2.getValue());
                                    entry1.setValue(Integer.toString(time1 + time2));
                                    list.remove(list.get(j));
                                    j--;
                                }
                                secondCount++;
                            }
                            firstCount++;
                        }
                    }
                }

然后我们需要将得到的信息根据题目判断处理成1或0的形式,例如如果进入的时间晚于上课时间5min,则迟到这一栏则为1

for (Map<String, String> map_final : list)//信息写入 姓名,参加次数,迟到次数,早退次数
                {
                    int j = 0;
                    for (Entry<String, String> entry : map_final.entrySet()) {
                        if (j == 0)
                            System.out.println(entry.getValue());

                        if (j == 1)//处理参加次数
                        {
                            if (entry.getValue().equals("是")) {
                                entry.setValue("1");
                            } else {
                                entry.setValue("0");
                            }
                        }
                        if (j == 2)//处理迟到时间
                        {
                            int t = Integer.parseInt(entry.getValue());
                            int bt = Integer.parseInt(changeTime(startTime));
                            if (t - bt > 300)
                                entry.setValue("1");
                            else
                                entry.setValue("0");
                        }
                        if (j == 3)//处理观看时间
                        {
                            int t = Integer.parseInt(entry.getValue());
                            if (t < 60)
                                entry.setValue("1");
                            else {
                                entry.setValue("0");
                            }
                        }
                        j++;
                    }
                }
                System.out.println("---");
            }

这样对于一个文件的腾讯课堂的处理便结束了;

腾讯会议:

腾讯会议的输出文件如下:

《腾讯会议腾讯课堂考勤工具》

可以看到腾讯会议的输出结构是:

  • 第一行无用数据

  • 第5列为姓名

  • 第6列为入会时间

  • 第7列为退会时间

  • 第8列为观看时长

    那么同上,我们根据这样的结果对数据进行处理:

    数据读取:

    if(((String) getCellFormatValue(row.getCell(0))).equals("预定开始时间"))//腾讯会议
    {
        //获取最大列数
        int colnum = 9;
        for (int i = 1; i < rownum; i++)
        {
            Map<String, String> map = new LinkedHashMap<String, String>();
            row = sheet.getRow(i);
            if (row != null) {
                cellData = (String) getCellFormatValue(row.getCell(4));
                map.put("name", cellData);
                cellData = (String) getCellFormatValue(row.getCell(5));
                map.put("entertime", cellData);
                cellData = (String) getCellFormatValue(row.getCell(6));
                map.put("outtime", cellData);
                cellData = (String) getCellFormatValue(row.getCell(7));
                map.put("viewtime", cellData);
            } else {
                break;
            }
            list.add(map);
        }
    
    //遍历解析出来的list,将人名统一,同时提取时间
    for (Map<String, String> map : list)
    {
        int j = 0;
        for (Entry<String, String> entry : map.entrySet()) {
            if (j == 0)//处理人名
            {
                entry.setValue(matchChinese(entry.getValue()));
            }
            if (j == 1)//处理进入时间
            {
                String[] strArr = entry.getValue().split(" ");
                entry.setValue(changeTime(strArr[1]));
            }
            if (j == 2)//处理退出时间
            {
                String[] strArr = entry.getValue().split(" ");
                entry.setValue(changeTime(strArr[1]));
            }
            if (j == 3)//处理观看时间
            {
                entry.setValue(changeTime(entry.getValue()));
            }
            j++;
        }
    }
    
    for (int i = 0; i < list.size(); i++)   //整合重复
    {
        for (int j = i; j <list.size(); j++) {
            if (i == j) continue;//如果访问的是同一个则继续
            int firstCount = 0;
            boolean ifSame = false;
            for (Entry<String, String> entry1 : list.get(i).entrySet()) {
                int secondCount = 0;
                for (Entry<String, String> entry2 : list.get(j).entrySet()) {
                    if (firstCount == 0 && secondCount == 0) //是否同名
                    {
                        String first = entry1.getValue();
                        String second = entry2.getValue();
                        if (first.equals(second))//同名
                        {
                            ifSame = true;
                        }
                    }
                    if (firstCount == 1 && secondCount == 1 && ifSame == true)//到入会时间这了同时还同名
                    {
                        int time1 = Integer.parseInt(entry1.getValue());
                        int time2 = Integer.parseInt(entry2.getValue());
                        if (time1 > time2)
                            entry1.setValue(Integer.toString(time2));
                    }
                    if (firstCount == 2 && secondCount == 2 && ifSame == true)//到出会时间这了同时还同名
                    {
                        int time1 = Integer.parseInt(entry1.getValue());
                        int time2 = Integer.parseInt(entry2.getValue());
                        if (time1 < time2)
                            entry1.setValue(Integer.toString(time2));
                    }
                    if (firstCount == 3 && ifSame == true && secondCount == 3)//到了观看时长这了
                    {
                        int time1 = Integer.parseInt(entry1.getValue());
                        int time2 = Integer.parseInt(entry2.getValue());
                        entry1.setValue(Integer.toString(time1 + time2));
                        list.remove(list.get(j));
                        j--;
                    }
                    secondCount++;
                }
                firstCount++;
            }
        }
    }
    
 for (Map<String, String> map_final : list)//信息写入 姓名,参加次数,迟到次数,早退次数
    {
        int j = 0;
        boolean islate=false;
        boolean isEarlyLeave=false;
        for (Entry<String, String> entry : map_final.entrySet())
        {
            if (j == 0)
                System.out.println(entry.getValue());
            if (j == 1)//处理参加次数
            {
                int t = Integer.parseInt(entry.getValue());
                int bt = Integer.parseInt(changeTime(startTime));
                if (t - bt > 300)
                    islate=true;
                else
                    islate=false;
                entry.setValue("1");

            }
            if (j == 2)//处理迟到时间
            {
                int t = Integer.parseInt(entry.getValue());
                int bt = Integer.parseInt(changeTime(endTime));
                if (bt-t >300)
                    isEarlyLeave=true;
                else {
                    isEarlyLeave=false;
                }
                if(islate==true)
                    entry.setValue("1");
                else
                    entry.setValue("0");
            }
            if (j == 3)//处理观看时间
            {
               int t=Integer.parseInt(entry.getValue());
               if(t<3600||isEarlyLeave==true)
                   entry.setValue("1");
               else
                   entry.setValue("0");

            }
            j++;
        }
    }
}

当然为了完成上面两种数据的处理,我们需要写一些其他的辅助函数来帮助我们,例如:

public static String changeTime(String time)//将时间转换成秒类型的整数,同时需要注意处理数据类型,因为腾讯会议和课堂输出													的时间格式略有差异,同时老师给的时间格式和他们也有差异
{
    String[]str=time.split(":");
    int hour=Integer.parseInt(str[0]);
    int minute=Integer.parseInt(str[1]);
    int result;
    if(str.length==3)
    {
        int second=Integer.parseInt(str[2]);
        result=hour*3600+minute*60+second;
    }
    else
    {
        result=hour*3600+minute*60;
    }
    return Integer.toString(result);
}
public static String matchChinese(String strE)//匹配中文,这里是在一串字符串中找到精准人名以实现名字的统一
{
        String pattern = "[\\u4E00-\\u9FA5]+";
        String[] splitStr = strE.split("");
        StringBuffer result=new StringBuffer();
        for(String str:splitStr)
        {
            if(Pattern.matches(pattern, str))
                result.append(str);
        }
        return result.toString();
}

那么最后呢我们对一个Excel文件能进行了处理,于是我写了另一个类SignInStatistic来整体处理读取条件文本同时对结果进行文本输出:

public static List<Map<String,String>> finalList;
public static void main(String[]args)
{
    finalList = new ArrayList<Map<String,String>>();
    File file = new File("D:\\JavaLearning\\lab3-2020\\data\\file-list.txt");
    BufferedReader reader = null;
    try {
        System.out.println("以行为单位读取文件内容,一次读一整行:");
        reader = new BufferedReader(new FileReader(file));
        String tempString = null;
        // 一次读入一行,直到读入null为文件结束
        int i=0;
        while ((tempString = reader.readLine()) != null) {
            if(i!=0&&!tempString.equals(""))
                inputData(tempString);
            i++;
        }
        reader.close();
        dealData();
        fileWrite("D:\\JavaLearning\\lab3-2020\\data\\result.txt");
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (reader != null) {
            try {
                reader.close();
            } catch (IOException e1) {
            }
        }
    }
}
public static void dealData()
{
    int deleteNum=0;
    int rownum=finalList.size();
    for(int i=0;i<rownum-deleteNum;i++)   //整合重复
    {
        for(int j=0;j<rownum-deleteNum;j++)
        {
            if(i==j)continue;//如果访问的是同一个则继续
            int firstCount=0;
            boolean ifSame=false;
            for (Map.Entry<String,String> entry1 : finalList.get(i).entrySet())
            {
                int secondCount=0;
                for (Map.Entry<String,String> entry2 : finalList.get(j).entrySet())
                {
                    if(firstCount==0&&secondCount==0)
                    {
                        String first=entry1.getValue();
                        String second=entry2.getValue();
                        if(first.equals(second))//同名
                        {
                            ifSame=true;
                        }
                    }
                    if(firstCount==1&&secondCount==1&&ifSame==true)//到参加次数这了同时还同名
                    {
                        int time1=Integer.parseInt(entry1.getValue());
                        int time2=Integer.parseInt(entry2.getValue());
                        time2=time1+time2;
                        entry2.setValue(Integer.toString(time2));
                    }
                    if(firstCount==2&&secondCount==2&&ifSame==true)//到迟到次数这了同时还同名
                    {
                        int time1=Integer.parseInt(entry1.getValue());
                        int time2=Integer.parseInt(entry2.getValue());
                        time2=time1+time2;
                        entry2.setValue(Integer.toString(time2));
                    }
                    if(firstCount==3&&ifSame==true&&secondCount==3)//到早退次数观看时长这了
                    {
                        int time1=Integer.parseInt(entry1.getValue());
                        int time2=Integer.parseInt(entry2.getValue());
                        time2=time1+time2;
                        entry2.setValue(Integer.toString(time2));
                        finalList.remove(finalList.get(i));
                        deleteNum++;
                    }
                    secondCount++;
                }
                firstCount++;
            }
        }
    }
}
    原文作者:狗帅
    原文地址: https://blog.csdn.net/u011992422/article/details/106943091
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。

相关文章