用Java实现两个Excel表格中数据的对比

起因

最近疫情又开始严重了,身为班长的我理所当然的又担负起了这个打卡的职责。(超级麻烦,因为每个班总有几个顽固分子你不给他私信打电话他是不会主动打卡的。。。)

他们打完卡之后我需要去根据今天的数据和昨天对比,看看是否有变化,因为大部分人即使位置变动了人也懒得标注- -!

于是在工作比较闲暇的今天我就想着琢磨一下能不能写个接口传上去能直接告诉我对比结果(其实这个用pyhon会简单很多,但是我不会),那么说干就干!

整理思路

开发环境:springboot

我为了节省时间直接在我的项目里面新增了个接口,用的是knife4j的测试文档,

其实想来也简单:

1、上传需要对比的两个excel

2、提取其中的数据

3、完成比对并打印结果

实体类:(根据实际需要修改)

public class SExcel {
    private String name;
    private String userId;
    private String finish;
    private Long number;
    private String health;
    private String city;
    private String address;
    private String plan;
    private String today;
    private String tomorrow;
    private String home;
    private String xxdz;
    
    //省略get、set方法
}

完整代码:

@Api(tags = "excel文件对比")
@RestController
@RequestMapping("excel")
public class CompareExcel {

    @ApiOperation("excel文件对比")
    @PostMapping("compareExcel")
    public List<SExcel> compareExcel(MultipartFile file1, MultipartFile file2) throws IOException {
        //读取前一天的excel文件的sheet1页面数据
        XSSFWorkbook oldExcel = new XSSFWorkbook(file1.getInputStream());
        Sheet sht0 = oldExcel.getSheetAt(0);
        //读取当天的excel文件的sheet1页面数据
        XSSFWorkbook newExcel = new XSSFWorkbook(file2.getInputStream());
        Sheet sht1 = newExcel.getSheetAt(0);

        //对将前一天的excel数据进行保存
        ArrayList<SExcel> oldList = new ArrayList<>();
        for (int i = 1; i < sht0.getPhysicalNumberOfRows(); i++) {
            Row row = sht0.getRow(i);//获取行,第一行为表头默认从第二行开始
            SExcel excel1 = new SExcel();
            row.getCell(2).setCellType(CellType.STRING);
            excel1.setName(row.getCell(2).getStringCellValue());
            row.getCell(6).setCellType(CellType.STRING);
            excel1.setUserId(row.getCell(6).getStringCellValue());
            row.getCell(7).setCellType(CellType.STRING);
            excel1.setFinish(row.getCell(7).getStringCellValue());
            row.getCell(8).setCellType(CellType.STRING);
            excel1.setNumber(Long.valueOf(row.getCell(8).getStringCellValue()));
            row.getCell(9).setCellType(CellType.STRING);
            excel1.setHealth(row.getCell(9).getStringCellValue());
            row.getCell(10).setCellType(CellType.STRING);
            excel1.setCity(row.getCell(10).getStringCellValue());
            row.getCell(11).setCellType(CellType.STRING);
            excel1.setAddress(row.getCell(11).getStringCellValue());
            row.getCell(12).setCellType(CellType.STRING);
            excel1.setPlan(row.getCell(12).getStringCellValue());
            row.getCell(15).setCellType(CellType.STRING);
            excel1.setToday(row.getCell(15).getStringCellValue());
            row.getCell(16).setCellType(CellType.STRING);
            excel1.setTomorrow(row.getCell(16).getStringCellValue());
            row.getCell(17).setCellType(CellType.STRING);
            excel1.setHome(row.getCell(17).getStringCellValue());
            row.getCell(18).setCellType(CellType.STRING);
            excel1.setXxdz(row.getCell(18).getStringCellValue());

            oldList.add(excel1);
        }

        //对将当天的excel数据进行保存
        ArrayList<SExcel> newList = new ArrayList<>();
        for (int i = 1; i < sht1.getPhysicalNumberOfRows(); i++) {
            Row row = sht1.getRow(i);//获取行,第一行为表头默认从第二行开始
            SExcel excel2 = new SExcel();
            row.getCell(2).setCellType(CellType.STRING);
            excel2.setName(row.getCell(2).getStringCellValue());
            row.getCell(6).setCellType(CellType.STRING);
            excel2.setUserId(row.getCell(6).getStringCellValue());
            row.getCell(7).setCellType(CellType.STRING);
            excel2.setFinish(row.getCell(7).getStringCellValue());
            row.getCell(8).setCellType(CellType.STRING);
            excel2.setNumber(Long.valueOf(row.getCell(8).getStringCellValue()));
            row.getCell(9).setCellType(CellType.STRING);
            excel2.setHealth(row.getCell(9).getStringCellValue());
            row.getCell(10).setCellType(CellType.STRING);
            excel2.setCity(row.getCell(10).getStringCellValue());
            row.getCell(11).setCellType(CellType.STRING);
            excel2.setAddress(row.getCell(11).getStringCellValue());
            row.getCell(12).setCellType(CellType.STRING);
            excel2.setPlan(row.getCell(12).getStringCellValue());
            row.getCell(15).setCellType(CellType.STRING);
            excel2.setToday(row.getCell(15).getStringCellValue());
            row.getCell(16).setCellType(CellType.STRING);
            excel2.setTomorrow(row.getCell(16).getStringCellValue());
            row.getCell(17).setCellType(CellType.STRING);
            excel2.setHome(row.getCell(17).getStringCellValue());
            row.getCell(18).setCellType(CellType.STRING);
            excel2.setXxdz(row.getCell(18).getStringCellValue());

            newList.add(excel2);
        }

        //关闭文件流释放空间
        oldExcel.close();
        newExcel.close();

        HashMap<String, String> hashMap = new HashMap<>();
        //将两天的数据进行比对
        ArrayList<SExcel> endExcel = new ArrayList<>();
        for (int i = 0; i < oldList.size(); i++) {
            SExcel sExcel = oldList.get(i);
            SExcel sExcel1 = newList.get(i);
            //分别取昨天和今天表中详细地址的**省**市**区做对比
            String a = sExcel.getXxdz();
            String b = sExcel1.getXxdz();
            int index = a.indexOf(",",a.indexOf(",",a.indexOf(",")+1)+1)+2;
            String old = a.substring(index, index+9);
            int index1 = b.indexOf(",",b.indexOf(",",b.indexOf(",")+1)+1)+2;
            String today = b.substring(index1, index1+9);
            //按照是否健康、今天位置变动、明天位置变动、详细地址作为对比依据,如果有不同的则导出
            if (!sExcel1.getHealth().equals("健康")
                    || sExcel1.getToday().equals("是")
                    || sExcel1.getTomorrow().equals("是")
                    || !old.equals(today)) {
                endExcel.add(newList.get(i));
                System.out.println(sExcel1.getName()+":"+old+"-------"+today);
            }
            if (sExcel1.getHome().equals("否")){
                hashMap.put(sExcel1.getName(),today);
            }
        }
        System.out.println("变动人员总数为:"+endExcel.size());
        System.out.println("不在学校的人数为:"+hashMap.size());
        System.out.println(hashMap);
        return endExcel;
    }
}

实际操作

进去测试文档页面后点击具体接口,然后上传文件,点击发送即可

结果如下:

Java对比 node java对比两个excel内容_Java对比 node


Java对比 node java对比两个excel内容_开发语言_02

过程问题

使用substring()方法出现下表越界问题

这个问题其实是我自己对于这个方法了解不够造成的

点进去substring()发现如下:

public String substring(int beginIndex, int endIndex) {
    if (beginIndex < 0) {
        throw new StringIndexOutOfBoundsException(beginIndex);
    }
    if (endIndex > value.length) {
        throw new StringIndexOutOfBoundsException(endIndex);
    }
    int subLen = endIndex - beginIndex;
    if (subLen < 0) {
        throw new StringIndexOutOfBoundsException(subLen);
    }
    return ((beginIndex == 0) && (endIndex == value.length)) ? this
            : new String(value, beginIndex, subLen);
}

也就是说如果传的两个参数(如果传一个默认结束位置为末尾)的话,分别是截取字符串的起止位置和终止位置,我一开始以为后面的参数是截取的长度所以导致了报错;

有待改进

我计划把这个独立出来配一个jsp页面,这样的话我可以直接打开网页输入网址就可以操作了,要不然我每次还得开服务输网址什么的,麻烦的很。


2021/11/08更新

主要改动:项目独立开出来了,直接用的springboot+thymeleaf引擎模板开发

新增接口:模板下载

@RequestMapping(value = "template",method = RequestMethod.GET)
    public void template(HttpServletResponse response){
        // 创建excel
        HSSFWorkbook wk = new HSSFWorkbook();
        // 创建一张工作表
        HSSFSheet sheet = wk.createSheet();
        // 2
        sheet.setColumnWidth(0, 5000);
        HSSFRow row = sheet.createRow(0);
        // 创建第一行的第一个单元格
        // 想单元格写值
        HSSFCell cell = row.createCell((short) 0);
        cell.setCellValue("提交人");
        cell = row.createCell((short)1);
        cell.setCellValue("提交时间");
        cell = row.createCell((short)2);
        cell.setCellValue("学生姓名");
        cell = row.createCell((short)3);
        cell.setCellValue("填写周期");
        cell = row.createCell((short)4);
        cell.setCellValue("星期");
        cell = row.createCell((short)5);
        cell.setCellValue("userId");
        cell = row.createCell((short)6);
        cell.setCellValue("是否填写");
        cell = row.createCell((short)7);
        cell.setCellValue("学号");
        cell = row.createCell((short)8);
        cell.setCellValue("目前健康状况");
        cell = row.createCell((short)9);
        cell.setCellValue("当前所在城市");
        cell = row.createCell((short)10);
        cell.setCellValue("当日所在位置");
        cell = row.createCell((short)11);
        cell.setCellValue("目前健康状况");
        cell = row.createCell((short)12);
        cell.setCellValue("白天体温");
        cell = row.createCell((short)13);
        cell.setCellValue("晚上体温");
        cell = row.createCell((short)14);
        cell.setCellValue("今日所在位置是否有变化");
        cell = row.createCell((short)15);
        cell.setCellValue("明日所在位置是否有变化");
        cell = row.createCell((short)16);
        cell.setCellValue("明日是否有出行计划");
        cell = row.createCell((short)17);
        cell.setCellValue("当前是否在校");
        cell = row.createCell((short)18);
        cell.setCellValue("当前时间,当前地点");

        try {
            /**
             * 弹出下载选择路径框
             */
            response.setContentType("application/octet-stream");
            response.setHeader("Content-disposition", "attachment;filename=template.xls");//默认Excel名称
            response.flushBuffer();
            wk.write(response.getOutputStream());
//            wk.write(new FileOutputStream(new File("D://daochu/a.xls")));
            wk.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        finally {

        }
    }
}

项目结构

Java对比 node java对比两个excel内容_开发语言_03

页面展示:

Java对比 node java对比两个excel内容_后端_04


Java对比 node java对比两个excel内容_Java对比 node_05

在线网址:http://121.40.223.139:3013 Gitee地址:https://gitee.com/king_teng/compareExcel.git