• 使用VUE+SpringBoot+EasyExcel 整合导入导出数据 look


    使用VUE+SpringBoot+EasyExcel 整合导入导出数据

    创建一个普通的maven项目即可

    项目目录结构

    image-20220514105517968

    1 前端

    存放在resources/static 下

    index.html

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Document</title>
        <!-- 开发环境版本,包含了有帮助的命令行警告 -->
        <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
        <!-- 引入样式 -->
        <link
          rel="stylesheet"
          href="https://unpkg.com/element-ui/lib/theme-chalk/index.css"
        />
        <!-- 引入组件库 -->
        <script src="https://unpkg.com/element-ui/lib/index.js"></script>
        <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
      </head>
      <body>
        <div id="app">
          <div class="app-container">
            <div style="margin-bottom: 10px">
              <el-button
                @click="dialogVisible = true"
                type="primary"
                size="mini"
                icon="el-icon-download"
              >
                导入Excel
              </el-button>
              <el-dialog
                title="数据字典导入"
                :visible.sync="dialogVisible"
                width="30%"
              >
                <el-form>
                  <el-form-item label="请选择Excel文件">
                    <el-upload
                      :auto-upload="true"
                      :multiple="false"
                      :limit="1"
                      :on-exceed="fileUploadExceed"
                      :on-success="fileUploadSuccess"
                      :on-error="fileUploadError"
                      :action="importUrl"
                      name="file"
                      accept="application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
                    >
                      <!--accept 只接受某种格式的文件-->
                      <el-button size="small" type="primary">点击上传</el-button>
                    </el-upload>
                  </el-form-item>
                </el-form>
                <div slot="footer" class="dialog-footer">
                  <el-button @click="dialogVisible = false">取消</el-button>
                </div>
              </el-dialog>
    
              <!-- 导出 -->
              <el-button
                @click="exportData"
                type="primary"
                size="mini"
                icon="el-icon-upload2"
              >
                导出Excel
              </el-button>
    
              <!-- 数据展示 -->
              <el-table :data="list" stripe style=" 100%">
                <el-table-column prop="name" label="姓名" width="180">
                </el-table-column>
                <el-table-column prop="birthday" label="生日" width="180">
                </el-table-column>
                <el-table-column prop="salary" label="薪资"> </el-table-column>
              </el-table>
              <div>
                <el-pagination
                  @size-change="handleSizeChange"
                  @current-change="handleCurrentChange"
                  :current-page="pageNum"
                  :page-sizes="[2, 5, 10,  20]"
                  :page-size="pageSize"
                  background
                  layout="total, sizes, prev, pager, next, jumper"
                  :total="total"
                >
                </el-pagination>
              </div>
            </div>
          </div>
        </div>
      </body>
      <script>
        new Vue({
          el: '#app',
          data() {
            return {
              dialogVisible: false, //文件上传对话框是否显示
              list: [], // 字典的数据
              importUrl: 'http://localhost:8811/api/excel/import',
              pageNum: 1, // 页数
              pageSize: 5, // 每页条数
              total: 1000,
            }
          },
          created() {
            this.showList()
          },
          methods: {
            showList() {
              //使用自定义配置
              const request = axios.create({
                baseURL: 'http://localhost:8811', //url前缀
                timeout: 1000, //超时时间
                // headers: { token: 'helen123456' }, //携带令牌
              })
              request
                .get('/api/excel/list', {
                  params: {
                    pageNum: this.pageNum,
                    pageSize: this.pageSize,
                  },
                })
                .then((res) => {
                  this.total = res.data.size
                  this.list = res.data.list
                  console.log(res)
                })
            },
            // 上传多于一个文件时
            fileUploadExceed() {
              this.$message.warning('只能选取一个文件')
            },
    		// 导出
            exportData() {
              window.location.href = 'http://localhost:8811/api/excel/export'
            },
    
            //上传成功回调
            fileUploadSuccess(response) {
              if (response.code === 0) {
                this.$message.success('数据导入成功')
                this.dialogVisible = false
              } else {
                this.$message.error(response.message)
              }
            },
    
            //上传失败回调
            fileUploadError(error) {
              this.$message.error('数据导入失败')
            },
            /**
             * 用户所选择当前页面展示的数据条数
             */
            handleSizeChange(val) {
              console.log(`每页 ${val} 条`)
              this.pageSize = val
              this.showList()
            },
            handleCurrentChange(val) {
              console.log(`当前页: ${val}`)
              this.pageNum = val
              this.showList()
            },
          },
        })
      </script>
    </html>
    
    

    2 数据库

    CREATE TABLE `student` (
      `name` varchar(255) DEFAULT NULL COMMENT '姓名',
      `birthday` datetime DEFAULT NULL COMMENT '生日',
      `salary` decimal(10,4) DEFAULT NULL COMMENT '薪资'
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
    

    3 后端

    3.1 contrller

    StudentController

    @Slf4j
    @RestController
    @CrossOrigin
    @RequestMapping("/api/excel/")
    public class StudentController {
    
        @Resource
        private StudentMapper studentMapper;
    
        @GetMapping("list")
        public HashMap<String, Object> list(@RequestParam int pageNum,@RequestParam int pageSize){
            // 分页查询
            Page<Student> page = new Page<>(pageNum, pageSize);
            studentMapper.selectPage(page,null);
            
            // 封装数据
            HashMap<String, Object> map = new HashMap<>();
            ArrayList<ExcelStudentDTO> excelDictDTOList = new ArrayList<>();
            // 转换数据
            page.getRecords().forEach(student -> {
                ExcelStudentDTO studentDTO = new ExcelStudentDTO();
                BeanUtils.copyProperties(student,studentDTO);
                excelDictDTOList.add(studentDTO);
            });
            
            map.put("list",excelDictDTOList);
            map.put("size",page.getTotal());
            return map;
        }
    
        /**
         * 导入
         * @param file 文件对象
         */
        @RequestMapping("import")
        @Transactional(rollbackFor = {Exception.class})
        public String importData( @RequestParam("file") MultipartFile file){
            try {
                // 读取文件流
                EasyExcel.read
                        (file.getInputStream(),// 前端上传的文件
                                ExcelStudentDTO.class,// 跟excel对应的实体类
                                new ExcelDictDTOListener(studentMapper))// 监听器 
                        .excelType(ExcelTypeEnum.XLSX)// excel的类型
                        .sheet("模板").doRead();
                log.info("importData finished");
            } catch (IOException e) {
               log.info("失败");
               e.printStackTrace();
            }
            return "上传成功";
        }
    
        /**
         * 导入
         */
        @GetMapping("export")
        public String exportData(HttpServletResponse response){
    
            try {
                // 设置响应体内容
                response.setContentType("application/vnd.ms-excel");
                response.setCharacterEncoding("utf-8");
    
                // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
                String fileName = URLEncoder.encode("myStu", "UTF-8").replaceAll("\\+", "%20");
                response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
                EasyExcel.write(response.getOutputStream()
                        ,ExcelStudentDTO.class).sheet().doWrite(studentMapper.selectList(null));
            } catch (Exception e) {
                e.printStackTrace();
            }
            return "上传成功";
        }
    
    }
    

    3.2 mapper

    StudentMapper

    @Mapper
    public interface StudentMapper extends BaseMapper<Student> {
        void insertBatch(List<ExcelStudentDTO> list);
    }
    

    StudentMapper.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="look.word.mapper.StudentMapper">
      <insert id="insertBatch" >
        insert into student(name, birthday, salary)
        values
        <foreach collection="list"   item="item" separator=",">
                   (
            #{item.name} ,
            #{item.birthday} ,
            #{item.salary} 
            )
        </foreach>
      </insert>
    </mapper>
    

    3.3 bean

    ExcelStudentDTO

    导入数据时 要保证excel中列名和ExcelStudentDTO一致奥

    /**
     * excel对应的实体类
     * @author jiejie
     */
    @Data
    public class ExcelStudentDTO {
    	// excel中的列名
        @ExcelProperty("姓名")
        private String name;
    
        @ExcelProperty("生日")
        private Date birthday;
    
        @ExcelProperty("薪资")
        private BigDecimal salary;
    }
    

    Student

    /**
     * 数据库对应的实体类
     * @author jiejie
     */
    @Data
    @TableName(value = "student")
    public class Student {
        /**
         * 姓名
         */
        @TableField(value = "name")
        private String name;
    
        /**
         * 生日
         */
        @TableField(value = "birthday")
        private Date birthday;
    
        /**
         * 薪资
         */
        @TableField(value = "salary")
        private BigDecimal salary;
    
        public static final String COL_NAME = "name";
    
        public static final String COL_BIRTHDAY = "birthday";
    
        public static final String COL_SALARY = "salary";
    }
    

    3.3 listener

    官方文档

    EasyExcel读取文件需要用到

    ExcelDictDTOListener

    /**
     * 监听
     * 再读取数据的同时 对数据进行插入操作
     * @author : look-word
     * @date : 2022-05-10 21:35
     **/
    @Slf4j
    //@AllArgsConstructor //全参
    @NoArgsConstructor //无参
    public class ExcelDictDTOListener extends AnalysisEventListener<ExcelStudentDTO> {
    
    
        /**
         * 每隔5条存储数据库,实际使用中可以3000条,然后清理list ,方便内存回收
         */
        private static final int BATCH_COUNT = 5;
        List<ExcelStudentDTO> list = new ArrayList<ExcelStudentDTO>();
    
        private StudentMapper studentMapper;
    
        //传入mapper对象
        public ExcelDictDTOListener(StudentMapper studentMapper) {
            this.studentMapper = studentMapper;
        }
    
        /**
         *遍历每一行的记录
         * @param data
         * @param context
         */
        @Override
        public void invoke(ExcelStudentDTO data, AnalysisContext context) {
            log.info("解析到一条记录: {}", data);
            list.add(data);
            // 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
            if (list.size() >= BATCH_COUNT) {
                saveData();
                // 存储完成清理 list
                list.clear();
            }
        }
    
        /**
         * 所有数据解析完成了 都会来调用
         */
        @Override
        public void doAfterAllAnalysed(AnalysisContext context) {
            // 这里也要保存数据,确保最后遗留的数据也存储到数据库
            saveData();
            log.info("所有数据解析完成!");
        }
    
        /**
         * 加上存储数据库
         */
        private void saveData() {
            log.info("{}条数据,开始存储数据库!", list.size());
            studentMapper.insertBatch(list);  //批量插入
            log.info("存储数据库成功!");
        }
    }
    

    3.5 config

    mybatisPlus分页插件

    MybatisPlusConfig

    @Configuration
    public class MybatisPlusConfig {
    
        /**
         * 新的分页插件,一缓和二缓遵循mybatis的规则,
         * 需要设置 MybatisConfiguration#useDeprecatedExecutor = false
         * 避免缓存出现问题(该属性会在旧插件移除后一同移除)
         */
        @Bean
        public MybatisPlusInterceptor mybatisPlusInterceptor() {
            MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
            PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();
            paginationInnerInterceptor.setDbType(DbType.MYSQL);
            paginationInnerInterceptor.setOverflow(true);
            interceptor.addInnerInterceptor(paginationInnerInterceptor);
            return interceptor;
        }
    
        @Bean
        public ConfigurationCustomizer configurationCustomizer() {
            return configuration -> configuration.setUseDeprecatedExecutor(false);
        }
    }
    

    3.6 配置文件

    application.yaml

    server:
      port: 8811
    spring:
      datasource: # mysql数据库连接
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/2022_source_springboot?serverTimezone=GMT%2B8&characterEncoding=utf-8
        username: root
        password: 317311
    mybatis-plus:
      configuration:# sql日志
        log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
      mapper-locations:
        - classpath:mapper/*.xml
    
    

    4 启动测试

    启动springboot哦

    页面效果图

    image-20220514121951441

    导出效果

    image-20220514122058553

    注意

    导入数据时 要保证excel中列名和ExcelStudentDTO一致奥

  • 相关阅读:
    转载 从最简单的vector中sort用法到自定义比较函数comp后对结构体排序的sort算法
    TYVJ P1081 最近距离 Label:这不是分治!!!
    TYVJ P1086 Elevator Label:dp
    数字图像处理的三个层次
    栅格化是什么意思?
    图像基本知识
    修改了天空盒子但是点play还是没变原因
    地形编辑
    Bmp8位图像亮度如何调整?
    bmp图像作业笔记
  • 原文地址:https://www.cnblogs.com/look-word/p/16269739.html
Copyright © 2020-2023  润新知