当前位置:   article > 正文

关于springboot+vue的excel导入导出_springboot vue实现excel导入导出功能

springboot vue实现excel导入导出功能

       在做项目的过程中,外面经常会遇到一个问题,怎么才能把excel表中的数据实现批量的导入导出,使用的是EasyExcel进行操作。

一、项目前准备

1、依赖导入

在pom文件中添加对应的依赖
  1. <dependency>
  2. <groupId>com.alibaba</groupId>
  3. <artifactId>easyexcel</artifactId>
  4. <version>3.1.3</version>
  5. </dependency>

2、实体类准备

数据库字段过多,这边就截取一部分进行展示

  1. @Data
  2. @AllArgsConstructor
  3. @NoArgsConstructor
  4. @TableName("emp_user")
  5. public class EmpUserEntity implements Serializable {
  6. private static final long serialVersionUID = 1L;
  7. /**
  8. * 人员id
  9. */
  10. @ExcelIgnore
  11. private Long id;
  12. /**
  13. * 用户ID
  14. */
  15. @ExcelIgnore
  16. private Long userId;
  17. /**
  18. * 密码
  19. */
  20. @TableField(exist = false)
  21. @ExcelIgnore
  22. private String password;
  23. /**
  24. * 姓名
  25. */
  26. @ExcelProperty(value = {"姓名"}, index = 0)
  27. private String name;
  28. /**
  29. * 性别:1:男 0:女
  30. */
  31. @ExcelProperty(value = {"性别"}, index = 1,converter = SexConvert.class)
  32. //静态下拉框
  33. @ExcelSelected(source = {"男","女"})
  34. private Integer gender;
  35. /**
  36. * 年龄(计算退休时间)
  37. */
  38. @ExcelProperty(value = {"年龄"}, index = 2)
  39. private Integer age;
  40. /**
  41. * 电话
  42. */
  43. @ExcelProperty(value = {"电话"}, index = 3)
  44. @ColumnWidth(20)
  45. private String tel;
  46. /**
  47. * 邮箱
  48. */
  49. @ExcelProperty(value = {"邮箱"}, index = 4)
  50. @ColumnWidth(25)
  51. private String email;
  52. }

注释解释:

  1. @ExcelIgnore:EasyExcel框架中的注解,用于标识实体类中不需要导出或导入的属性。
  2. @ExcelProperty(value = {"性别"}, index = 1,converter = SexConvert.class):指定实体类与表格之间的映射关系
  3.       value表示excel表格的标题列。
  4.        index表示excel表格中的列索引。
  5.       converter = SexConvert.class:指定类型转换器,将Excel表格中的数据转换成Java对象。
  6. @ExcelSelected(source = {"男","女"}):导出下拉框自定义注解

3、类型转换器

       有些数据外面存入数据库的是数字,例如一般男生我们选用1,女生选用0,当时当我们进行表的输出和输入时,excel表中用的是男、女,我们采用类型转换器进行数据的转化。

(1)实体类中添加注释
  1. @ExcelProperty(value = {"性别"}, index = 1,converter = SexConvert.class)
  2. //SexConvert.class定义类转化器的类
(2)转换类的编写
  1. import com.alibaba.excel.converters.Converter;
  2. import com.alibaba.excel.enums.CellDataTypeEnum;
  3. import com.alibaba.excel.metadata.CellData;
  4. import com.alibaba.excel.metadata.GlobalConfiguration;
  5. import com.alibaba.excel.metadata.property.ExcelContentProperty;
  6. public class SexConvert implements Converter<Integer> {
  7. @Override
  8. //指定该转换器支持的 Java 类型。在本例中,返回 Integer.class,表示该转换器用于将 Excel 中的数据转换为整数类型。
  9. public Class supportJavaTypeKey() {
  10. return Integer.class;
  11. }
  12. @Override
  13. //指定该转换器支持的 Excel 数据类型。在本例中,返回 CellDataTypeEnum.STRING,表示该转换器处理的是字符串类型的 Excel 数据。
  14. public CellDataTypeEnum supportExcelTypeKey() {
  15. return CellDataTypeEnum.STRING;
  16. }
  17. @Override
  18. //将 Excel 中的数据转换为 Java 对象的方法。在本例中,该方法尚未实现,因此返回 null。你需要根据实际需求,实现具体的转换逻辑。
  19. public Integer convertToJavaData(CellData cellData, ExcelContentProperty excelContentProperty, GlobalConfiguration globalConfiguration) throws Exception {
  20. return "男".equals(cellData.getStringValue()) ? 1 : 0;
  21. }
  22. @Override
  23. //将 Java 对象转换为 Excel 数据的方法。
  24. public CellData convertToExcelData(Integer value, ExcelContentProperty excelContentProperty, GlobalConfiguration globalConfiguration) throws Exception {
  25. if (value == 1) {
  26. return new CellData("男");
  27. } else if (value == 0) {
  28. return new CellData("女");
  29. }
  30. // 如果值不是 Integer 或者不是合法的性别值,则抛出异常
  31. throw new IllegalArgumentException("无效的性别值");
  32. }
  33. }

  其中第三个和第四个方法代表 java对象与excel表里的相互转换。

*注意包不要导错喔

二、导入功能的实现

1、后端功能实现:

(1)自定义监听器,对下载的excel中的数据进行校验。
  1. public class WebUserListener<T> extends AnalysisEventListener<T> {
  2. //首先使用 Logger 记录当前读取的数据信息,然后将读取到的数据对象 t 加入到 list 列表中,以备后续的获取
  3. public final Logger log = LoggerFactory.getLogger(this.getClass());
  4. public List<T> list = new ArrayList<>();
  5. /**
  6. * 该方法在读取到表格中的一条数据时被调用。其中 t 参数表示当前行的数据对象,analysisContext 参数表示解析过程的上下文对象。
  7. * @param t
  8. * @param
  9. */
  10. @Override
  11. public void invoke(T t, AnalysisContext analysisContext) {
  12. log.info("读取表格[{}]",t);
  13. list.add(t);
  14. }
  15. @Override
  16. public void doAfterAllAnalysed(AnalysisContext analysisContext) {
  17. }
  18. //获取数据,供controller层调用
  19. public List<T> getExcelData(){
  20. return list;
  21. }
  22. }
(2)controller层:
  1. @RestController
  2. @RequestMapping("emp/excel")
  3. public class EmpUserImport extends AbstractController {
  4. @Autowired
  5. private EmpUserService empUserService;
  6. @PostMapping("/Import")
  7. //@RequiresPermissions("emp:user:excelImport")
  8. public EmpUserEntity redExcel(MultipartFile multipartFile) throws IOException {
  9. //输入流指向了上传的 Excel 文件
  10. InputStream inputStream = multipartFile.getInputStream();
  11. //实例是一个 EasyExcel 的监听器,用于解析 Excel 数据。
  12. WebUserListener<EmpUserEntity> webListener = new WebUserListener<>();
  13. //用于处理 Excel 数据的监听器,表示对 Excel 中所有的 sheet 进行解析。
  14. EasyExcel.read(inputStream,EmpUserEntity.class,webListener).sheet().doRead();
  15. //获取数据对象列表。
  16. List<EmpUserEntity> excelData = webListener.getExcelData();
  17. //将获取到的数据填入数据库
  18. for (EmpUserEntity user : excelData) {
  19. empUserService.save(user);
  20. }
  21. return excelData ;
  22. }

2、前端代码

(1)触发按钮
  1. <el-form-item >
  2. <el-upload
  3. class="upload-demo"
  4. :action="excelImports"
  5. :headers="tokenInfo"
  6. :on-preview="handlePreview"
  7. :on-remove="handleRemove"
  8. :on-success="uploadSuccess"
  9. multiple
  10. name="multipartFile"
  11. :limit="3"
  12. >
  13. <el-button type="success" >点击上传</el-button>
  14. </el-upload>
  15. </el-form-item>
(2)接口定义
  1. data () {
  2. return {
  3. excelImports: this.$http.adornUrl('/emp/excel/Import'),
  4. tokenInfo: {
  5. 'token': this.$cookie.get('token')
  6. },
  7. dataForm: {
  8. deptId: '' //部门id
  9. },
  10. .........
  11. }
  12. }
(3)方法补充
  1. uploadSuccess (response, file, fileList) {
  2. this.getDataList()
  3. console.log(response)
  4. },
  5. handleRemove (file, fileList) {
  6. console.log(file, fileList)
  7. },
  8. handlePreview (file) {
  9. console.log(file)
  10. }

三、导出功能实现

 可实现导出附加功能:

  • 可实现按部门进行导入导出,该页面显示按照部门id进行输入选择,可选择其他条件进行筛选,或自行设置级联选择。
  • 让导出的excel表实现下拉框的选择

1、后端代码

(1)创建实现下拉框选择的注解

  1. import java.lang.annotation.*;
  2. @Documented
  3. @Retention(RetentionPolicy.RUNTIME)
  4. @Target(ElementType.FIELD)
  5. public @interface ExcelSelected {
  6. /**
  7. * 固定下拉内容
  8. */
  9. String[] source() default {};
  10. /**
  11. * 设置下拉框的起始行,默认为第二行
  12. */
  13. int firstRow() default 1;
  14. /**
  15. * 设置下拉框的结束行,默认为最后一行
  16. */
  17. int lastRow() default 0x10000;
  18. }

(2)自定义注解使用

  1. /**
  2. * 性别:1:男 0:女
  3. */
  4. @ExcelProperty(value = {"性别"}, index = 1,converter = SexConvert.class)
  5. //静态下拉框
  6. @ExcelSelected(source = {"男","女"})
  7. private Integer gender;

(2)创建导出工具类

  1. @Slf4j
  2. public class EasyExcelUtils {
  3. /**
  4. * 导出单sheet页且sheet页中含有下拉框的excel文件
  5. *
  6. * @param response HttpServletResponse
  7. * @param fileName 文件名
  8. * @param sheetName sheet页名
  9. * @param data 要导出的数据
  10. */
  11. public static <T> void writeExcelBySelect(HttpServletResponse response, String fileName, String sheetName, List<T> data) {
  12. try {
  13. encodeFileName(response, fileName);
  14. Map<Integer, ExcelSelected> integerExcelSelectedMap = resolveSelectedAnnotation(IterUtil.getElementType(data));
  15. EasyExcel.write(response.getOutputStream(), IterUtil.getElementType(data))
  16. .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
  17. .registerWriteHandler(selectedSheetWriteHandler(integerExcelSelectedMap))
  18. .sheet(StringUtils.isEmpty(sheetName) ? "Sheet1" : sheetName)
  19. .doWrite(data);
  20. } catch (IOException e) {
  21. log.error("导出excel文件异常", e);
  22. }
  23. }
  24. /**
  25. * 设置文件名
  26. *
  27. * @param response HttpServletResponse
  28. * @param fileName 文件名
  29. */
  30. private static void encodeFileName(HttpServletResponse response, String fileName) throws UnsupportedEncodingException {
  31. fileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.name());
  32. response.setCharacterEncoding(StandardCharsets.UTF_8.name());
  33. response.setHeader(HttpHeaders.CONTENT_DISPOSITION, String.format("attachment;filename=\"%s\"", fileName + ".xlsx"));
  34. response.setHeader(HttpHeaders.CACHE_CONTROL, "no-cache");
  35. response.setHeader(HttpHeaders.PRAGMA, "no-cache");
  36. response.setDateHeader(HttpHeaders.EXPIRES, -1);
  37. }
  38. /**
  39. * 解析表头类中的下拉注解
  40. *
  41. * @param head 表头类
  42. * @return Map<下拉框列索引, 下拉框内容> map
  43. */
  44. private static <T> Map<Integer, ExcelSelected> resolveSelectedAnnotation(Class<T> head) {
  45. Map<Integer, ExcelSelected> selectedMap = new HashMap<>(16);
  46. Field[] fields = head.getDeclaredFields();
  47. for (int i = 0; i < fields.length; i++) {
  48. Field field = fields[i];
  49. ExcelSelected selected = field.getAnnotation(ExcelSelected.class);
  50. ExcelProperty property = field.getAnnotation(ExcelProperty.class);
  51. if (selected != null) {
  52. if (property != null && property.index() >= 0) {
  53. selectedMap.put(property.index(), selected);
  54. }
  55. }
  56. }
  57. return selectedMap;
  58. }
  59. /**
  60. * 为excel创建下拉框
  61. *
  62. * @param selectedMap 下拉框配置数据 Map<下拉框列索引, 下拉框内容>
  63. * @return intercepts handle sheet creation
  64. */
  65. private static SheetWriteHandler selectedSheetWriteHandler(Map<Integer, ExcelSelected> selectedMap) {
  66. return new SheetWriteHandler() {
  67. @Override
  68. public void beforeSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
  69. }
  70. @Override
  71. public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
  72. //获取正在处理的工作表对象
  73. Sheet sheet = writeSheetHolder.getSheet();
  74. //获得一个用于创建数据验证规则的辅助对象,用于创建和配置数据验证规则
  75. DataValidationHelper helper = sheet.getDataValidationHelper();
  76. selectedMap.forEach((k, v) -> {//其中 (k, v) 表示 Map 的键和值,在每次迭代时会传入这两个参数。
  77. // 获取固定下拉框的内容
  78. List<String> source = new ArrayList<>();
  79. //如果 ExcelSelected 注解中的 source 数组不为空,则将其转换为 List,并添加到 source 变量中
  80. if (v.source().length > 0) {
  81. source.addAll(Arrays.asList(v.source()));
  82. }
  83. //CollUtil.isNotEmpty(source) 是一个对集合 source 进行非空判断的工具方法。
  84. if (CollUtil.isNotEmpty(source)) {
  85. /**
  86. * 代码创建一个 CellRangeAddressList 对象 rangeList,用于定义下拉框的范围。
  87. * 其中,v.firstRow() 和 v.lastRow() 分别表示下拉框的起始行和结束行,k 表示下拉框所在的列
  88. */
  89. CellRangeAddressList rangeList = new CellRangeAddressList(v.firstRow(), v.lastRow(), k, k);
  90. //用于定义下拉框的约束。该约束指定下拉框的选项为 source 列表中的内容
  91. DataValidationConstraint constraint = helper.createExplicitListConstraint(source.toArray(new String[0]));
  92. DataValidation validation = helper.createValidation(constraint, rangeList);
  93. //代码设置数据验证规则的错误样式为停止(DataValidation.ErrorStyle.STOP)
  94. validation.setErrorStyle(DataValidation.ErrorStyle.STOP);
  95. //显示错误提示框(validation.setShowErrorBox(true))
  96. validation.setShowErrorBox(true);
  97. //隐藏下拉箭头(validation.setSuppressDropDownArrow(true))
  98. validation.setSuppressDropDownArrow(true);
  99. validation.createErrorBox("提示", "请输入下拉选项中的内容");
  100. sheet.addValidationData(validation);
  101. }
  102. });
  103. }
  104. };
  105. }
  106. }

 (3)controller层

  1. @GetMapping("/export")
  2. public void exportData(@RequestParam(required = false) String deptId,//查询条件可不存在
  3. HttpServletResponse response) {
  4. // Data
  5. QueryWrapper<EmpUserEntity> wrapper = new QueryWrapper<>();
  6. wrapper.like(StrUtil.isNotBlank(deptId), "dept_id", deptId);
  7. //将部门id变为部门名称
  8. List<EmpUserEntity> list = empUserService.list(wrapper);
  9. EasyExcelUtils.writeExcelBySelect(response, "测试", "用户信息表", list);
  10. }

2、前端代码

(1)按钮展示

  1. <el-form-item style="float:right">
  2. <el-button type="success" @click="exportUser()">导出</el-button>
  3. </el-form-item>
  4. <el-form-item style="float:right">
  5. <el-input v-model="dataForm.deptId" placeholder="请选择部门进行导出" style="width: 200px" clearable></el-input>
  6. </el-form-item>

(2)方法定义

  1. // 导出用户,通过blob
  2. exportUser() {
  3. this.$axios({
  4. method: 'get',
  5. url: this.$http.adornUrl('/emp/user/export?deptId='+this.dataForm.deptId),
  6. responseType: 'blob',
  7. }).then(function (response){
  8. let blob = new Blob([response.data], { type: 'application/vnd.ms-excel;charset=utf-8' })
  9. let downloadElement = document.createElement('a');//创建一个 <a> 元素,用于执行文件下载操作。
  10. let href = window.URL.createObjectURL(blob); //创建下载的链接
  11. downloadElement.href = href;// 将下载链接指定给 <a> 元素的 href 属性。
  12. downloadElement.download = 'test.xlsx'; //下载后文件名
  13. document.body.appendChild(downloadElement);// 将 <a> 元素添加到页面的 <body> 元素中。
  14. downloadElement.click(); //点击下载
  15. document.body.removeChild(downloadElement); //下载完成移除元素
  16. window.URL.revokeObjectURL(href); //释放掉blob对象
  17. }).catch(function(error){
  18. this.$message.error(error)
  19. })
  20. },

3、实物展示

 

----------------------------------------------------------------------------

   本页面的导出下拉框,是固定写入,若需要动态导入,可参考以下大佬文章:

   http://t.csdnimg.cn/zBVD0

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/536882
推荐阅读
相关标签
  

闽ICP备14008679号