Springboot+MybatisPlus整合poi实现导出导入Excle表格

1.需求

*数据库数据表导出Excle表格

*Excle数据批量新增到数据库

2.工具

工具: idea

数据库: mysql

框架:Springboot

*准备工作*:

创建springboot项目

 创建项目的过程就省略了,不会的可以去看我的球员项目超详细

1.导入导出的主要依赖:poi

2.整体依赖:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.5</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.springboot</groupId>
    <artifactId>mybatisplus</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>mybatisplus</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.2</version>
        </dependency>


        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.2.15</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>3.17</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>4.1.2</version>
        </dependency>
    </dependencies>


    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>
    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
        <repository>
            <id>spring-snapshots</id>
            <name>Spring Snapshots</name>
            <url>https://repo.spring.io/snapshot</url>
            <releases>
                <enabled>false</enabled>
            </releases>
        </repository>
    </repositories>
    <pluginRepositories>
        <pluginRepository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </pluginRepository>
        <pluginRepository>
            <id>spring-snapshots</id>
            <name>Spring Snapshots</name>
            <url>https://repo.spring.io/snapshot</url>
            <releases>
                <enabled>false</enabled>
            </releases>
        </pluginRepository>
    </pluginRepositories>

</project>

3.yaml配置

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/aac?serverTimezone=GMT%2B8
    username: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver

  thymeleaf:
    cache: false
    suffix=: .html
    prefix: classpath:/templates/
 #   type: com.zaxxer.hikari.HikariDataSource
  jdbc:
    template:
      query-timeout: 3
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

3.数据库数据导出Excle表格

1.数据库表结构

2..总体结构 

准备实体类goods(我的实体类是Mybatisplus生成的,我就往上面加注解就行了)

可以自动生成很多东西,需要下载mybatisx

 连接数据库后

 手写也没问题

@TableName(value ="goods")对应的是你的数据库表
@Value属性是匹配Excle表格的标头名称(导入准备的)
导出导入共用一个实体类

3.controller层

 @RequestMapping("/ExcelDownload")
    public void excelDownload(HttpServletResponse response) throws IOException {
        //表头数据
        String[] header = {"id", "数量", "姓名", "单价", "物品类型"};

        //声明一个工作簿
        HSSFWorkbook workbook = new HSSFWorkbook();

        //生成一个表格,设置表格名称为"学生表"
        HSSFSheet sheet = workbook.createSheet("物品表");

        //设置表格列宽度为10个字节
        sheet.setDefaultColumnWidth(10);

        //创建第一行表头
        HSSFRow headrow = sheet.createRow(0);

        //遍历添加表头(下面模拟遍历学生,也是同样的操作过程)
        for (int i = 0; i < header.length; i++) {
            //创建一个单元格
            HSSFCell cell = headrow.createCell(i);

            //创建一个内容对象
            HSSFRichTextString text = new HSSFRichTextString(header[i]);

            //将内容对象的文字内容写入到单元格中
            cell.setCellValue(text);
        }


        //***********************************
        //拿到数据
        List<Goods> goods = goodsService.getAllGoodsList();
        for (int i = 0; i < goods.size(); i++) {
            HSSFRow row = sheet.createRow(i + 1);
            Goods good = goods.get(i);
            HSSFCell cell = null;
            String[] names = {Math.toIntExact(good.getId()) + "",
                    good.getCount() + "",
                    good.getName() + "",
                    good.getPrice() + "",
                    good.getType().getTyname() + ""};
            for (int k = 0; k < names.length; k++) {
                cell = row.createCell(k);
                //拿到属性值
                HSSFRichTextString text = new HSSFRichTextString(names[k]);
                cell.setCellValue(text);
            }
        }
        //*****************************************


        //准备将Excel的输出流通过response输出到页面下载
        //八进制输出流
        response.setContentType("application/octet-stream");

        //这后面可以设置导出Excel的名称,此例中名为student.xls
        response.setHeader("Content-disposition", "attachment;filename=student.xls");

        //刷新缓冲
        response.flushBuffer();

        //workbook将Excel写入到response的输出流中,供页面下载
        workbook.write(response.getOutputStream());
    }

//******  中间的代码就是从数据库拿值出来放到表格中

//拿到数据
        List<Goods> goods = goodsService.getAllGoodsList();

如果想让controller层看起来干净点 没事 我把他封装了一个工具类

两者选其一就行

package com.springboot.mybatisplus.config;

import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import javax.servlet.http.HttpServletResponse;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.lang.reflect.Field;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;


public class ExcelUtil {

    /**
     * Excel表格导出
     * @param response HttpServletResponse对象
     * @param excelData Excel表格的数据,封装为List<List<String>>
     * @param sheetName sheet的名字
     * @param fileName 导出Excel的文件名
     * @param columnWidth Excel表格的宽度,建议为15
     * @throws IOException 抛IO异常
     */
    public static void exportExcel(HttpServletResponse response,
                                   List<List<String>> excelData,
                                   String sheetName,
                                   String fileName,
                                   int columnWidth) throws IOException {

        //声明一个工作簿
        HSSFWorkbook workbook = new HSSFWorkbook();

        //生成一个表格,设置表格名称
        HSSFSheet sheet = workbook.createSheet(sheetName);

        //设置表格列宽度
        sheet.setDefaultColumnWidth(columnWidth);

        //写入List<List<String>>中的数据
        int rowIndex = 0;
        for(List<String> data : excelData){
            //创建一个row行,然后自增1
            HSSFRow row = sheet.createRow(rowIndex++);

            //遍历添加本行数据
            for (int i = 0; i < data.size(); i++) {
                //创建一个单元格
                HSSFCell cell = row.createCell(i);

                //创建一个内容对象
                HSSFRichTextString text = new HSSFRichTextString(data.get(i));

                //将内容对象的文字内容写入到单元格中
                cell.setCellValue(text);
            }
        }

        //准备将Excel的输出流通过response输出到页面下载
        //八进制输出流
        response.setContentType("application/octet-stream");

        //设置导出Excel的名称
        response.setHeader("Content-disposition", "attachment;filename=" + fileName);

        //刷新缓冲
        response.flushBuffer();

        //workbook将Excel写入到response的输出流中,供页面下载该Excel文件
        workbook.write(response.getOutputStream());

        //关闭workbook
        workbook.close();
    }

}

4.service接口层 

5.service实现类

package com.springboot.mybatisplus.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.springboot.mybatisplus.pojo.Goods;
import com.springboot.mybatisplus.service.GoodsService;
import com.springboot.mybatisplus.mapper.GoodsMapper;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 *
 */
@Service
public class GoodsServiceImpl extends ServiceImpl<GoodsMapper, Goods>
    implements GoodsService{

    @Autowired
    private GoodsMapper goodsMapper;

    @Override
    public int addAllGoods(List<Goods> list) {
        for (int i = 0; i <list.size() ; i++) {
            if (list.get(i)==null){
                continue;
            }
            System.out.println(getBaseMapper().insert(list.get(i)));
        }
        return 1;


    }

    @Override
    public List<Goods> getAllGoodsList() {
        return goodsMapper.getAll();
    }
}




addAllGoods(List<Goods> list):是导入给数据库批量新增的方法,用的是Mybatisplus自己封装的新增的方法

 List<Goods> getAllGoodsList():是自己写的导出从数据库两表查询的方法

6.mapper接口层

7.mapper.xml

 getAll写的就是两表查询

然后手动映射(这个也是Mybatisplus自动生成的)

页面:html+thymeleaf

就ok了可以通过地址导出了

4.Excle数据批量新增到数据库

1.实体类是一样的

 2.service接口层 (和上面一样的)

3.service实现类(和上面一样的)

package com.springboot.mybatisplus.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.springboot.mybatisplus.pojo.Goods;
import com.springboot.mybatisplus.service.GoodsService;
import com.springboot.mybatisplus.mapper.GoodsMapper;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 *
 */
@Service
public class GoodsServiceImpl extends ServiceImpl<GoodsMapper, Goods>
    implements GoodsService{

    @Autowired
    private GoodsMapper goodsMapper;

    @Override
    public int addAllGoods(List<Goods> list) {
        for (int i = 0; i <list.size() ; i++) {
            if (list.get(i)==null){
                continue;
            }
            System.out.println(getBaseMapper().insert(list.get(i)));
        }
        return 1;


    }

    @Override
    public List<Goods> getAllGoodsList() {
        return goodsMapper.getAll();
    }
}




4.然后写一个工具类

package com.springboot.mybatisplus.config;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Value;

import javax.swing.text.DateFormatter;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import static java.sql.Types.BOOLEAN;
import static java.sql.Types.NUMERIC;
import static org.apache.poi.ss.usermodel.DataValidationConstraint.ValidationType.FORMULA;
import static org.apache.tomcat.util.bcel.classfile.ElementValue.STRING;


public class ExcelImport {
    //上传的是以.xls后缀的
    private final static String excel2003L = ".xls";
    //上传的是以.xlsx后缀的
    private final static String excel2007U = ".xlsx";

    public static List<List<Object>> getListByExcel(InputStream in, String fileName) throws Exception {
        //创建 list 模拟Excel表结构
        List<List<Object>> list = null;

        //创建Excel工作薄
        Workbook work = getWorkbook(in, fileName);
        if (null == work) {
            throw new Exception("创建Excel工作薄为空!");
        }
        Sheet sheet = null;  //页数
        Row row = null;  //行数
        Cell cell = null;  //列数

        list = new ArrayList<List<Object>>();
        //遍历Excel中所有的sheet页
        for (int i = 0; i < work.getNumberOfSheets(); i++) {
            sheet = work.getSheetAt(i);
            if (sheet == null) {
                continue;
            }

            //遍历当前sheet中的所有行
            for (int j = sheet.getFirstRowNum(); j <= sheet.getLastRowNum(); j++) {
                row = sheet.getRow(j);
                if (row == null) {
                    continue;
                }

                //遍历所有的列
                List<Object> li = new ArrayList<Object>();
                for (int y = row.getFirstCellNum(); y < row.getLastCellNum(); y++) {
                    //获取第i页第j行第y列的值
                    //Cannot get a STRING value from a NUMERIC cell
                    //poi导入excel表格数据时报java.lang.IllegalStateException: Cannot get a STRING value from a NUMERIC cell异常是因为在读取cell单元格字符串时,有number类型的数据,因此需要把它转化为纯String类型
                    //在number类型转化为String类型的过程中造成了Cannot get a STRING value from a NUMERIC cell这样的问题,因此需要在读取excel单元格数据转化之前设置单元格类型为String
                    //  cell = row.getCell(y);
                    // li.add(getValue(cell));
                   String cellValue=new DataFormatter().formatCellValue(row.getCell(y));
                    li.add(cellValue);
                }
                list.add(li);
            }
        }
        return list;
    }

    public static Workbook getWorkbook(InputStream inStr, String fileName) throws Exception {
        Workbook wb = null;
        //获取Excel后缀
        String fileType = fileName.substring(fileName.lastIndexOf("."));
        //跟据后缀创建工作簿
        if (excel2003L.equals(fileType)) {
            wb = new HSSFWorkbook(inStr);  //2003-
        } else if (excel2007U.equals(fileType)) {
            wb = new XSSFWorkbook(inStr);  //2007+
        } else {
            throw new Exception("解析的文件格式有误!");
        }
        return wb;
    }

    public static String getValue(Cell cell) {
        String value = "";
        if (null == cell) {
            return value;
        }
        switch (cell.getCellType()) {
            //数值型
            case NUMERIC:
                if (DateUtil.isCellDateFormatted(cell)) {
                    //如果是date类型则 ,获取该cell的date值
                    Date date = DateUtil.getJavaDate(cell.getNumericCellValue());
                    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    value = format.format(date);
                    ;
                } else {// 纯数字
                    BigDecimal big = new BigDecimal(cell.getNumericCellValue());
                    value = big.toString();
                    //解决1234.0  去掉后面的.0
                    if (null != value && !"".equals(value.trim())) {
                        String[] item = value.split("[.]");
                        if (1 < item.length && "0".equals(item[1])) {
                            value = item[0];
                        }
                    }
                }
                break;
            //字符串类型
            case STRING:
                //如果是string类型进行下划线转驼峰处理
                value = cell.getStringCellValue();
                break;
            // 公式类型
            case FORMULA:
                //读公式计算值
                value = String.valueOf(cell.getNumericCellValue());
                if (value.equals("NaN")) {// 如果获取的数据值为非法值,则转换为获取字符串
                    value = cell.getStringCellValue();
                }
                break;
            // 布尔类型
            case BOOLEAN:
                value = " " + cell.getBooleanCellValue();
                break;
            default:
                value = cell.getStringCellValue();
        }
        if ("null".endsWith(value.trim())) {
            value = "";
        }
        return value;
    }

    public static void setFileValueByFieldName(Object object, String fieldName, Object val) {
        //获取object类的所有属性
        Field[] fields = object.getClass().getDeclaredFields();
        try {
            //对所有属性进行遍历
            for (int i = 0; i < fields.length; i++) {
                //获取第i个属性
                Field field = fields[i];
                //如果Excel的某一列的列名(fieldName)与
                //在第i个属性上面添加的@Value注解的value一样,进行下面的操作
                if (fieldName.equals(field.getAnnotation(Value.class).value())) {
                    Class type = field.getType();
                    if (fieldName.equals("id")){
                        continue;
                    }
                    //如果field为私有属性,也可以对它进行操作
                    field.setAccessible(true);
                    //获取该属性的数据类型,如果是Integer类型的
                    if (field.getType()==Integer.class) {
                        field.set(object, Integer.valueOf(val.toString()));
                        //如果时LocalDateTime类型的
                    } else  if (field.getType()==double.class) {
                        field.set(object, Double.valueOf(val.toString()));
                        //如果时LocalDateTime类型的
                    } else if (type== int.class) {
                        //把val转成Integer存到该属性里面
                        field.set(object, Integer.valueOf(val.toString()));
                    } else if (field.getType()==long.class) {
                        field.set(object, Long.valueOf(val.toString()));
                        //如果时LocalDateTime类型的
                    } else if (field.getType() == LocalDateTime.class) {
                        //先把他格式化
                        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                        LocalDateTime time = LocalDateTime.parse(val.toString(), formatter);
                        field.set(object, time);
                        //如果其他类型的直接存
                    } else {
                        field.set(object, val);
                    }
                    return;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
setFileValueByFieldName(实体类Object,Excle表格的标头fileName,要注入的值var)在该方法进行属性类型判定赋值

5.controller层

package com.springboot.mybatisplus.controller;

import com.springboot.mybatisplus.config.ExcelImport;
import com.springboot.mybatisplus.pojo.Goods;
import com.springboot.mybatisplus.service.impl.GoodsServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.List;


@Controller
public class StudentController {
    @Autowired
    GoodsServiceImpl goodService;

    @RequestMapping("/upload")
    @ResponseBody
    public String uploadFile(@RequestParam("file") MultipartFile file) throws Exception {
        try {
            // 上传文件路径
            String filePath = "E:\\doc\\sdfsdf";
            // 为了防止文件名冲突,获取当前时间+文件原名生成新的文件名
            String fileName = System.currentTimeMillis() + file.getOriginalFilename();
            // 上传文件
            File f = new File(filePath + fileName);
            file.transferTo(f);
            fileName = filePath + fileName;

            //输入流,获取刚刚上传文件转成输入流
            FileInputStream fileInputStream = new FileInputStream(new File(fileName));
            //定义一个list变量,模拟excel结构
            List<List<Object>> list = ExcelImport.getListByExcel(fileInputStream, fileName);
            //定义firstRows变量,用来获取第一行,就是标题,每列名字
            List<Object> firstRows = null;
            //定义studentList变量,用来存储文件内容(学生信息)
            List<Goods> studentList = new ArrayList<>();
            //如果 list 不为空,大小大于0则获取第一行存到firstRows 里面
            if (list != null && list.size() > 0) {
                firstRows = list.get(0);
            } else {
                //否则返回 failure
                return "表格数据为空";
            }


            //对list进行遍历,因为第一行是标题,不用存到数据库,所以从第二行开始遍历
            for (int i = 1; i < list.size(); i++) {
                //获取第i行数据
                List<Object> rows = list.get(i);
                //定义goods遍历,存储第i行数据
                Goods good = new Goods();
                //对第i行数据进行遍历,
                //从1开始是因为新增不能有id
                for (int j = 1; j < rows.size(); j++) {
                    //获取第i行第j列数据,存到cellVal 变量里面
                    String cellVal = (String) rows.get(j);
                    //调用setFileValueByFieldName函数,把数据存到student对应的属性里面
                    ExcelImport.setFileValueByFieldName(good, firstRows.get(j).toString().trim(), cellVal);
                }
                //把student变量加到studentList
                studentList.add(good);
            }
            //调用批量插入方法,把数据存到数据库
            int o= goodService.addAllGoods(studentList);
            if (o != 0) {
                return "成功了";
            } else {
                return "导入失败";
            }
        } catch (Exception e) {
            return "报错了: "+e.getMessage();
        }
    }
}

这边id是自增列,所以不把id新增进去,所以 int =i

6.前端导入页面

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>导入Excel</title>
</head>
<body>
<h1>选择Excel</h1>
<form th:action="@{/upload}" method="post" enctype="multipart/form-data">
    <!-- name 的值与@RequestParam的值相同-->
    <input type="file" name="file"/><br/>
    <input type="submit" value="上传"/><br/>
</form>
 
</body>
</html>

5.效果

点击导出后

 

**导入

准备表:

 选择Excle表后

点击提交

查看数据库

 总结:制作不易,如果帮助到你 请点赞收藏支持一下

如果新增的只有name或者新增不全面

看一下实体类的注解

还有看一下工具类的这个地方有没有判断你实体类属性的数据类型,没有的话照着写一个

 如果还有纰漏请及时告知 感谢观看

  • 9
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值