纳税服务系统二(用户模块)【POI、用户唯一性校验】

POI Cannot add merged region XXX to sheet because it overlaps with an existing merged region问题解决 问题描述: java.lang.IllegalStateException: Cannot add merged region A1:B2 to sheet because it overlaps with an existing merged region (A1:C3). 问题分析: 1、使用POI的sheet.addMergedRegion()添加合并单元格信息方法,要合并的区域已经存在合并单元格,导致报错。 CellRangeAddress cellRangeAddress = new C 阅读详情

前言

用户模块:本文主要的知识点有以下:

  • 使用POI来操作Excel,对数据进行导入和导出

  • 对用户进行唯一性校验,不能同时出现相同的用户

POI基础

再次回到我们的用户模块上,我们发现还有两个功能没有完成:

640?wx_fmt=png
这里写图片描述

对于将网页中的数据导入或导出到excel文件中,我们是完全没有学习过的。但是呢,在Java中操作excel是相对常用的,因此也有组件供我们使用

JAVA中操作Excel的有两种比较主流的工具包

  • JXL

  • POI

这次我们主要学习的是POI操作excel。

JXL有一个缺陷,只能操作03或以前版本的excel,而POI可以操作97-07版本的。

面向对象看excel

首先,要用Java来操作excel的话,肯定用对象来指定excel相关的内容的。我们来看看excel由什么组成:

640?wx_fmt=png
这里写图片描述

POI是这样看的:

  • 整个excel称作为工作薄

  • 工作薄下可以创建很多张表,称作为工作表

  • 工作表有非常多的行

  • 行又可细分单元格【指定行的列就可以定位到工作表任意的位置了】

给我们一顿分析以后,我们发现它们之间是有从属关系的:

  • 工作表从属于工作薄

  • 行从属于工作表

  • 单元格从属于行

640?wx_fmt=png

640?wx_fmt=png

操作Excel步骤

导入POI开发包:

/** * 使用POI1无非操作Excel无非就4个步骤: * * 创建/读取工作薄 * 创建/读取工作表 * 创建/读取行 * 创建/读取单元格 * * * */

创建Excel并写入数据

    @Test    public void testWrite() throws IOException {        //创建工作薄        HSSFWorkbook workbook = new HSSFWorkbook();        //创建工作表        HSSFSheet sheet = workbook.createSheet("我是新的工作表");        //创建行,坐标从0开始,我创建的是第三行        HSSFRow row = sheet.createRow(2);        //创建单元格,坐标也是从0开始,于是就是第三行第三列        HSSFCell cell = row.createCell(2);        //往单元格写数据        cell.setCellValue("helloWorld");        //把工作薄写到硬盘中        FileOutputStream outputStream = new FileOutputStream("C:\\工作薄.xls");        workbook.write(outputStream);        //关闭流        workbook.close();        outputStream.close();    }
   public void testWrite() throws IOException {

       //创建工作薄
       HSSFWorkbook workbook = new HSSFWorkbook();

       //创建工作表
       HSSFSheet sheet = workbook.createSheet("我是新的工作表");

       //创建行,坐标从0开始,我创建的是第三行
       HSSFRow row = sheet.createRow(2);

       //创建单元格,坐标也是从0开始,于是就是第三行第三列
       HSSFCell cell = row.createCell(2);

       //往单元格写数据
       cell.setCellValue("helloWorld");

       //把工作薄写到硬盘中
       FileOutputStream outputStream = new FileOutputStream("C:\\工作薄.xls");
       workbook.write(outputStream);

       //关闭流
       workbook.close();
       outputStream.close();

   }
640?wx_fmt=png
这里写图片描述
640?wx_fmt=png
这里写图片描述

读取Excel的数据

    @Test    public void testRead() throws IOException {        //获取输入流,读取Excel数据        FileInputStream inputStream = new FileInputStream("C:\\工作薄.xls");        //创建工作薄        HSSFWorkbook workbook = new HSSFWorkbook(inputStream);        //得到工作表        HSSFSheet sheet = workbook.getSheetAt(0);        //得到行        HSSFRow row = sheet.getRow(2);        //得到单元格        HSSFCell cell = row.getCell(2);        //得到单元格的数据        String cellValue = cell.getStringCellValue();        System.out.println(cellValue);    }
   public void testRead() throws IOException {

       //获取输入流,读取Excel数据
       FileInputStream inputStream = new FileInputStream("C:\\工作薄.xls");

       //创建工作薄
       HSSFWorkbook workbook = new HSSFWorkbook(inputStream);

       //得到工作表
       HSSFSheet sheet = workbook.getSheetAt(0);

       //得到行
       HSSFRow row = sheet.getRow(2);

       //得到单元格
       HSSFCell cell = row.getCell(2);

       //得到单元格的数据
       String cellValue = cell.getStringCellValue();

       System.out.println(cellValue);

   }
640?wx_fmt=png
这里写图片描述
640?wx_fmt=png
这里写图片描述

03与07版本

其实他们的方法都是一样的,仅仅是类的不同。而使用哪个对象,我们可以根据后缀名来判断创建哪个对象【是03还是07】

    @Test    public void testRead03And07Excel() throws Exception {        String fileName = "D:\\itcast\\测试.xlsx";        if(fileName.matches("^.+\\.(?i)((xls)|(xlsx))$")){//判断是否excel文档            boolean is03Excel = fileName.matches("^.+\\.(?i)(xls)$");            FileInputStream inputStream = new FileInputStream(fileName);            //1、读取工作簿            Workbook workbook = is03Excel ?new HSSFWorkbook(inputStream):new XSSFWorkbook(inputStream);            //2、读取第一个工作表            Sheet sheet = workbook.getSheetAt(0);            //3、读取行;读取第3行            Row row = sheet.getRow(2);            //4、读取单元格;读取第3行第3列            Cell cell = row.getCell(2);            System.out.println("第3行第3列单元格的内容为:" + cell.getStringCellValue());            workbook.close();            inputStream.close();        }    }
   public void testRead03And07Excel() throws Exception {
       String fileName = "D:\\itcast\\测试.xlsx";
       if(fileName.matches("^.+\\.(?i)((xls)|(xlsx))$")){//判断是否excel文档

           boolean is03Excel = fileName.matches("^.+\\.(?i)(xls)$");

           FileInputStream inputStream = new FileInputStream(fileName);

           //1、读取工作簿
           Workbook workbook = is03Excel ?new HSSFWorkbook(inputStream):new XSSFWorkbook(inputStream);
           //2、读取第一个工作表
           Sheet sheet = workbook.getSheetAt(0);
           //3、读取行;读取第3行
           Row row = sheet.getRow(2);
           //4、读取单元格;读取第3行第3列
           Cell cell = row.getCell(2);
           System.out.println("第3行第3列单元格的内容为:" + cell.getStringCellValue());

           workbook.close();
           inputStream.close();
       }
   }

Excel样式

回到我们的需求中,当我们使用POI导出数据的时候,Excel应该要有样式才好看的。类似下面的模板:

640?wx_fmt=png
这里写图片描述

在POI中可以利用格式化对象来格式化excel文档;也即设置excel内容的样式。

POI中主要的格式化对象常用的有:

POI的样式对象明显是属性工作薄的。应用于工作表

640?wx_fmt=png
这里写图片描述

合并单元格

属于工作薄,应用于工作表

创建合并单元格对象的时候要给出4个参数,它们分别表示:

    @Test    public void testCellRange() throws IOException {        //创建工作薄        HSSFWorkbook workbook = new HSSFWorkbook();        //创建合并单元格对象,从第六行开始到第十行,从第六列开始,到第十列        CellRangeAddress cellRangeAddress = new CellRangeAddress(5, 9, 5, 9);        //创建工作表        HSSFSheet sheet = workbook.createSheet("我是新的工作表");        //应用于工作表        sheet.addMergedRegion(cellRangeAddress);        //创建行,坐标从0开始,我创建的是第六行        HSSFRow row = sheet.createRow(5);        //创建单元格,坐标也是从0开始,于是就是第六行第六列        HSSFCell cell = row.createCell(5);        //往单元格写数据        cell.setCellValue("helloWorld");        //把工作薄写到硬盘中        FileOutputStream outputStream = new FileOutputStream("C:\\工作薄.xls");        workbook.write(outputStream);        //关闭流        workbook.close();        outputStream.close();    }
   public void testCellRange() throws IOException {

       //创建工作薄
       HSSFWorkbook workbook = new HSSFWorkbook();

       //创建合并单元格对象,从第六行开始到第十行,从第六列开始,到第十列
       CellRangeAddress cellRangeAddress = new CellRangeAddress(5, 9, 5, 9);

       //创建工作表
       HSSFSheet sheet = workbook.createSheet("我是新的工作表");

       //应用于工作表
       sheet.addMergedRegion(cellRangeAddress);

       //创建行,坐标从0开始,我创建的是第六行
       HSSFRow row = sheet.createRow(5);

       //创建单元格,坐标也是从0开始,于是就是第六行第六列
       HSSFCell cell = row.createCell(5);

       //往单元格写数据
       cell.setCellValue("helloWorld");

       //把工作薄写到硬盘中
       FileOutputStream outputStream = new FileOutputStream("C:\\工作薄.xls");
       workbook.write(outputStream);

       //关闭流
       workbook.close();
       outputStream.close();

   }
640?wx_fmt=png
这里写图片描述

设置单元格样式

上面的图我们可以发现,我们已经实现了合并单元格,但是一般我们都是将字体设置成居中、字体大小等等。POI也提供了相对应的对象给我们实现:

设置居中

样式属于工作薄,应用于单元格:

    @Test    public void test() throws IOException {        //创建工作薄        HSSFWorkbook workbook = new HSSFWorkbook();        //创建样式对象        HSSFCellStyle style = workbook.createCellStyle();        //创建合并单元格对象,从第六行开始到第十行,从第六列开始,到第十列        CellRangeAddress cellRangeAddress = new CellRangeAddress(5, 9, 5, 9);        //设置水平居中        style.setAlignment(HSSFCellStyle.ALIGN_CENTER);        //设置垂直居中        style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);        //创建工作表        HSSFSheet sheet = workbook.createSheet("我是新的工作表");        sheet.addMergedRegion(cellRangeAddress);        //创建行,坐标从0开始,我创建的是第六行        HSSFRow row = sheet.createRow(5);        //创建单元格,坐标也是从0开始,于是就是第六行第六列        HSSFCell cell = row.createCell(5);        //往单元格写数据        cell.setCellValue("helloWorld");        //设置单元格的样式        cell.setCellStyle(style);        //把工作薄写到硬盘中        FileOutputStream outputStream = new FileOutputStream("C:\\工作薄.xls");        workbook.write(outputStream);        //关闭流        workbook.close();        outputStream.close();    }
   public void test() throws IOException {

       //创建工作薄
       HSSFWorkbook workbook = new HSSFWorkbook();

       //创建样式对象
       HSSFCellStyle style = workbook.createCellStyle();

       //创建合并单元格对象,从第六行开始到第十行,从第六列开始,到第十列
       CellRangeAddress cellRangeAddress = new CellRangeAddress(5, 9, 5, 9);

       //设置水平居中
       style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
       //设置垂直居中
       style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);

       //创建工作表
       HSSFSheet sheet = workbook.createSheet("我是新的工作表");

       sheet.addMergedRegion(cellRangeAddress);
       //创建行,坐标从0开始,我创建的是第六行
       HSSFRow row = sheet.createRow(5);

       //创建单元格,坐标也是从0开始,于是就是第六行第六列
       HSSFCell cell = row.createCell(5);

       //往单元格写数据
       cell.setCellValue("helloWorld");

       //设置单元格的样式
       cell.setCellStyle(style);

       //把工作薄写到硬盘中
       FileOutputStream outputStream = new FileOutputStream("C:\\工作薄.xls");
       workbook.write(outputStream);

       //关闭流
       workbook.close();
       outputStream.close();

   }
640?wx_fmt=png
这里写图片描述

设置字体

字体属于工作薄,应用于样式【和css是类似的】

    @Test    public void test() throws IOException {        //创建工作薄        HSSFWorkbook workbook = new HSSFWorkbook();        //创建样式对象        HSSFCellStyle style = workbook.createCellStyle();        //创建合并单元格对象,从第六行开始到第十行,从第六列开始,到第十列        CellRangeAddress cellRangeAddress = new CellRangeAddress(5, 9, 5, 9);        //设置水平居中        style.setAlignment(HSSFCellStyle.ALIGN_CENTER);        //设置垂直居中        style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);        //创建font对象        HSSFFont font = workbook.createFont();        //设置字体为粗体        font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);        //字体为23字号        font.setFontHeightInPoints((short) 23);        //设置字体的颜色        font.setColor(HSSFFont.COLOR_RED);        //字体应用于样式        style.setFont(font);        //创建工作表        HSSFSheet sheet = workbook.createSheet("我是新的工作表");        sheet.addMergedRegion(cellRangeAddress);        //创建行,坐标从0开始,我创建的是第六行        HSSFRow row = sheet.createRow(5);        //创建单元格,坐标也是从0开始,于是就是第六行第六列        HSSFCell cell = row.createCell(5);        //往单元格写数据        cell.setCellValue("helloWorld");        //设置单元格的样式        cell.setCellStyle(style);        //把工作薄写到硬盘中        FileOutputStream outputStream = new FileOutputStream("C:\\工作薄.xls");        workbook.write(outputStream);        //关闭流        workbook.close();        outputStream.close();    }
   public void test() throws IOException {

       //创建工作薄
       HSSFWorkbook workbook = new HSSFWorkbook();

       //创建样式对象
       HSSFCellStyle style = workbook.createCellStyle();

       //创建合并单元格对象,从第六行开始到第十行,从第六列开始,到第十列
       CellRangeAddress cellRangeAddress = new CellRangeAddress(5, 9, 5, 9);

       //设置水平居中
       style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
       //设置垂直居中
       style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);

       //创建font对象
       HSSFFont font = workbook.createFont();

       //设置字体为粗体
       font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
       //字体为23字号
       font.setFontHeightInPoints((short) 23);
       //设置字体的颜色
       font.setColor(HSSFFont.COLOR_RED);

       //字体应用于样式
       style.setFont(font);

       //创建工作表
       HSSFSheet sheet = workbook.createSheet("我是新的工作表");

       sheet.addMergedRegion(cellRangeAddress);
       //创建行,坐标从0开始,我创建的是第六行
       HSSFRow row = sheet.createRow(5);

       //创建单元格,坐标也是从0开始,于是就是第六行第六列
       HSSFCell cell = row.createCell(5);

       //往单元格写数据
       cell.setCellValue("helloWorld");

       //设置单元格的样式
       cell.setCellStyle(style);

       //把工作薄写到硬盘中
       FileOutputStream outputStream = new FileOutputStream("C:\\工作薄.xls");
       workbook.write(outputStream);

       //关闭流
       workbook.close();
       outputStream.close();

   }
640?wx_fmt=png
这里写图片描述

实现导出功能

绑定按钮事件,请求Action处理导出,打开一个输入框给用户下载

        function doExportExcel() {            window.open("${basePath}user/user_exportExcel.action");           }
           window.open("${basePath}user/user_exportExcel.action");  
       }

Action处理

    /************导出Excel*************************/    public void exportExcel() throws IOException {        //查找出列表的全部数据        List<User> list = userServiceImpl.findObjects();        //导出其实就是让用户下载该Excel文件        HttpServletResponse response = ServletActionContext.getResponse();        //设置头和指定名称        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("列表展示.xls", "UTF-8"));        //指定返回的类容数据        response.setContentType("application/x-execl");        ServletOutputStream outputStream = response.getOutputStream();        //给Service层做导出Excel操作        userServiceImpl.exportExcel(list, outputStream);    }
   public void exportExcel() throws IOException {

       //查找出列表的全部数据
       List<User> list = userServiceImpl.findObjects();

       //导出其实就是让用户下载该Excel文件
       HttpServletResponse response = ServletActionContext.getResponse();

       //设置头和指定名称
       response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("列表展示.xls", "UTF-8"));
       //指定返回的类容数据
       response.setContentType("application/x-execl");

       ServletOutputStream outputStream = response.getOutputStream();

       //给Service层做导出Excel操作
       userServiceImpl.exportExcel(list, outputStream);

   }

Service实现

    /**     * 第一行写死,字体大小11,居中,粗体,合并单元格     * 第二行写死,粗体     * 第三行开始,是数据库列表的数据     */    @Override    public void exportExcel(List<User> list, ServletOutputStream outputStream) {        /***********创建工作薄---样式---字体--单元格*************/        HSSFWorkbook workbook = new HSSFWorkbook();        //第一行的合并单元格        CellRangeAddress cellRangeAddress = new CellRangeAddress(0, 0, 0, 4);        //创建第一行样式【居中】        HSSFCellStyle cellStyle = workbook.createCellStyle();        cellStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);        cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);        //创建第二行样式【居中】        HSSFCellStyle cellStyle2 = workbook.createCellStyle();        cellStyle2.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);        cellStyle2.setAlignment(HSSFCellStyle.ALIGN_CENTER);        //创建第一行字体        HSSFFont font = workbook.createFont();        font.setFontHeightInPoints((short) 23);        font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);        //创建第二行字体        HSSFFont font2 = workbook.createFont();        font2.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);        //字体应用于样式        cellStyle.setFont(font);        cellStyle2.setFont(font2);        /***********创建工作表*************/        HSSFSheet sheet = workbook.createSheet("用户列表");        //第一行单元格应用于工作表        sheet.addMergedRegion(cellRangeAddress);        //设置默认列宽        sheet.setDefaultColumnWidth(25);        /***********创建行*************/        //第一行        HSSFRow row = sheet.createRow(0);        HSSFCell cell = row.createCell(0);        cell.setCellStyle(cellStyle);        cell.setCellValue("用户列表");        //第二行数据也是写死的,我们用数组遍历即可        String[] data = {"用户名","帐号", "所属部门", "性别", "电子邮箱"};        HSSFRow row1 = sheet.createRow(1);        for (int i = 0; i < data.length; i++) {            HSSFCell cell1 = row1.createCell(i);            cell1.setCellValue(data[i]);            //加载第二行样式            cell1.setCellStyle(cellStyle2);        }        /***************行和列在循环的时候,不要重复了。不然会报错的!!!!*****************/        //第三行数据就是我们数据库保存的数据        if (list != null) {            int i=2;            for (User user : list) {                //从第三行开始                HSSFRow row2 = sheet.createRow(i);                HSSFCell row2Cel0 = row2.createCell(0);                row2Cel0.setCellValue(user.getName());                HSSFCell row2Cell = row2.createCell(1);                row2Cell.setCellValue(user.getAccount());                HSSFCell row2Cel2 = row2.createCell(2);                row2Cel2.setCellValue(user.getDept());                HSSFCell row2Cel3 = row2.createCell(3);                row2Cel3.setCellValue(user.isGender() ? "男" : "女");                HSSFCell row2Cel4 = row2.createCell(4);                row2Cel4.setCellValue(user.getEmail());                i++;            }        }        try {            //写到outputSteam上            workbook.write(outputStream);            workbook.close();            outputStream.close();        } catch (IOException e) {            e.printStackTrace();        }    }
   @Override
   public void exportExcel(List<User> list, ServletOutputStream outputStream) {

       /***********创建工作薄---样式---字体--单元格*************/
       HSSFWorkbook workbook = new HSSFWorkbook();

       //第一行的合并单元格
       CellRangeAddress cellRangeAddress = new CellRangeAddress(0, 0, 0, 4);

       //创建第一行样式【居中】
       HSSFCellStyle cellStyle = workbook.createCellStyle();
       cellStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
       cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);

       //创建第二行样式【居中】
       HSSFCellStyle cellStyle2 = workbook.createCellStyle();
       cellStyle2.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
       cellStyle2.setAlignment(HSSFCellStyle.ALIGN_CENTER);

       //创建第一行字体
       HSSFFont font = workbook.createFont();
       font.setFontHeightInPoints((short) 23);
       font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);

       //创建第二行字体
       HSSFFont font2 = workbook.createFont();
       font2.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);

       //字体应用于样式
       cellStyle.setFont(font);
       cellStyle2.setFont(font2);

       /***********创建工作表*************/
       HSSFSheet sheet = workbook.createSheet("用户列表");

       //第一行单元格应用于工作表
       sheet.addMergedRegion(cellRangeAddress);

       //设置默认列宽
       sheet.setDefaultColumnWidth(25);

       /***********创建行*************/
       //第一行
       HSSFRow row = sheet.createRow(0);
       HSSFCell cell = row.createCell(0);
       cell.setCellStyle(cellStyle);
       cell.setCellValue("用户列表");

       //第二行数据也是写死的,我们用数组遍历即可
       String[] data = {"用户名","帐号", "所属部门", "性别", "电子邮箱"};
       HSSFRow row1 = sheet.createRow(1);
       for (int i = 0; i < data.length; i++) {
           HSSFCell cell1 = row1.createCell(i);
           cell1.setCellValue(data[i]);

           //加载第二行样式
           cell1.setCellStyle(cellStyle2);

       }


       /***************行和列在循环的时候,不要重复了。不然会报错的!!!!*****************/
       //第三行数据就是我们数据库保存的数据

       if (list != null) {
           int i=2;
           for (User user : list) {

               //从第三行开始
               HSSFRow row2 = sheet.createRow(i);

               HSSFCell row2Cel0 = row2.createCell(0);
               row2Cel0.setCellValue(user.getName());

               HSSFCell row2Cell = row2.createCell(1);
               row2Cell.setCellValue(user.getAccount());

               HSSFCell row2Cel2 = row2.createCell(2);
               row2Cel2.setCellValue(user.getDept());

               HSSFCell row2Cel3 = row2.createCell(3);
               row2Cel3.setCellValue(user.isGender() ? "男" : "女");

               HSSFCell row2Cel4 = row2.createCell(4);
               row2Cel4.setCellValue(user.getEmail());

               i++;
           }
       }
       try {
           //写到outputSteam上
           workbook.write(outputStream);

           workbook.close();
           outputStream.close();

       } catch (IOException e) {
           e.printStackTrace();
       }


   }

效果

640?wx_fmt=png
这里写图片描述

优化一

我们来看下面这段代码,他们都要设置居中,字体就除了大小不同。其他都相同。却占用了这么多代码!!!

        //创建第一行样式【居中】        HSSFCellStyle cellStyle = workbook.createCellStyle();        cellStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);        cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);        //创建第二行样式【居中】        HSSFCellStyle cellStyle2 = workbook.createCellStyle();        cellStyle2.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);        cellStyle2.setAlignment(HSSFCellStyle.ALIGN_CENTER);        //创建第一行字体        HSSFFont font = workbook.createFont();        font.setFontHeightInPoints((short) 23);        font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);        //创建第二行字体        HSSFFont font2 = workbook.createFont();        font2.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);        //字体应用于样式        cellStyle.setFont(font);        cellStyle2.setFont(font2);
       HSSFCellStyle cellStyle = workbook.createCellStyle();
       cellStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
       cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);

       //创建第二行样式【居中】
       HSSFCellStyle cellStyle2 = workbook.createCellStyle();
       cellStyle2.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
       cellStyle2.setAlignment(HSSFCellStyle.ALIGN_CENTER);

       //创建第一行字体
       HSSFFont font = workbook.createFont();
       font.setFontHeightInPoints((short) 23);
       font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);

       //创建第二行字体
       HSSFFont font2 = workbook.createFont();
       font2.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);

       //字体应用于样式
       cellStyle.setFont(font);
       cellStyle2.setFont(font2);

于是我就抽取成一个方法来得到样式

    /**     * @param workbook 当前使用工作薄     * @param fontSize 字体大小     *     * */    public HSSFCellStyle createStyle(HSSFWorkbook workbook, short fontSize) {        HSSFCellStyle cellStyle = workbook.createCellStyle();        cellStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);        cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);        HSSFFont font = workbook.createFont();        font.setFontHeightInPoints(fontSize);        font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);        cellStyle.setFont(font);        return cellStyle;    }
   public HSSFCellStyle createStyle(HSSFWorkbook workbook, short fontSize) {

       HSSFCellStyle cellStyle = workbook.createCellStyle();
       cellStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
       cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);

       HSSFFont font = workbook.createFont();
       font.setFontHeightInPoints(fontSize);
       font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
       cellStyle.setFont(font);

       return cellStyle;
   }

当使用的时候,代码就变成了这样调用:

        HSSFCellStyle cellStyle = createStyle(workbook, (short) 24);        HSSFCellStyle cellStyle2 = createStyle(workbook, (short) 13);24);
       HSSFCellStyle cellStyle2 = createStyle(workbook, (short) 13);

优化二

我们的Service业务层的代码看起来太多了。这样我们维护起来就不方便了。

我的做法是:把代码抽取成Utils的方法,Service层调用就好了。

640?wx_fmt=png


实现导入功能

现在我有这么一个Excel文件,要把信息存储到数据库中,并且在浏览器显示出来

640?wx_fmt=png
这里写图片描述

其实导入Excel就是文件上传,只不过不用把文件保存在服务器的硬盘数据中而是保存在数据库中,输出到浏览器就行了。

        function doImportExcel() {            document.forms[0].action = "${basePath}user/user_importExcel.action";            document.forms[0].submit();        }
           document.forms[0].action = "${basePath}user/user_importExcel.action";
           document.forms[0].submit();

       }

Action封装文件上传

/*************上传Excel************************/    private File userExcel;    private String userExcelFileName;    private String userExcelContentType;    public void setUserExcel(File userExcel) {        this.userExcel = userExcel;    }    public void setUserExcelFileName(String userExcelFileName) {        this.userExcelFileName = userExcelFileName;    }    public void setUserExcelContentType(String userExcelContentType) {        this.userExcelContentType = userExcelContentType;    }
   private File userExcel;
   private String userExcelFileName;
   private String userExcelContentType;

   public void setUserExcel(File userExcel) {
       this.userExcel = userExcel;
   }

   public void setUserExcelFileName(String userExcelFileName) {
       this.userExcelFileName = userExcelFileName;
   }

   public void setUserExcelContentType(String userExcelContentType) {
       this.userExcelContentType = userExcelContentType;
   }

Action处理

主要判断有没有上传文件。给Service层处理

    /************导入Excel*************************/    public String importExcel() throws IOException {        //1、获取excel文件        if(userExcel != null){            //是否是excel            if(userExcelFileName.matches("^.+\\.(?i)((xls)|(xlsx))$")){                //2、导入                userServiceImpl.importExcel(userExcel, userExcelFileName);            }        }        return "list";    }
   public String importExcel() throws IOException {

       //1、获取excel文件
       if(userExcel != null){
           //是否是excel
           if(userExcelFileName.matches("^.+\\.(?i)((xls)|(xlsx))$")){
               //2、导入
               userServiceImpl.importExcel(userExcel, userExcelFileName);
           }
       }

       return "list";
   }

Utils封装成集合返回

 public static List<User> importExcel(File userExcel, String userExcelFileName) {        try {            FileInputStream fileInputStream = new FileInputStream(userExcel);            boolean is03Excel = userExcelFileName.matches("^.+\\.(?i)(xls)$");            //1、读取工作簿            Workbook workbook = is03Excel ? new HSSFWorkbook(fileInputStream) : new XSSFWorkbook(fileInputStream);            //2、读取工作表            Sheet sheet = workbook.getSheetAt(0);            //3、读取行             List<User> users = new ArrayList<>();            if (sheet.getPhysicalNumberOfRows() > 2) {                User user = null;                for (int k = 2; k < sheet.getPhysicalNumberOfRows(); k++) {                    //4、读取单元格                    Row row = sheet.getRow(k);                    user = new User();                    //用户名                    Cell cell0 = row.getCell(0);                    user.setName(cell0.getStringCellValue());                    //帐号                    Cell cell1 = row.getCell(1);                    user.setAccount(cell1.getStringCellValue());                    //所属部门                    Cell cell2 = row.getCell(2);                    user.setDept(cell2.getStringCellValue());                    //性别                    Cell cell3 = row.getCell(3);                    user.setGender(cell3.getStringCellValue().equals("男"));                    //手机号                    String mobile = "";                    Cell cell4 = row.getCell(4);                    try {                        mobile = cell4.getStringCellValue();                    } catch (Exception e) {                        double dMobile = cell4.getNumericCellValue();                        mobile = BigDecimal.valueOf(dMobile).toString();                    }                    user.setMobile(mobile);                    //电子邮箱                    Cell cell5 = row.getCell(5);                    user.setEmail(cell5.getStringCellValue());                    //生日                    Cell cell6 = row.getCell(6);                    if (cell6.getDateCellValue() != null) {                        user.setBirthday(cell6.getDateCellValue());                    }                    //默认用户密码为 123456                    user.setPassword("123456");                    //默认用户状态为 有效                    user.setState(User.USER_STATE_VALID);                    users.add(user);                }            }            workbook.close();            fileInputStream.close();            return users;        } catch (Exception e) {            e.printStackTrace();        }        return null;    }

       try {
           FileInputStream fileInputStream = new FileInputStream(userExcel);
           boolean is03Excel = userExcelFileName.matches("^.+\\.(?i)(xls)$");
           //1、读取工作簿
           Workbook workbook = is03Excel ? new HSSFWorkbook(fileInputStream) : new XSSFWorkbook(fileInputStream);
           //2、读取工作表
           Sheet sheet = workbook.getSheetAt(0);
           //3、读取行
            List<User> users = new ArrayList<>();
           if (sheet.getPhysicalNumberOfRows() > 2) {
               User user = null;
               for (int k = 2; k < sheet.getPhysicalNumberOfRows(); k++) {
                   //4、读取单元格
                   Row row = sheet.getRow(k);
                   user = new User();
                   //用户名
                   Cell cell0 = row.getCell(0);
                   user.setName(cell0.getStringCellValue());
                   //帐号
                   Cell cell1 = row.getCell(1);
                   user.setAccount(cell1.getStringCellValue());
                   //所属部门
                   Cell cell2 = row.getCell(2);
                   user.setDept(cell2.getStringCellValue());
                   //性别
                   Cell cell3 = row.getCell(3);
                   user.setGender(cell3.getStringCellValue().equals("男"));
                   //手机号
                   String mobile = "";
                   Cell cell4 = row.getCell(4);
                   try {
                       mobile = cell4.getStringCellValue();
                   } catch (Exception e) {
                       double dMobile = cell4.getNumericCellValue();
                       mobile = BigDecimal.valueOf(dMobile).toString();
                   }
                   user.setMobile(mobile);

                   //电子邮箱
                   Cell cell5 = row.getCell(5);
                   user.setEmail(cell5.getStringCellValue());
                   //生日
                   Cell cell6 = row.getCell(6);
                   if (cell6.getDateCellValue() != null) {
                       user.setBirthday(cell6.getDateCellValue());
                   }
                   //默认用户密码为 123456
                   user.setPassword("123456");
                   //默认用户状态为 有效
                   user.setState(User.USER_STATE_VALID);

                   users.add(user);

               }
           }
           workbook.close();
           fileInputStream.close();
           return users;

       } catch (Exception e) {
           e.printStackTrace();
       }
       return null;

   }

Service调用

    public void importExcel(File userExcel, String userExcelFileName) {        List<User> users = ExcelUtils.importExcel(userExcel, userExcelFileName);        for (User user : users) {            save(user);        }    }
       List<User> users = ExcelUtils.importExcel(userExcel, userExcelFileName);
       for (User user : users) {
           save(user);
       }
   }

用户唯一性校验

接下来是对其进行补充…主要完成用户唯一性校验的问题。

我们发现:在新增或编辑页面的时候用户的账号是可以重复的,这是不符合我们的逻辑的。

640?wx_fmt=png
这里写图片描述

当用户新增账号的时候,如果该账号已经存在了,就应该告诉用户该账号重复,不能使用该账号。

分析

用户在填写完账户的时候,就应该去做校验了。【使用AJAX】

校验的工作是什么呢????其实就是去查找数据库有没有对应的账户记录,如果有,那么就告诉用户存在了。如果没有,就没问题了。

上面已经说了有两处需要校验用户唯一性的问题:

新增页面和修改页面是有不同的处理方案的,因为在修改页面时,如果用户不修改账户,该用户的账户本来就存在了。因此我们要排除该用户的当前账户相同的问题,其实也很简单。


前台使用AJAX处理

为账户的输入框添加事件

当账户的输入框修改时,就去数据库查询有没有相同的账户名字。

值得注意的是:本来我是在控件上添加一个id,使用Jquery得到id所在的控件,然后绑定事件,但是用不了。

所以,我只能在控件上绑定一个静态方法了。

    <tr>        <td class="tdBg" width="200px">帐号:</td>        <td><s:textfield id="userAccount" name="user.account" onchange="doVerify()"/></td>    </tr>
       <td class="tdBg" width="200px">帐号:</td>
       <td><s:textfield id="userAccount" name="user.account" onchange="doVerify()"/></td>
   </tr>

把账号的值传递给服务器,接受服务器返回的值

        function doVerify() {            //得到输入的值            var account = $("#userAccount").val();            $.ajax({                type: "post",                url: "${basePath}user/user_doVerify.action",                data:{"user.account" :account},                success:function (backdata) {                    alert(backdata);                }            });        }
           //得到输入的值
           var account = $("#userAccount").val();

           $.ajax({
               type: "post",
               url: "${basePath}user/user_doVerify.action",
               data:{"user.account" :account},
               success:function (backdata) {
                   alert(backdata);
               }
           });
       }

编写Dao方法

我们使用的是Hibernate,编写的HQL语句是FROM 实体,并不是"SELECT * FROM….. "

    //因为我们不是在查id,因此是不能保证只有一个User对象的,即使在AJAX已经做了检查。因此返回值是个List集合    List<User> findAccount(String id, String account);
   List<User> findAccount(String id, String account);
    @Override    public List<User> findAccount(String id, String account) {        String hql = "FROM User WHERE account = ? ";        //判断有没有id,如果有id,多加个条件【本账户不算】        if (StringUtils.isNotBlank(id)) {            hql = hql + "  AND id!=?";        }        Query query = getSession().createQuery(hql);        query.setParameter(0, account);        if (StringUtils.isNotBlank(id)) {            query.setParameter(1, id);        }        List list = query.list();        return list;    }
   public List<User> findAccount(String id, String account) {

       String hql = "FROM User WHERE account = ? ";

       //判断有没有id,如果有id,多加个条件【本账户不算】
       if (StringUtils.isNotBlank(id)) {

           hql = hql + "  AND id!=?";
       }

       Query query = getSession().createQuery(hql);
       query.setParameter(0, account);
       if (StringUtils.isNotBlank(id)) {
           query.setParameter(1, id);
       }

       List list = query.list();
       return list;

   }

Service调用Dao

 List<User> findAccount(String id, String account);
    @Override    public List<User> findAccount(String id, String account) {        return userDaoImpl.findAccount(id, account);    }
   public List<User> findAccount(String id, String account) {
       return userDaoImpl.findAccount(id, account);
   }

Action处理

由于经常要判断传递过来的数据时候为null,是否为"",我们使用StringUtils来进行判断:

    /************账户一次性校验*************************/    public void doVerify() {        try {            //默认不存在            String exist = "false";            //判断账户是否为空,已经用户输入的数据。【我们使用StringUtils这个类来判断】            //isNotBlank封装了不为null和不为""            if (user != null && StringUtils.isNotBlank(user.getAccount())) {                List<User> list = userServiceImpl.findAccount(user.getId(), user.getAccount());                //如果查询到数据,那么说明该账户已经存在了。                if (list != null && list.size() > 0) {                    exist = "true";                }            }            HttpServletResponse response = ServletActionContext.getResponse();            response.setContentType("text/html");            ServletOutputStream outputStream = response.getOutputStream();            outputStream.write(exist.getBytes());            outputStream.close();        } catch (IOException e) {            e.printStackTrace();        }    }
   public void doVerify() {


       try {
           //默认不存在
           String exist = "false";

           //判断账户是否为空,已经用户输入的数据。【我们使用StringUtils这个类来判断】
           //isNotBlank封装了不为null和不为""
           if (user != null && StringUtils.isNotBlank(user.getAccount())) {
               List<User> list = userServiceImpl.findAccount(user.getId(), user.getAccount());

               //如果查询到数据,那么说明该账户已经存在了。
               if (list != null && list.size() > 0) {
                   exist = "true";
               }
           }
           HttpServletResponse response = ServletActionContext.getResponse();
           response.setContentType("text/html");
           ServletOutputStream outputStream = response.getOutputStream();
           outputStream.write(exist.getBytes());
           outputStream.close();
       } catch (IOException e) {
           e.printStackTrace();
       }

   }

前台提示

    <script type="text/javascript">        function doVerify() {            //得到输入的值            var account = $("#userAccount").val();            $.ajax({                type: "post",                url: "${basePath}user/user_doVerify.action",                data:{"user.account" :account},                success:function (backdata) {                    //当存在的时候,告诉用户该账户已经存在了。                    if(backdata=="true") {                        alert("该账户已经存在了!请用别的账户");                        //定焦                        $("#userAccount").focus();                    }else {                    }                }            });        }    </script>
       function doVerify() {
           //得到输入的值
           var account = $("#userAccount").val();

           $.ajax({
               type: "post",
               url: "${basePath}user/user_doVerify.action",
               data:{"user.account" :account},
               success:function (backdata) {

                   //当存在的时候,告诉用户该账户已经存在了。
                   if(backdata=="true") {
                       alert("该账户已经存在了!请用别的账户");

                       //定焦
                       $("#userAccount").focus();
                   }else {

                   }
               }
           });
       }
   </script>
640?wx_fmt=gif
这里写图片描述

完善

上面只是完成了校验用户名是否唯一的功能,但是如果用户不听我的劝告,照样去提交表单,还是可以完成的。

于是在提交表单的时候要判断是否合法才能让用户提交:

把submit按钮改成是button,提供单击事件

   <input type="button" class="btnB2" value="保存" onclick="doSubmit()" />
    <script type="text/javascript">        var Vresult = true;        function doVerify() {            //得到输入的值            var account = $("#userAccount").val();            $.ajax({                type: "post",                url: "${basePath}user/user_doVerify.action",                async:false,                data:{"user.account" :account},                success:function (backdata) {                    //当存在的时候,告诉用户该账户已经存在了。                    if(backdata=="true") {                        alert("该账户已经存在了!请用别的账户");                        //定焦                        $("#userAccount").focus();                        Vresult = false;                    }else {                        Vresult = true;                    }                }            });        }        function doSubmit() {            //在提交之前执行验证,但是验证又是异步的,因此要把异步改成同步            doVerify();            //判断能否提交表单            if(Vresult) {                document.forms[0].submit();            }        }    </script>
       var Vresult = true;
       function doVerify() {
           //得到输入的值
           var account = $("#userAccount").val();
           $.ajax({
               type: "post",
               url: "${basePath}user/user_doVerify.action",
               async:false,
               data:{"user.account" :account},
               success:function (backdata) {
                   //当存在的时候,告诉用户该账户已经存在了。
                   if(backdata=="true") {
                       alert("该账户已经存在了!请用别的账户");
                       //定焦
                       $("#userAccount").focus();
                       Vresult = false;
                   }else {
                       Vresult = true;
                   }
               }
           });
       }
       function doSubmit() {
           //在提交之前执行验证,但是验证又是异步的,因此要把异步改成同步
           doVerify();
           //判断能否提交表单
           if(Vresult) {
               document.forms[0].submit();
           }
       }
   
</script>

editUI

在editUI上唯一区别就是需要把id传递过去给服务器端。

data: {"user.account": account, "user.id": "${user.id}"},
640?wx_fmt=gif
这里写图片描述

总结

如果文章有错的地方欢迎指正,大家互相交流。习惯在微信看技术文章,想要获取更多的Java资源的同学,可以关注微信公众号:Java3y



数据科学家的AI伦理实操手册:从代码层落实公平性与可解释性 AI伦理不是抽象原则,而是嵌入数据采集、特征工程、模型训练与部署全链路的技术实践。其核心在于将公平性(如demographic parity difference)、可解释性(如SHAP实时解释)、可追溯性(如数据溯源审计)等要求转化为可执行的代码逻辑与自动化检查。例如,在PyTorch中添加公平性正则项约束梯度更新,在特征筛选阶段用互信息量化代理变量风险,在API响应中强制返回counterfactual解释字段。这些技术动作直接支撑医疗、金融等高风险场景的合规落地,避免因训练集偏差、地域歧视或黑盒决策引 阅读详情

相关推荐

房地产价值偏差诊断:用数据科学做资产健康检查

房地产估值不是预测价格涨跌,而是识别当前交易价相对于内在价值的系统性偏离。其核心在于区分市场情绪驱动的‘共识价格’与基本面支撑的‘合理价值’,通过土地成本、租金资本化、教育配套、交通便利性等可验证因子构建刚性锚点,并结合挂牌周期、议价波动等市场行为进行动态校准。这种偏差诊断方法跳出了传统回归模型的黑箱陷阱,强调可解释性、空间异质性处理与异常模式识别,广泛适用于购房决策、抵押物评估、社区运营及政策响应监测等真实业务场景。

weixin_34007906的博客 452

C#合并单元格,AddMergedRegion

做项目用到了合并单元格,本以为是件简单的事情,几句话搞定。 上网搜了下方法,百度排名第一的结果,立马跳出来。写得也很清楚 原文如下: 这里就介绍一个DLL文件NPOI.dll的合并单元格。 假如我们需要合并第一行和第二行: 代码:sheet.AddMergedRegion(new CellRangeAddress(0, 1, 0, 0)); CellRangeAddress有4个参数...

youyou390的专栏 7536

在 Oracle EBS 印度本地化(India Localization)中,GST(商品及服务税,原增值税)

摘要: Oracle EBS印度本地化中,GST计税时间点(TaxPoint)由TaxPointBasis(TPB)配置决定,分为销售(O2C)和采购(P2P)两大场景,遵循印度GST法的供应时间规则。销售场景常用TPB=Delivery(发货计税),采购场景常用TPB=Receipt(入库抵扣),特殊业务(如服务或逆向代扣)可选TPB=Invoice(开票计税)。配置路径包括定义税制、税率及分配税分类,关键注意事项包括TPB触发后不可修改、日期一致性及版本要求(EBS R12.1.1+)。该机制确保税务负

金牌架构师 574

poi合并单元格

注:我这里合并的是列的相同单元格,图片效果如下:  POI合并单元格的方法是addMergedRegion(); /**        * 合并单元格        * @param sheet 要合并单元格的excel 的sheet      * @param cellLine  要合并的列        * @param startRow  要合并列的开始行  

jishamo的专栏 2739

USB之ch376s数据手册

         最近师兄交给我一个项目,虽说刚学嵌入式起步,但上手一个项目怎说都是最好的快速学习方式。因为刚了解ch376s管理U盘的数据,所以先是看了ch376s的数据手册。那我就把数据手册直接放上来吧。。。。      1、概述 CH376 是文件管理控制芯片,用于单片机系统读写 U 盘或者 SD 卡中的文件。 CH376 支持 USB 设备方式和 USB 主机方式,并且内置了 USB 通...

iBGG的博客 6004

Arduino蜂鸣器播放《Astronomia》:从乐谱到代码的嵌入式音乐实现

在嵌入式系统开发中,通过编程控制硬件执行特定任务是核心基础。其原理在于利用微控制器生成精确的时序和频率信号,驱动执行器(如蜂鸣器、电机)完成预定动作。这项技术的价值在于实现了软件逻辑与物理世界的直接交互,是物联网设备、智能硬件开发的基石。常见的应用场景包括电子玩具的音效生成、报警器设计以及交互式艺术装置。本文以热门歌曲《Astronomia》的播放为例,具体展示了如何运用Arduino的`tone()`函数和数组数据结构,将抽象的乐谱转化为可执行的频率与延时控制代码,完整呈现了从**核心硬件解析**到**软

weixin_29796279的博客 348

java 导出excel时 addMergedRegion方法

Excel,代码示例相关视频讲解:用python编程Excel有没有用处?数组-Go代码演示Java导出Excel时addMergedRegion方法解析 在Java开发中,经常需要将数据导出到Excel中。Apache POI是一个流行的用于操作Excel文件的开源Java库。在使用POI进行Excel导出时,我们可...

weixin_28900989的博客 919

AlphaFold-multimer实战:从零开始预测STAT1-STAT2蛋白复合物结构

本文详细介绍了使用AlphaFold-multimer从零开始预测STAT1-STAT2蛋白复合物结构的完整实战流程。内容涵盖环境配置、数据库准备、序列处理、参数优化及结果可信度评估,为研究者利用这一AI工具进行复合物结构预测提供了系统指南和深度解析。

weixin_29094301的博客 887

easyExcle单元格合并

如果将需要合并的数据一次性传入afterRowDispose方法进行合并,在合并过程中使用addMergedRegionUnsafe方法合并单元格可能会导致工作簿损坏,而使用addMergedRegion会进行单元格是否重复合并的校验,会直接抛出异常。

sliencr的博客 2124

GAMES101:MacOS作业环境搭建

查看gcc/clang的位置产看gcc/clang的版本1.1.2 安装cmake。

weixin_38844255的博客 716

kubeadm init 运行时kebelet启动失败问题

解决k8s kubeadm init时遇到的kubelet问题

ZDPZN的博客 6074

java纳税服务_纳税服务系统【总结】

正版包邮spring响应式编程spring73.3元包邮(需用券)去购买 >纳税服务系统总结纳税服务系统是我第一个做得比较大的项目(不同于javaWeb小项目),该项目系统来源于传智Java32期,十天的视频课程(想要视频的同学关注我的公众号就可以直接获取了)我跟着练习一步一步完成需求,才发觉原来Java是这样用来做网站的,Java有那么多的类库,页面的效果(图表、日期选择器等等)是通过Ja...

weixin_39855843的博客 231

OCR文字识别领域经典论文总结

本篇将介绍文字识别经典论文,内容包括文字检测、文字识别、端到端识别等方法,具体将分别对论文算法简介、思路、代码等几个部分展开介绍。目前各部分只举例经典论文,算法没有全部写完,后续会将在此部分基础上更新更多论文综述及代码实战部分。.................................

专注大数据与人工智能技术分享,欢迎私信加群互相学习! 1万+

纳税服务系统【总结】

纳税服务系统总结 纳税服务系统是我第一个做得比较大的项目(不同于javaWeb小项目),该项目系统来源于传智Java32期,十天的视频课程(想要视频的同学关注我的公众号就可以直接获取了) 我跟着练习一步一步完成需求,才发觉原来Java是这样用来做网站的,Java有那么多的类库,页面的效果(图表、日期选择器等等)是通过JavaScript组件来显示,调用后端代码来获取数据从而显示出来的。 通过...

3y 1181

ORB-SLAM3算法2之EuRoc开源数据集运行ORB-SLAM3生成轨迹并用evo工具评估轨迹

ORB-SLAM3算法1 已成功编译安装ORB-SLAM3到本地,本篇目的是用EuRoc开源数据来运行ORB-SLAM3,并生成轨迹,最后用evo评估工具来评估ORB-SLAM3生成的轨迹和真值轨迹。

重点记录机器人和自动驾驶相关领域的技术,尤其是计算机视觉,视觉SLAM等,不仅有前言文献或必备算法的学习,也会有实际应用的点滴经验 3762

【无人机基站】基于K-mean算法实现无人机基站部署附matlab代码

【无人机基站】基于K-mean算法实现无人机基站部署附matlab代码

天天酷科研的博客 243

项目过后回顾用到的技术和学到的技术

1、搭建SSH;加载日志记录工具log4j(debug,info,warn,error,fatal);分类源文件夹(src源代码,config配置文件,test测试源代码)    用户管理(entity,dao,service,action,conf);日期选择工具Wdatepicker.js 2、POI导入导出Excel ① 操作工作簿 ② 操作工作表 ③ 操作行 ④ 操作单

qq_32528231的博客 407

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

分析在线生成模板、导入、导出

vue前端

man632的博客 800

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

Kimi无法识别自定义数字格式?独家逆向工程成果:提取Excel样式映射字典(含137种中国财税常用格式ID)

解决Kimi无法识别Excel自定义数字格式难题,独家逆向工程提取137种中国财税常用格式ID及样式映射字典。适用于财务、审计等需高精度读取Excel数值的场景,提升Kimi阅读Excel技巧可靠性与兼容性。值得收藏。

CodeVibe的博客 72

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

AutoPOI Word模板表格导出:终极解决方案与最佳实践指南

AutoPOI是一个基于Apache POI的智能化封装工具,专门用于简化Excel和Word文档的导入导出操作。对于需要快速实现Word模板表格导出的开发者来说,AutoPOI提供了便捷的解决方案,但在实际使用中可能会遇到表格行插入功能的问题。本文将为你深入解析这些问题并提供完整的解决方案。 ## 快速上手:AutoPOI Word模板导出基础 AutoPOI的Word模板导出功能通过`Wo

gitblog_00998的博客 212

葡萄城表格技术:数据处理、性能与 BI 能力的全栈解决方案解析

葡萄城表格技术提供全栈解决方案,覆盖前端到服务端的数据处理全流程。其SpreadJS控件采用稀疏矩阵存储和Canvas渲染,支持百万级数据交互,同时GcExcel服务端组件实现亿级数据处理。核心技术包括513种Excel公式兼容的计算引擎、依赖链优化及AI助手,已在金融、政务等领域50万客户中验证。方案显著提升数据规模支持、处理性能和BI集成能力,满足企业级应用需求。

葡萄城技术团队博客 684

Java+Vue企业工资管理系统开发实践

企业级应用开发中,工资管理系统是人力资源管理的核心模块。基于Java+Spring Boot和Vue.js的前后端分离架构,能够有效解决传统Excel手工计算工资的痛点问题。系统采用RBAC权限模型确保数据安全,通过灵活的工资计算引擎实现个税计算、社保扣款等复杂业务逻辑。技术实现上,后端使用Spring Security进行认证授权,前端采用Element UI组件库提升开发效率。该系统特别适合中小型企业部署,通过Docker容器化技术可实现快速部署和运维。

weixin_33755557的博客 402

酒店抗风险可视化系统:数据驱动的动态风控实践

酒店风险管理正从经验判断转向数据决策,其核心在于将分散在PMS、CRM、OTA及外部API中的多源异构数据,通过可视化技术实现动态基线建模、风险前置识别与响应颗粒度控制。这一过程依托实时数据采集、关联推演和角色定制看板,显著提升危机响应速度与人力弹性系数等关键指标。在供应链中断、本地活动取消、员工集中病假等高频运营风险场景中,可视化不再只是大屏展示,而是嵌入日常决策流的神经突触,支撑前厅、工程、采购等多角色3秒感知、30秒归因、3分钟闭环。本文聚焦酒店业真实落地路径,详解如何用轻量架构构建可嵌入、可验证、可

weixin_33749131的博客 388
上一篇: 纳税服务系统七(投诉管理模块)【显示投诉信息、处理回复、我要投诉、Quartz自动受理、统计图FusionCharts】...
下一篇: 纳税服务系统四(角色模块)【角色与权限、角色与用户】
Java3y
Java3y 领域专家: 后端开发技术领域 领域专家: 后端开发技术领域
博客等级 码龄9年 1万+粉丝 509原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值