2

前言

之前一直心心念的文件处理(导出/导入)终于在本周遇到了,一步一步尝试过来发现真的挺有趣的,在此记录Excel文件的导入与导出。

准备

首先在项目的pom.xml文件引入依赖:

     <!-- 用于Microsoft文档的Java API -->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>4.1.2</version>
        </dependency>

        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>4.1.2</version>
        </dependency>

Import

C层:

   @PostMapping("upload")
    public void upload(@RequestParam("file") MultipartFile multipartFile) throws IOException, InvalidFormatException {
        this.excelService.upload(multipartFile);
    }

M层:

    @Override
    //上传文件
    public void upload(MultipartFile multipartFile) throws IOException, InvalidFormatException {
        //文件大小
        System.out.println(multipartFile.getSize());
        //文件名
        System.out.println(multipartFile.getOriginalFilename());
        //读取文件信息
        this.readFromFile(multipartFile);
    }
    
    
    @Override
    public void readFromFile(MultipartFile multipartFile) throws IOException, InvalidFormatException {
    
        //通过将整个文件输入流缓冲到内存中,构造一个XSSFWorkbook对象
        Workbook workbook = new XSSFWorkbook(multipartFile.getInputStream());

        //从第一个sheet读取数据
        Sheet sheet = workbook.getSheetAt(0);
        //迭代器
        Iterator<Row> rows = sheet.iterator();

        while (rows.hasNext()) {
            Row currentRow = rows.next();

            Iterator<Cell> cellsInRow = currentRow.iterator();

            //循环,输出数据
            while (cellsInRow.hasNext()) {
                Cell currentCell = cellsInRow.next();
                System.out.println(currentCell);
            }

            workbook.close();
        }
    }

由于在开发时是前后台分离开发,因此在测试时使用了Postman进行了该方法的测试:

Headers

在Headers中取消对原有的Content-Type的勾选, 然后添加KEY:Content-Type, 但是不添加VALUE : 在测试过程中,我们理论上应该为其添加的Content-Type的value应该为: multipart/form-data, 但是经过多次尝试发现, 无论其value为什么, 均会出现:

The request was rejected because no multipart boundary was found in springboot

的问题, 后来在StackOverFlow上找到了如下回答:

The problem is that you are setting the Content-Type by yourself, let it be blank. Google Chrome will do it for you. The multipart Content-Type needs to know the file boundary, and when you remove the Content-Type, Postman will do it automagically for you.

image.png

body

对于body, 我们选择的类型为form-data, 值得注意的是, key值类型默认为Text,我们需要手动选择一下:
image.png

将鼠标光标移动到KEY第一栏最后一部分,会有选择栏出现, 然后我们选择File,这时VALUE一栏就会有Select Files按钮:
image.png

我们将KEY值设置为file(与C层方法的@RequestParam("file")相同),然后选择要处理的文件。

测试

接下来我们启动后台,然后利用Postman验证方法是否可用:

测试表单:
image.png

Status信息处于控制台上方,并非在控制台中打印:
image.png

然后看一下后台控制台输出:

7421
104189855_2_Test_5_5.xlsx
序号
提交答卷时间
所用时间
来源
来源详情
来自IP
1、单选测试1
2、(多选测试1选项1)
2、(多选测试1选项2)
3、(多选测试2选项1)
3、(多选测试2选项2)
4、单选测试2
5、填空测试1
6、填空测试2
1.0
2021/1/12 18:27:55
33秒
手机提交
直接访问
183.197.57.68(河北-沧州)
1.0
1.0
1.0
1.0
0.0
2.0
填空测试1结果
填空测试2结果
2.0
2021/1/12 18:31:56
16秒
手机提交
直接访问
183.197.61.88(河北-沧州)
1.0
1.0
1.0
1.0
1.0
2.0
1.0
2.0
3.0
2021/1/12 18:31:59
24秒
手机提交
直接访问
110.244.253.249(河北-沧州)
1.0
1.0
1.0
1.0
1.0
2.0
1.0
2.0
4.0
2021/1/12 18:33:53
42秒
手机提交
直接访问
221.192.178.136(河北-石家庄)
1.0
1.0
1.0
1.0
1.0
2.0
1.0
2.0
5.0
2021/1/12 18:34:58
18秒
手机提交
直接访问
122.96.40.68(江苏-南京)
1.0
1.0
1.0
1.0
1.0
2.0
。
。

过程

image.png

Export

C层

@GetMapping("dataExport")
    public void dataExport(HttpServletResponse response) throws IOException {
        this.excelService.dataExport(response.getOutputStream());
    }

M层

  //输出文件
  this.export(outputStream);
  
  
  public void export(ServletOutputStream outputStream) throws IOException {
        //添加表头数据
        writeHeaderLine();
        //在添加每行数据时使用, 从第二行开始写入
        this.rowCount = 1;
        //添加每行数据
        writeDataLines();
        workbook.write(outputStream);
        workbook.close();
        outputStream.close();
    }
  
     public void writeHeaderLine(List<Question> questions) {
        workbook = new XSSFWorkbook();
        sheet = workbook.createSheet(RandomString.make(6));

        //创建第一行
        Row row = sheet.createRow(0);

        //每行的样式
        CellStyle style = workbook.createCellStyle();
        XSSFFont font = workbook.createFont();
        font.setBold(true);
        font.setFontHeight(16);
        style.setFont(font);
        //列 从0开始,可自增
        AtomicInteger columnCount = new AtomicInteger(0);
        for (int i = 0; i< 5; i++) {
            createCell(row, columnCount.getAndIncrement(), RandomString.make(6), style);
        }
    }


 public void writeDataLines(AnswerSheet answerSheet) {

        CellStyle style = workbook.createCellStyle();
        XSSFFont font = workbook.createFont();
        font.setFontName("Calibri");
        font.setFontHeight(14);
        style.setFont(font);

        Row row = sheet.createRow(rowCount++);
        AtomicInteger columnCount = new AtomicInteger(0);
        for (int i = 0; i< 5; i++) {
            createCell(row, columnCount.getAndIncrement(), RandomString.make(6), style);
        }
    }

测试:

在不启动前台的条件下, 我们可以在C层添加如下代码进行测试:

@GetMapping("dataExport")
    public void dataExport(HttpServletResponse response) throws IOException {
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        DateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd_HH:mm:ss");
        String currentDateTime = dateFormatter.format(new Date());

        String headerKey = "Content-Disposition";
        //设置filename
        String headerValue = "attachment; filename=tests" + currentDateTime + ".xlsx";
        response.setHeader(headerKey, headerValue);
            this.excelService.dataExport(response.getOutputStream());
    }

然后发起请求(使用浏览器访问url),查看结果:
image.png

过程

image.png

总结

能让数据库的数据变成.xlsx文件展现,能让.xlsx文件的数据存储到数据库中,也确实很神奇,这就是代码的乐趣吧。

本文作者:河北工业大学梦云智开发团队 张文达


锦城
854 声望21 粉丝

好好生活