腾讯会议腾讯课堂考勤工具
实习题目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
本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
相关文章