Spring Boot整合EasyExcel导入导出

蔚落 2023-05-30 09:13 149阅读 0赞

ps:2021,对本篇博客进行一个更新,重新写了一个demo,并对easyExcel封装了一个工具类,以下是demo的完整内容:

一、项目结构:

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM3NDk1Nzg2_size_16_color_FFFFFF_t_70

1、使用jar包 pom.xml:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  4. <modelVersion>4.0.0</modelVersion>
  5. <parent>
  6. <groupId>org.springframework.boot</groupId>
  7. <artifactId>spring-boot-starter-parent</artifactId>
  8. <version>2.4.2</version>
  9. <relativePath/> <!-- lookup parent from repository -->
  10. </parent>
  11. <groupId>com.example</groupId>
  12. <artifactId>demo</artifactId>
  13. <version>0.0.1-SNAPSHOT</version>
  14. <name>demo</name>
  15. <description>Demo project for Spring Boot</description>
  16. <properties>
  17. <java.version>1.8</java.version>
  18. </properties>
  19. <dependencies>
  20. <dependency>
  21. <groupId>org.springframework.boot</groupId>
  22. <artifactId>spring-boot-starter-web</artifactId>
  23. </dependency>
  24. <dependency>
  25. <groupId>com.alibaba</groupId>
  26. <artifactId>easyexcel</artifactId>
  27. <version>2.1.6</version>
  28. </dependency>
  29. <dependency>
  30. <groupId>com.alibaba</groupId>
  31. <artifactId>fastjson</artifactId>
  32. <version>1.2.58</version>
  33. </dependency>
  34. <dependency>
  35. <groupId>org.apache.commons</groupId>
  36. <artifactId>commons-lang3</artifactId>
  37. <version>3.8.1</version>
  38. </dependency>
  39. <dependency>
  40. <groupId>mysql</groupId>
  41. <artifactId>mysql-connector-java</artifactId>
  42. </dependency>
  43. <dependency>
  44. <groupId>com.baomidou</groupId>
  45. <artifactId>mybatis-plus-boot-starter</artifactId>
  46. <version>3.4.0</version>
  47. </dependency>
  48. <dependency>
  49. <groupId>org.projectlombok</groupId>
  50. <artifactId>lombok</artifactId>
  51. <optional>true</optional>
  52. </dependency>
  53. <dependency>
  54. <groupId>org.springframework.boot</groupId>
  55. <artifactId>spring-boot-starter-test</artifactId>
  56. <scope>test</scope>
  57. </dependency>
  58. <dependency>
  59. <groupId>javax.validation</groupId>
  60. <artifactId>validation-api</artifactId>
  61. <version>2.0.1.Final</version>
  62. </dependency>
  63. </dependencies>
  64. <build>
  65. <plugins>
  66. <plugin>
  67. <groupId>org.springframework.boot</groupId>
  68. <artifactId>spring-boot-maven-plugin</artifactId>
  69. <configuration>
  70. <excludes>
  71. <exclude>
  72. <groupId>org.projectlombok</groupId>
  73. <artifactId>lombok</artifactId>
  74. </exclude>
  75. </excludes>
  76. </configuration>
  77. </plugin>
  78. </plugins>
  79. </build>
  80. </project>

2、配置文件 application.yml:

  1. spring:
  2. datasource:
  3. username: root
  4. password: 123456
  5. url: jdbc:mysql://localhost:3306/employees?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
  6. driver-class-name: com.mysql.cj.jdbc.Driver

3、工具包 utils**:**

  1. 分为validaexcel以及一个断言工具类;
  2. valida包下用于校验对象属性是否满足要求,不了解可以去了解hibernate-validator
  3. excel包下是用于对excel进行解析。
  4. AssertUtil断言工具类,用于对判断当前是否该抛异常。

二、valida 下所有类

  1. package com.example.demo.utils.valida;
  2. /**
  3. * 新增数据 Group
  4. *
  5. * @author Lucifer
  6. */
  7. public interface AddGroup {
  8. }
  9. package com.example.demo.utils.valida;
  10. import javax.validation.GroupSequence;
  11. /**
  12. * 定义校验顺序(组顺序),如果AddGroup组失败,则UpdateGroup组不会再校验
  13. *
  14. * @author Lucifer
  15. */
  16. @GroupSequence({AddGroup.class,UpdateGroup.class})
  17. public interface Group {
  18. }
  19. package com.example.demo.utils.valida;
  20. /**
  21. * 更新数据 Group
  22. * @author Lucifer
  23. */
  24. public interface UpdateGroup {
  25. }
  26. package com.example.demo.utils.valida;
  27. import com.alibaba.excel.annotation.ExcelProperty;
  28. import javax.validation.ConstraintViolation;
  29. import javax.validation.Validation;
  30. import javax.validation.Validator;
  31. import javax.validation.groups.Default;
  32. import java.lang.reflect.Field;
  33. import java.util.Set;
  34. /**
  35. * hibernate-validator校验工具类
  36. *
  37. * @author Lucifer
  38. */
  39. public class ValidationUtil {
  40. private static Validator validator;
  41. static {
  42. validator = Validation.buildDefaultValidatorFactory().getValidator();
  43. }
  44. /**
  45. * 校验对象
  46. * 例: ValidationUtil.validateEntity(user,AddGroup.class),
  47. * 那么会对AddGroup分组下的属性和Default Group(ps:未加group属性,都是Default Group)下属性进行校验
  48. *
  49. * @param object 待校验对象
  50. * @param groups 待校验的组
  51. * @throws RuntimeException 校验不通过,则报ServerException异常
  52. */
  53. public static void validateEntity(Object object, Class<?>... groups)
  54. throws RuntimeException {
  55. Set<ConstraintViolation<Object>> constraintViolations = validator.validate(object, groups);
  56. if (!constraintViolations.isEmpty()) {
  57. ConstraintViolation<Object> constraint = constraintViolations.iterator().next();
  58. throw new RuntimeException(constraint.getMessage());
  59. }
  60. }
  61. /**
  62. * 校验默认分组,并将异常拼接起来
  63. *
  64. * @param obj
  65. * @param <T>
  66. * @return
  67. * @throws NoSuchFieldException
  68. */
  69. public static <T> String validateEntity(T obj) throws NoSuchFieldException {
  70. StringBuilder result = new StringBuilder();
  71. Set<ConstraintViolation<T>> set = validator.validate(obj, Default.class);
  72. if (set != null && !set.isEmpty()) {
  73. for (ConstraintViolation<T> cv : set) {
  74. Field declaredField = obj.getClass().getDeclaredField(cv.getPropertyPath().toString());
  75. ExcelProperty annotation = declaredField.getAnnotation(ExcelProperty.class);
  76. //拼接错误信息,包含当前出错数据的标题名字+错误信息
  77. result.append(annotation.value()[0] + cv.getMessage()).append(";");
  78. }
  79. }
  80. return result.toString();
  81. }
  82. }

三、excel 下所有类

  1. package com.example.demo.utils.excel;
  2. import com.alibaba.excel.EasyExcel;
  3. import lombok.extern.slf4j.Slf4j;
  4. import org.springframework.web.multipart.MultipartFile;
  5. import javax.servlet.http.HttpServletResponse;
  6. import java.io.IOException;
  7. import java.io.InputStream;
  8. import java.net.URLEncoder;
  9. import java.util.List;
  10. import java.util.function.Function;
  11. @Slf4j
  12. public class ExcelUtil {
  13. /**
  14. * 写excel
  15. *
  16. * @param response
  17. * @param list
  18. * @param fileName
  19. * @param sheetName
  20. * @param clazz
  21. * @throws Exception
  22. */
  23. public static void writeExcel(HttpServletResponse response, List<?> list, String fileName, String sheetName, Class clazz) {
  24. try {
  25. response.setCharacterEncoding("utf8");
  26. response.setContentType("application/vnd.ms-excel;charset=utf-8");
  27. response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileName + ".xlsx", "UTF-8"));
  28. response.setHeader("Cache-Control", "no-store");
  29. response.addHeader("Cache-Control", "max-age=0");
  30. EasyExcel.write(response.getOutputStream(), clazz)
  31. .sheet(sheetName)
  32. .doWrite(list);
  33. } catch (IOException e) {
  34. e.printStackTrace();
  35. }
  36. }
  37. /**
  38. * 读取excel,并返回错误错误行号及原因
  39. *
  40. * @param file excel文件
  41. * @param tClass excel读取的实体类
  42. * @param function function接口
  43. * @param tClass excelParams BaseExcelListener监听器所需参数
  44. * @param <T>
  45. */
  46. public static <T extends BaseExcelModel> List<ErrorModel> readExcel(MultipartFile file, Class<T> tClass, Function<List<T>,List<ErrorModel>> function, ExcelParams excelParams) {
  47. //todo 做文件格式校验以及文件大小校验
  48. BaseExcelListener<T> listener = new BaseExcelListener<T>(function, excelParams);
  49. try (InputStream inputStream = file.getInputStream()) {
  50. EasyExcel.read(inputStream, tClass, listener).sheet().doRead();
  51. } catch (IOException e) {
  52. log.error("readExcel error:{}", e);
  53. throw new RuntimeException("readExcel error");
  54. }
  55. return listener.getErrorList();
  56. }
  57. /**
  58. * 同上
  59. * @param file
  60. * @param tClass
  61. * @param function
  62. * @param <T>
  63. * @return
  64. */
  65. public static <T extends BaseExcelModel> List<ErrorModel> readExcel(MultipartFile file, Class<T> tClass, Function<List<T>,List<ErrorModel>> function) {
  66. return readExcel(file, tClass, function, null);
  67. }
  68. }
  69. package com.example.demo.utils.excel;
  70. import lombok.AllArgsConstructor;
  71. import lombok.Builder;
  72. import lombok.Data;
  73. import lombok.NoArgsConstructor;
  74. /**
  75. * excel监听器构造器所需参数对象
  76. *
  77. * @author Lucifer
  78. */
  79. @Data
  80. @AllArgsConstructor
  81. @NoArgsConstructor
  82. @Builder
  83. public class ExcelParams {
  84. /**
  85. * 读取时抛出异常是否继续读取,true:跳过继续读取, false:停止读取
  86. */
  87. private Boolean continueAfterThrowing;
  88. /**
  89. * 每隔N条存执行一次方法
  90. */
  91. private Integer batchCount;
  92. /**
  93. * 是否在解析excel时,通过ValidationUtil校验数据
  94. */
  95. private Boolean validateBeforeAddData;
  96. }
  97. package com.example.demo.utils.excel;
  98. import com.alibaba.excel.annotation.ExcelProperty;
  99. import lombok.AllArgsConstructor;
  100. import lombok.Builder;
  101. import lombok.Data;
  102. import lombok.NoArgsConstructor;
  103. /**
  104. * 错误信息对象
  105. *
  106. * @author lucifer
  107. */
  108. @NoArgsConstructor
  109. @AllArgsConstructor
  110. @Data
  111. @Builder
  112. public class ErrorModel {
  113. @ExcelProperty("行号")
  114. private Integer rowNo;
  115. @ExcelProperty("原始数据")
  116. private String resourceBody;
  117. @ExcelProperty("错误原因")
  118. private String errorMessage;
  119. }
  120. package com.example.demo.utils.excel;
  121. import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
  122. import com.baomidou.mybatisplus.annotation.TableField;
  123. import lombok.Data;
  124. /**
  125. * //TODO
  126. *
  127. * @author: zhang_zhi_kang
  128. */
  129. @Data
  130. @ExcelIgnoreUnannotated
  131. public class BaseExcelModel {
  132. /**
  133. * 行号
  134. */
  135. @TableField(exist = false)
  136. private Integer rowNo;
  137. }
  138. package com.example.demo.utils.excel;
  139. import com.alibaba.excel.context.AnalysisContext;
  140. import com.alibaba.excel.event.AnalysisEventListener;
  141. import com.alibaba.fastjson.JSON;
  142. import com.example.demo.utils.AssertUtil;
  143. import com.example.demo.utils.valida.ValidationUtil;
  144. import lombok.extern.slf4j.Slf4j;
  145. import org.apache.commons.lang3.StringUtils;
  146. import java.util.ArrayList;
  147. import java.util.List;
  148. import java.util.Objects;
  149. import java.util.function.Function;
  150. /**
  151. * excel监听器
  152. *
  153. * @author: Lucifer
  154. */
  155. @Slf4j
  156. public class BaseExcelListener<Model extends BaseExcelModel> extends AnalysisEventListener<Model> {
  157. /**
  158. * data
  159. */
  160. private List<Model> dataList = new ArrayList<>();
  161. /**
  162. * 失败执行data
  163. */
  164. private List<ErrorModel> errorList = new ArrayList<>();
  165. /**
  166. * <p>读取时抛出异常是否继续读取.</p>
  167. * <p>true:跳过继续读取 , false:停止读取 , 默认true .</p>
  168. */
  169. private boolean continueAfterThrowing = true;
  170. /**
  171. * 每隔N条存执行一次方法,
  172. * 如果是入库操作,可使用默认的3000条,然后清理list,方便内存回收
  173. */
  174. private Integer batchCount = 3_000;
  175. /**
  176. * 该方法用于对读取excel过程中对每一行的数据进行校验操作,
  177. * 如果不需要对每行数据进行校验,则直接返回false即可.
  178. */
  179. private boolean validateBeforeAddData = true;
  180. private Function<List<Model>, List<ErrorModel>> function;
  181. public BaseExcelListener(Function<List<Model>, List<ErrorModel>> function, ExcelParams excelParams) {
  182. AssertUtil.isNull(function, "param(function) must not null");
  183. this.function = function;
  184. if (!Objects.isNull(excelParams)) {
  185. this.continueAfterThrowing = excelParams.getContinueAfterThrowing();
  186. this.batchCount = excelParams.getBatchCount();
  187. this.validateBeforeAddData = excelParams.getValidateBeforeAddData();
  188. }
  189. }
  190. /**
  191. * 这个每一条数据解析都会来调用
  192. *
  193. * @param data
  194. * @param context
  195. */
  196. @Override
  197. public void invoke(Model data, AnalysisContext context) {
  198. String json = JSON.toJSONString(data);
  199. log.info("解析到一条数据:{}", json);
  200. //设置行号(用于赋值在doService中返回的ErrorModel)
  201. data.setRowNo(getCurrentRowIndex(context));
  202. if (validateBeforeAddData) {
  203. validateBeforeAddData(data, context, json);
  204. } else {
  205. dataList.add(data);
  206. }
  207. // 达到batchCount了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
  208. if (dataList.size() >= batchCount) {
  209. doService();
  210. // 存储完成清理 dataList
  211. dataList.clear();
  212. }
  213. }
  214. /**
  215. * 校验data
  216. *
  217. * @param data
  218. * @param context
  219. * @param json
  220. */
  221. private void validateBeforeAddData(Model data, AnalysisContext context, String json) {
  222. String errorMessage;
  223. try {
  224. errorMessage = ValidationUtil.validateEntity(data);
  225. } catch (NoSuchFieldException e) {
  226. log.error("BaseExcelListener invoke,error:{}:", e);
  227. errorMessage = "该类没有指定名称的字段,error:" + e.getMessage();
  228. }
  229. if (StringUtils.isNotBlank(errorMessage)) {
  230. errorList.add(new ErrorModel(getCurrentRowIndex(context), json, errorMessage));
  231. } else {
  232. dataList.add(data);
  233. }
  234. }
  235. /**
  236. * 所有数据解析完成了 都会来调用
  237. *
  238. * @param context
  239. */
  240. @Override
  241. public void doAfterAllAnalysed(AnalysisContext context) {
  242. doService();
  243. // 存储完成清理 list
  244. dataList.clear();
  245. }
  246. /**
  247. * 保存数据库
  248. * 需要由调用者自己实现
  249. */
  250. public void doService() {
  251. log.info("数据库保存开始.......");
  252. //这里可以拿到你处理业务时,返回的行号、原始数据、异常信息
  253. List<ErrorModel> errorModels = function.apply(dataList);
  254. errorList.addAll(errorModels);
  255. log.info("数据库保存结束.......");
  256. }
  257. /**
  258. * 在转换异常 获取其他异常下会调用本接口。抛出异常则停止读取。如果这里不抛出异常则继续读取下一行。
  259. * 如果不重写该方法,默认抛出异常,停止读取
  260. *
  261. * @param exception exception
  262. * @param context context
  263. */
  264. @Override
  265. public void onException(Exception exception, AnalysisContext context) throws Exception {
  266. // 如果continueAfterThrowing为false,则直接将异常抛出
  267. if (!continueAfterThrowing) {
  268. throw exception;
  269. }
  270. //当前sheet,当前行
  271. Integer rowIndex = context.readRowHolder().getRowIndex();
  272. log.error("读取发生错误! 错误SheetNo:{},错误行号:{},ERROR:{}", getCurrentSheetNo(context), context.readRowHolder().getRowIndex(), exception);
  273. errorList.add(new ErrorModel(rowIndex, JSON.toJSONString(getCurrentRowAnalysisResult(context)), exception.getMessage()));
  274. }
  275. /**
  276. * 获取当前读取的sheet no
  277. *
  278. * @param context 定义了获取读取excel相关属性的方法
  279. * @return current sheet no
  280. */
  281. private Integer getCurrentSheetNo(AnalysisContext context) {
  282. return context.readSheetHolder().getSheetNo();
  283. }
  284. /**
  285. * 获取当前读取的行号
  286. *
  287. * @param context 定义了获取读取excel相关属性的方法
  288. * @return current row index
  289. */
  290. private Integer getCurrentRowIndex(AnalysisContext context) {
  291. return context.readRowHolder().getRowIndex();
  292. }
  293. /**
  294. * 获取当前正在读取的行数据
  295. *
  296. * @param context
  297. * @return
  298. */
  299. private Object getCurrentRowAnalysisResult(AnalysisContext context) {
  300. return context.readRowHolder().getCurrentRowAnalysisResult();
  301. }
  302. /**
  303. * 获取错误的行号,和错误信息
  304. *
  305. * @return Map<Integer, List < String>>
  306. */
  307. public List<ErrorModel> getErrorList() {
  308. return errorList;
  309. }
  310. /**
  311. * 获取data数据
  312. *
  313. * @return
  314. */
  315. public List<Model> getData() {
  316. return dataList;
  317. }
  318. /**
  319. * 异常条数
  320. */
  321. public Integer getErrorSize() {
  322. return errorList.size();
  323. }
  324. }

四、断言工具类

  1. package com.example.demo.utils;
  2. import java.util.Objects;
  3. import java.util.function.Supplier;
  4. /**
  5. * 断言工具类
  6. *
  7. * @author: Lucifer
  8. */
  9. public class AssertUtil {
  10. public static void isNull(Object object, String message) {
  11. if (Objects.isNull(object)) {
  12. throw new RuntimeException(message);
  13. }
  14. }
  15. /**
  16. * 判断object参数是否为空
  17. * Assert.isNull(null, IllegalArgumentException::new);
  18. *
  19. * @param object object类型
  20. * @param errorSupplier 错误抛出异常接口
  21. */
  22. public static <X extends Throwable> void isNull(Object object, Supplier<X> errorSupplier) throws X {
  23. if (Objects.isNull(object)) {
  24. throw errorSupplier.get();
  25. }
  26. }
  27. }

五、测试

1、测试代码

  1. package com.example.demo.pojo;
  2. import com.alibaba.excel.annotation.ExcelProperty;
  3. import com.baomidou.mybatisplus.annotation.TableField;
  4. import com.baomidou.mybatisplus.annotation.TableName;
  5. import com.example.demo.utils.excel.BaseExcelModel;
  6. import com.fasterxml.jackson.annotation.JsonFormat;
  7. import lombok.AllArgsConstructor;
  8. import lombok.Data;
  9. import lombok.NoArgsConstructor;
  10. import org.springframework.format.annotation.DateTimeFormat;
  11. import java.util.Date;
  12. @AllArgsConstructor
  13. @NoArgsConstructor
  14. @Data
  15. @TableName("employees")
  16. public class Employees extends BaseExcelModel {
  17. @TableField("emp_no")
  18. @ExcelProperty(value = "员工编号")
  19. private Integer empNo;
  20. @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
  21. @DateTimeFormat(pattern = "yyyy-MM-dd")
  22. @ExcelProperty(value = "生日")
  23. @TableField("birth_date")
  24. private Date birthDate;
  25. @TableField("first_name")
  26. @ExcelProperty(value = "名字")
  27. private String firstName;
  28. @TableField("last_name")
  29. @ExcelProperty(value = "姓")
  30. private String lastName;
  31. @TableField("gender")
  32. @ExcelProperty(value = "性别")
  33. private String gender;
  34. @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
  35. @DateTimeFormat(pattern = "yyyy-MM-dd")
  36. @ExcelProperty(value = "入职日期")
  37. @TableField("hire_date")
  38. private Date hireDate;
  39. }
  40. package com.example.demo.mapper;
  41. import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  42. import com.example.demo.pojo.Employees;
  43. import org.apache.ibatis.annotations.Mapper;
  44. /**
  45. * //TODO
  46. *
  47. * @author: lucifer
  48. */
  49. @Mapper
  50. public interface ExcelMapper extends BaseMapper<Employees> {
  51. }
  52. package com.example.demo.service;
  53. import com.alibaba.fastjson.JSON;
  54. import com.example.demo.pojo.Employees;
  55. import com.example.demo.utils.excel.ErrorModel;
  56. import org.springframework.stereotype.Service;
  57. import java.util.ArrayList;
  58. import java.util.List;
  59. import java.util.Optional;
  60. /**
  61. * //TODO
  62. *
  63. * @author: Lucifer
  64. */
  65. @Service
  66. public class ExcelService {
  67. public List<ErrorModel> importExcel(List<Employees> employees) {
  68. //查询出数据库重复的(模拟)
  69. //用employees中的唯一字段去数据库查询
  70. List<Employees> repeatList = new ArrayList<>();
  71. //repeatList 里面的数据实际应该有数据库查询所得
  72. //此处最好是用in 然后一条sql查询这个批次所有的,但是in中不要过大,3000差不多了
  73. List<ErrorModel> errorModels = new ArrayList<>();
  74. Optional.ofNullable(repeatList).
  75. orElse(new ArrayList<>()).forEach(emp ->
  76. errorModels.add(ErrorModel.builder()
  77. .rowNo(emp.getRowNo())
  78. .resourceBody(JSON.toJSONString(employees))
  79. .errorMessage("xxxx重复").build()));
  80. //因处可以将插入数据库的操作写在另外一个service当中,比如叫xxxExcelService,然后
  81. //插入数据库的方法假如叫做insertDb();在insertDb方法中用@Transactional(rollbackFor = Exception.class,propagation=Propagation.REQUIRES_NEW)
  82. //然后在当前这个service中注入xxxExcelService,调用insertDb方法,并将其try catch住,
  83. //这里不要抛异常,而是将其构造成ErrorModel对象,统一返回,这个insertDb的事务因为是
  84. //另起的事务,所以一旦出现异常是会回滚数据库操作的。
  85. return errorModels;
  86. }
  87. }
  88. package com.example.demo.controller;
  89. import com.example.demo.mapper.ExcelMapper;
  90. import com.example.demo.pojo.Employees;
  91. import com.example.demo.service.ExcelService;
  92. import com.example.demo.utils.excel.ExcelUtil;
  93. import org.springframework.beans.factory.annotation.Autowired;
  94. import org.springframework.web.bind.annotation.GetMapping;
  95. import org.springframework.web.bind.annotation.PostMapping;
  96. import org.springframework.web.bind.annotation.RestController;
  97. import org.springframework.web.multipart.MultipartFile;
  98. import javax.annotation.Resource;
  99. import javax.servlet.http.HttpServletResponse;
  100. import java.util.List;
  101. /**
  102. * 测试
  103. *
  104. * @author: lucifer
  105. */
  106. @RestController
  107. public class TestController {
  108. @Resource
  109. private ExcelMapper excelMapper;
  110. @Autowired
  111. private ExcelService excelService;
  112. @GetMapping("test1")
  113. public void testExportExcel(HttpServletResponse httpServletResponse) {
  114. long startTime = System.currentTimeMillis();
  115. List<Employees> employees = excelMapper.selectList(null);
  116. ExcelUtil.writeExcel(httpServletResponse, employees, "文件名", "工作薄名", Employees.class);
  117. System.out.println("数据量:"+employees.size()+",耗时(毫秒):"+(System.currentTimeMillis()-startTime));
  118. }
  119. @PostMapping("test1")
  120. public void testImportExcel(MultipartFile file) {
  121. //如果记录日志,可以用异步去插入数据,日志信息主表(另开一个事务)
  122. ExcelUtil.readExcel(file, Employees.class, obj -> excelService.importExcel(obj));
  123. //插入日志详情表,并更新日志主表(另开一个事务)
  124. }
  125. }

2、测试结果

导出:

20210209130556424.png

导入:

懒得测了(#^.^#)

发表评论

表情:
评论列表 (有 0 条评论,149人围观)

还没有评论,来说两句吧...

相关阅读