EasyExcel的导入导出使用

1、说明

EasyExcel是阿里出的一款基于Java的、快速、简洁、解决大文件内存溢出的处理Excel的开源工具,本文主要是使用这个工具对Excel导入导出进行讲解。

  • 官网: https://easyexcel.opensource.alibaba.com/
  • github: https://github.com/alibaba/easyexcel

2、EasyExcel的使用

2.1、创建工具类

创建工具类EasyExcelUtil,将导出和导入的相关方法写入该类中,以下详细讲述使用EasyExcel导出、导入数据。

2.1.1、EasyExcel导出

2.1.1.1、导出一个sheet-无样式

/*** 导出excel表格** @param response* @param dataList  数据列表* @param clazz     数据对象* @param fileName  文件名称* @param sheetName sheet名称* @throws Exception*/
public static <T> void exportExcel(HttpServletResponse response, List<T> dataList, Class<T> clazz, String fileName, String sheetName) throws Exception {response.setContentType("application/vnd.ms-excel");response.setCharacterEncoding(StandardCharsets.UTF_8.name());fileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.name());response.setHeader("Content-disposition", "attachment;filename=" + fileName + FileTypeEnum.TEMPLATE_SUFFIX.getDesc());EasyExcelFactory.write(response.getOutputStream(), clazz).sheet(sheetName).doWrite(dataList);
}

2.1.1.2、导出一个sheet-有样式

/*** 导出excel表格-支设置单元格样式** @param response* @param dataList     数据列表* @param clazz        数据对象* @param fileName     文件名称* @param sheetName    sheet名称* @param writeHandler 处理器* @throws Exception*/
public static <T> void exportWriteHandlerExcel(HttpServletResponse response, List<T> dataList, Class<T> clazz, String fileName, String sheetName, WriteHandler writeHandler) throws Exception {response.setContentType("application/vnd.ms-excel");response.setCharacterEncoding(StandardCharsets.UTF_8.name());fileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.name());response.setHeader("Content-disposition", "attachment;filename=" + fileName + FileTypeEnum.TEMPLATE_SUFFIX.getDesc());ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream(), clazz).build();// 这里注意如果同一个sheet只要创建一次WriteSheet writeSheet = EasyExcel.writerSheet(sheetName).registerWriteHandler(writeHandler).build();excelWriter.write(dataList, writeSheet);excelWriter.finish();
}

2.1.1.3、导出多个sheet

/*** 导出多个sheet** @param response* @param dataList 多个sheet数据列表* @param clazzMap 对应每个sheet列表里面的数据对应的sheet名称* @param fileName 文件名* @param <T>* @throws Exception*/
public static <T> void exportExcels(HttpServletResponse response, List<List<?>> dataList, Map<Integer, String> clazzMap, String fileName) throws Exception {response.setContentType("application/vnd.ms-excel");response.setCharacterEncoding(StandardCharsets.UTF_8.name());fileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.name());response.setHeader("Content-disposition", "attachment;filename=" + fileName + FileTypeEnum.TEMPLATE_SUFFIX.getDesc());ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).build();int sheetNum = dataList.size();for (int i = 0; i < sheetNum; i++) {List<?> objects = dataList.get(i);Class<?> aClass = objects.get(0).getClass();WriteSheet writeSheet0 = EasyExcel.writerSheet(i, clazzMap.get(i)).head(aClass).build();excelWriter.write(objects, writeSheet0);}excelWriter.finish();
}

2.1.1.4、导出手动填充数据的模板

此功能应用于导出同一个业务功能数据,但是每次导出的数据的表头是动态变化的,比如不同租户查看的同一个页面上展示的字段不一样,举个例子,租户A看到展示的字段是a、b、c;租户B看到展示字段是a、b。那么此时导出模板的表头字段就不一样。
<1>导出模板,传入一个处理器

/*** 导出excel表格-列不确定情况;只导出模板【一个处理器】** @param response* @param headList     表头列表* @param dataList     数据列表* @param fileName     文件名称* @param sheetName    sheet名称* @param writeHandler 处理器* @throws Exception*/
public static <T> void exportExcel(HttpServletResponse response, List<List<String>> headList, List<List<T>> dataList, 
String fileName, String sheetName, WriteHandler writeHandler) throws Exception {response.setContentType("application/vnd.ms-excel");response.setCharacterEncoding(StandardCharsets.UTF_8.name());fileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.name());response.setHeader("Content-disposition", "attachment;filename=" + fileName + FileTypeEnum.TEMPLATE_SUFFIX.getDesc());ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).build();// 这里注意如果同一个sheet只要创建一次ExcelWriterSheetBuilder sheetBuilder = EasyExcel.writerSheet(sheetName).head(headList);if (null != writeHandler) {sheetBuilder.registerWriteHandler(writeHandler);}WriteSheet writeSheet = sheetBuilder.build();excelWriter.write(dataList, writeSheet);excelWriter.finish();
}

<2>导出模板,传入多个处理器

/*** 导出excel表格-列不确定情况;只导出模板【多个处理器】** @param response* @param headList      表头列表* @param dataList      数据列表* @param fileName      文件名称* @param sheetName     sheet名称* @param writeHandlers 处理器集合* @throws Exception*/
public static <T> void exportExcel(HttpServletResponse response, List<List<String>> headList, List<List<T>> dataList, String fileName, String sheetName, List<WriteHandler> writeHandlers) throws Exception {response.setContentType("application/vnd.ms-excel");response.setCharacterEncoding(StandardCharsets.UTF_8.name());fileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.name());response.setHeader("Content-disposition", "attachment;filename=" + fileName + FileTypeEnum.TEMPLATE_SUFFIX.getDesc());ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).build();// 这里注意如果同一个sheet只要创建一次ExcelWriterSheetBuilder sheetBuilder = EasyExcel.writerSheet(sheetName).head(headList);if (CollUtil.isNotEmpty(writeHandlers)) {for (WriteHandler writeHandler : writeHandlers) {sheetBuilder.registerWriteHandler(writeHandler);}}WriteSheet writeSheet = sheetBuilder.build();excelWriter.write(dataList, writeSheet);excelWriter.finish();
}

2.1.1.5、根据模板导出数据

填充数据的模板示例如下,注意:模板的格式需要加上字段对应的字段属性名称。样式举例:
在这里插入图片描述
说明:. 的{}就是根据自定义实体存值,{}里面是你自己写的字段
<1>填充列表数据

/*** 根据模板将集合对象填充表格** @param inputStream 模板文件输入流* @param response    模板文件输出流* @param list        填充对象集合* @param fileName    文件名称* @param sheetName   需要写入的sheet(不传:填充到第一个sheet)* @throws Exception*/
public static <T> void exportTemplateExcelList(InputStream inputStream, HttpServletResponse response, List<T> list, String fileName, String sheetName) throws Exception {// 全部填充:全部加载到内存中一次填充if (StringUtils.isBlank(sheetName)) {EasyExcelFactory.write(getOutputStream(fileName, response)).withTemplate(inputStream).sheet().doFill(list);} else {EasyExcelFactory.write(getOutputStream(fileName, response)).withTemplate(inputStream).sheet(sheetName).doFill(list);}
}

<2>填充列表+自定义字段属性值数据
此场景适用于模板中的一些字段不是实体中字段,而是一些特殊处理的字段,比如说展示当前文档的一个指示说明,只是特别标注在文档中某一个位置就好了,这个不是集合中的数据,所以自定义字段需要进行特殊处理,他的处理是通过下面方法的入参object。

一个sheet

/*** 根据模板将集合对象填充表格-单个sheet** @param inputStream 模板文件输入流* @param list        填充对象集合-元素对应模板中的.{}* @param object      填充对象-元素对应模板中的{}* @param fileName    文件名称* @throws Exception*/
public static <T> void exportTemplateSheet(InputStream inputStream, HttpServletResponse response, List<T> list, Object object, String fileName) throws Exception {FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();ExcelWriter excelWriter = EasyExcelFactory.write(getOutputStream(fileName, response)).withTemplate(inputStream).build();WriteSheet writeSheet0 = EasyExcelFactory.writerSheet(0).build();// 全部填充:全部加载到内存中一次填充excelWriter.fill(object, fillConfig, writeSheet0);excelWriter.fill(list, fillConfig, writeSheet0);// 可分多次填充,使用文件缓存(省内存)// excelWriter.fill(list1, writeSheet);// excelWriter.fill(list2, writeSheet);excelWriter.finish();
}

两个sheet

/*** 根据模板将集合对象填充表格-多个sheet** @param inputStream 模板文件输入* @param response    模板文件输出流* @param list1       填充对象集合-元素对应模板中的.{}* @param list2* @param object1     填充对象-元素对应模板中的{}* @param object2* @param fileName    文件名称* @throws Exception*/
public static <T> void exportTemplateSheets(InputStream inputStream, HttpServletResponse response, List<T> list1, List<T> list2,Object object1, Object object2, String fileName) throws Exception {FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();ExcelWriter excelWriter = EasyExcelFactory.write(getOutputStream(fileName, response)).withTemplate(inputStream).build();WriteSheet writeSheet0 = EasyExcelFactory.writerSheet(0).build();WriteSheet writeSheet1 = EasyExcelFactory.writerSheet(1).build();excelWriter.fill(object1, fillConfig, writeSheet0);excelWriter.fill(list1, fillConfig, writeSheet0);excelWriter.fill(object2, fillConfig, writeSheet1);excelWriter.fill(list2, fillConfig, writeSheet1);excelWriter.finish();
}

2.1.1.6、补充导出公共方法getOutputStream

/*** 构建输出流** @param fileName 文件名称* @param response 模板文件输出流* @param response* @return* @throws Exception*/
private static OutputStream getOutputStream(String fileName, HttpServletResponse response) throws Exception {fileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.name());response.setContentType("application/vnd.ms-excel");response.setCharacterEncoding(StandardCharsets.UTF_8.name());response.setHeader("Content-Disposition", "attachment;filename=" + fileName + FileTypeEnum.TEMPLATE_SUFFIX.getDesc());return response.getOutputStream();
}

2.1.2、EasyExcel导入

2.1.2.1、导入一个sheet

/*** 导入-读取一页sheet** @param inputStream 文件流* @param clazz       数据对象* @param sheetName   要读取的sheet (不传,默认读取第一个sheet)* @throws Exception*/
public static <T> List<T> importExcel(InputStream inputStream, Class<T> clazz, String sheetName, ReadExcelListener readExcelListener) throws Exception {ExcelReaderBuilder builder = EasyExcelFactory.read(inputStream, clazz, readExcelListener);if (StringUtils.isBlank(sheetName)) {builder.sheet().doRead();} else {builder.sheet(sheetName).doRead();}return readExcelListener.getList();
}

2.1.2.2、导入多个sheet

 /*** 导入-读取多个sheet** @param inputStream  文件流* @param sheetNum     需要读取的sheet个数(默认0开始,如果传入2,则读取0、1)* @param sheetObjList 每个sheet里面需要封装的对象(如果index为2,则需要传入对应的2个对象)* @param <T>* @return*/public static <T> List<List<T>> importExcels(InputStream inputStream, int sheetNum, List<T> sheetObjList, ReadExcelListener<T> readExcelListener) throws Exception {List<List<T>> resultList = new LinkedList<>();for (int index = 0; index < sheetNum; index++) {Class<T> tClass = (Class<T>) sheetObjList.get(index).getClass();EasyExcelFactory.read(inputStream, tClass, readExcelListener).sheet(index).doRead();List<T> list = readExcelListener.getList();resultList.add(list);}return resultList;}

2.2、创建导出样式相关公共类

2.2.1、设置单元格宽度

CellWidthStyleHandler

package com.wm.easyexcel.util;import cn.hutool.core.collection.CollUtil;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.data.CellData;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.write.handler.context.CellWriteHandlerContext;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.style.column.AbstractColumnWidthStyleStrategy;
import org.apache.poi.ss.usermodel.Cell;import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** @ClassName: CellWidthStyleHandler* @Description: 设置表头的调整宽策略* @Author: WM* @Date: 2022/12/23 14:37*/
public class CellWidthStyleHandler extends AbstractColumnWidthStyleStrategy {// 可以根据这里的最大宽度,按自己需要进行调整,搭配单元格样式实现类中的,自动换行,效果更好private static final int MAX_COLUMN_WIDTH = 50;private Map<Integer, Map<Integer, Integer>> CACHE = new HashMap(8);/*** 是否设置固定宽度*/private boolean fixed;/*** 固定宽度*/private int fixedWidth;public CellWidthStyleHandler() {}public CellWidthStyleHandler(boolean fixed, int fixedWidth) {this.fixed = fixed;this.fixedWidth = (fixedWidth == 0 ? 15 : fixedWidth);}@Overrideprotected void setColumnWidth(CellWriteHandlerContext context) {boolean needSetWidth = context.getHead() || !CollUtil.isEmpty(context.getCellDataList());if (!needSetWidth) {return;}WriteSheetHolder writeSheetHolder = context.getWriteSheetHolder();// 设置固定宽度if (fixed) {Cell cell = context.getCell();writeSheetHolder.getSheet().setColumnWidth(cell.getColumnIndex(), fixedWidth * 256);return;}// 设置自动调整宽度Map<Integer, Integer> maxColumnWidthMap = CACHE.get(writeSheetHolder.getSheetNo());if (maxColumnWidthMap == null) {maxColumnWidthMap = new HashMap(16);CACHE.put(writeSheetHolder.getSheetNo(), maxColumnWidthMap);}Cell cell = context.getCell();int columnWidth = this.dataLength(context.getCellDataList(), cell, context.getHead());if (columnWidth >= 0) {if (columnWidth > MAX_COLUMN_WIDTH) {columnWidth = MAX_COLUMN_WIDTH;}Integer maxColumnWidth = maxColumnWidthMap.get(cell.getColumnIndex());if (maxColumnWidth == null || columnWidth > maxColumnWidth) {maxColumnWidthMap.put(cell.getColumnIndex(), columnWidth);writeSheetHolder.getSheet().setColumnWidth(cell.getColumnIndex(), columnWidth * 256);}}}private int dataLength(List<WriteCellData<?>> cellDataList, Cell cell, Boolean isHead) {if (isHead) {return cell.getStringCellValue().getBytes().length;} else {CellData cellData = cellDataList.get(0);CellDataTypeEnum type = cellData.getType();if (type == null) {return -1;} else {switch (type) {case STRING:return cellData.getStringValue().getBytes().length;case BOOLEAN:return cellData.getBooleanValue().toString().getBytes().length;case NUMBER:return cellData.getNumberValue().toString().getBytes().length;default:return -1;}}}}
}

2.2.2、设置默认单元格字体样式

DefaultExcelHeadHandler

package com.wm.easyexcel.util;import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.write.handler.context.CellWriteHandlerContext;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import org.apache.poi.ss.usermodel.IndexedColors;/*** @ClassName: DefaultExcelHeadHandler* @Description: 默认自定义表头样式拦截器* @Author: WM* @Date: 2022/12/22 17:35*/
public class DefaultExcelHeadHandler extends HorizontalCellStyleStrategy {//设置头样式@Overrideprotected void setHeadCellStyle(CellWriteHandlerContext context) {WriteCellStyle headWriteCellStyle = new WriteCellStyle();headWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());WriteFont headWriteFont = new WriteFont();headWriteFont.setFontHeightInPoints((short) 11);headWriteFont.setColor(IndexedColors.BLACK.getIndex());headWriteCellStyle.setWriteFont(headWriteFont);if (stopProcessing(context)) {return;}WriteCellData<?> cellData = context.getFirstCellData();WriteCellStyle.merge(headWriteCellStyle, cellData.getOrCreateStyle());}
}

ExcelHeadStyles

package com.wm.easyexcel.util;import lombok.Data;/*** @ClassName: ExcelHeadStyles* @Description: excel表头颜色定义* @Author: WM* @Date: 2022/12/22 17:24*/
@Data
public class ExcelHeadStyles {/*** 表头横坐标 - 行*/private Integer rowIndex;/*** 表头纵坐标 - 列*/private Integer columnIndex;/*** 内置颜色*/private Short indexColor;/*** 字体颜色*/private Short fontColor;public ExcelHeadStyles(Integer columnIndex, Short fontColor) {this.columnIndex = columnIndex;this.fontColor = fontColor;}public ExcelHeadStyles(Integer rowIndex, Integer columnIndex, Short fontColor) {this.rowIndex = rowIndex;this.columnIndex = columnIndex;this.fontColor = fontColor;}
}

2.3、创建导入公共监听器

ReadExcelListener

package com.wm.easyexcel.util;import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.exception.ExcelDataConvertException;
import lombok.extern.slf4j.Slf4j;import java.util.ArrayList;
import java.util.List;
import java.util.Map;/*** @ClassName: ReadExcelListener* @Description: 读取excel文件数据监听器* @Author: WM* @Date: 2022/12/21 17:00*/
@Slf4j
public abstract class ReadExcelListener<T> extends AnalysisEventListener<T> {private static final int BATCH_COUNT = 10000;/*** 数据集*/private final List<T> list = new ArrayList<>();/*** 表头数据*/private Map<Integer, String> headMap = null;private Map<String, Object> params;// 获取数据集public List<T> getList() {return this.list;}// 获取表头数据public Map<Integer, String> getHeadMap() {return this.headMap;}/*** 每条数据都会进入** @param object* @param analysisContext*/@Overridepublic void invoke(T object, AnalysisContext analysisContext) {this.list.add(object);// 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOMif (list.size() >= BATCH_COUNT) {saveData();// 存储完成清理 listlist.clear();}}/*** 数据解析完调用** @param analysisContext*/@Overridepublic void doAfterAllAnalysed(AnalysisContext analysisContext) {// 这里也要保存数据,确保最后遗留的数据也存储到数据库saveData();log.info("所有数据解析完成!");}/*** 读取到的表头信息** @param headMap* @param context*/@Overridepublic void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {this.headMap = headMap;}/*** 异常时调用** @param exception:* @param context:* @throws Exception*/@Overridepublic void onException(Exception exception, AnalysisContext context) throws Exception {// 数据解析异常if (exception instanceof ExcelDataConvertException) {ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException) exception;throw new RuntimeException("第" + excelDataConvertException.getRowIndex() + "行" + excelDataConvertException.getColumnIndex() + "列" + "数据解析异常");}// 其他异常...}/*** 数据存储到数据库*/public abstract boolean saveData();
}

这里作为公共导入监听器,保存数据的方法saveData(),下放到各层具体的业务去继承实现。

2.4、创建实体类

创建学生和老师两个实体类
Student

package com.wm.easyexcel.entity;import com.alibaba.excel.annotation.ExcelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;/*** @ClassName: Student* @Description: 学生* @Author: WM* @Date: 2021-07-22 21:30**/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student {@ExcelProperty("序号")private Integer num;@ExcelProperty("学号")private String sno;@ExcelProperty("学生名字")private String name;@ExcelProperty("性别")private String sex;
}

Teacher

package com.wm.easyexcel.entity;import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;/*** @ClassName: Teacher* @Description: 老师* @Author: WM* @Date: 2021-07-22 21:30**/
@Data
public class Teacher {@ExcelProperty("编号")private String sno;@ExcelProperty("老师名字")private String name;@ExcelProperty("性别")private String sex;
}

2.5、创建业务接口

IStudentService

package com.wm.easyexcel.service;import com.wm.easyexcel.entity.Student;import java.util.List;
import java.util.Map;/*** @ClassName: IStudentService* @Description: 学生相关接口* @Author: WM* @Date: 2023/1/9 16:52*/
public interface IStudentService {/*** 查询学生集合信息** @return*/List<Student> listStudent(Long limit);/*** 批量保存学生数据** @param students* @return*/boolean batchSaveStudent(List<Student> students);/*** 批量保存学生数据-自行处理行列数据,不使用实体** @param dataList* @param headMap* @return*/boolean batchSaveStudent(List<Map<Integer, String>> dataList, Map<Integer, String> headMap);
}

对应的实现类StudentServiceImpl

package com.wm.easyexcel.service.impl;import cn.hutool.core.lang.UUID;
import com.wm.easyexcel.entity.Student;
import com.wm.easyexcel.service.IStudentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;import java.util.ArrayList;
import java.util.List;
import java.util.Map;/*** @ClassName: StudentServiceImpl* @Description: 学生相关接口实现* @Author: WM* @Date: 2023/1/9 16:53*/
@Slf4j
@Service
public class StudentServiceImpl implements IStudentService {@Overridepublic List<Student> listStudent(Long limit) {List<Student> students = new ArrayList<>();for (int i = 0; i < limit; i++) {Student student = new Student();student.setSex("男");student.setNum(i);student.setName("小A" + i);student.setSno(UUID.fastUUID().toString());students.add(student);}return students;}@Overridepublic boolean batchSaveStudent(List<Student> students) {// 调用dao层接口保存数据...log.info("批量保存学生数据,共:{}条数据", students.size());return true;}@Overridepublic boolean batchSaveStudent(List<Map<Integer, String>> dataList, Map<Integer, String> headMap) {// 这里可以针对读取到的表头数据和对应的行数据,这种应用场景适用于导入的excel中数据需要我们自己解析做其他业务处理,或者表头列是动态的,我们// 没有办法使用一个固定的实体做映射log.info("表头列数据:{}", headMap.values());log.info("批量保存学生数据,共:{}条数据", dataList.size());return true;}
}

ITeacherService

package com.wm.easyexcel.service;import com.wm.easyexcel.entity.Teacher;import java.util.List;
import java.util.Map;/*** @ClassName: ITeacherService* @Description: 老师相关接口* @Author: WM* @Date: 2023/1/9 16:52*/
public interface ITeacherService {/*** 查询老师集合信息** @return*/List<Teacher> listTeacher(Long limit);/*** 批量保存老师数据** @param Teachers* @return*/boolean batchSaveTeacher(List<Teacher> Teachers);}

对应的实现类TeacherServiceImpl

package com.wm.easyexcel.service.impl;import cn.hutool.core.lang.UUID;
import com.wm.easyexcel.entity.Teacher;
import com.wm.easyexcel.service.ITeacherService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;import java.util.ArrayList;
import java.util.List;/*** @ClassName: TeacherServiceImpl* @Description: 老师相关接口实现* @Author: WM* @Date: 2023/1/9 16:53*/
@Slf4j
@Service
public class TeacherServiceImpl implements ITeacherService {@Overridepublic List<Teacher> listTeacher(Long limit) {List<Teacher> teachers = new ArrayList<>();for (int i = 0; i < limit; i++) {Teacher teacher = new Teacher();teacher.setSex("女");teacher.setName("老师A" + i);teacher.setSno(UUID.fastUUID().toString());teachers.add(teacher);}return teachers;}@Overridepublic boolean batchSaveTeacher(List<Teacher> teachers) {// 调用dao层接口保存数据...log.info("批量保存老师数据,共:{}条数据", teachers.size());return true;}
}

2.6、创建Controller

2.6.1、导出ExportController

创建导出的Controller为工具类中各个导出方法的测试做准备。

2.6.1.1、代码展示

package com.wm.easyexcel.controller;import cn.hutool.core.collection.CollUtil;
import com.wm.easyexcel.entity.Student;
import com.wm.easyexcel.handler.UserExcelHeadHandler;
import com.wm.easyexcel.service.IStudentService;
import com.wm.easyexcel.service.ITeacherService;
import com.wm.easyexcel.strategy.RowMergeStrategy;
import com.wm.easyexcel.util.CellWidthStyleHandler;
import com.wm.easyexcel.util.EasyExcelUtil;
import com.wm.easyexcel.util.ExcelHeadStyles;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.*;
import java.util.stream.Collectors;/*** @ClassName: ExportController* @Description: 导出前端控制器* @Author: WM* @Date: 2023/1/9 16:44*/
@Slf4j
@RestController
public class ExportController {@Resourceprivate IStudentService studentService;@Resourceprivate ITeacherService teacherService;private static final String[] USER_HEAD_FIELDS = new String[]{"序号", "学号", "姓名", "性别"};/*** 导出学生数据-一个sheet** @param response*/@GetMapping("/student/export/sheet")public void exportSheetStudent(HttpServletResponse response) {List<Student> students = studentService.listStudent(10L);log.info("单sheet学生数据开始导出...");long startTimeL = System.currentTimeMillis();try {EasyExcelUtil.exportExcel(response, students, Student.class, "导出学生数据-一个sheet", "第一页");} catch (Exception e) {log.error("单sheet学生数据导出异常!", e);}log.info("单sheet学生数据导出完成:{}秒", (System.currentTimeMillis() - startTimeL) / 1000);}/*** 导出学生数据-多个sheet** @param response*/@GetMapping("/student/export/sheets")public void exportSheetsStudent(HttpServletResponse response) {log.info("多sheet学生数据开始导出...");long startTimeL = System.currentTimeMillis();try {List<List<?>> sheetList = new ArrayList<>();List<Student> students1 = studentService.listStudent(10L);List<Student> students2 = studentService.listStudent(20L);sheetList.add(students1);sheetList.add(students2);Map<Integer, String> clazzMap = new HashMap<>();clazzMap.put(0, "sheet1");clazzMap.put(1, "sheet2");EasyExcelUtil.exportExcels(response, sheetList, clazzMap, "导出学生数据-多个sheet");} catch (Exception e) {log.error("多sheet学生数据导出失败!", e);}log.info("多sheet学生数据导出完成:{}秒", (System.currentTimeMillis() - startTimeL) / 1000);}/*** 导出学生数据-重复行合并格式** @param response*/@GetMapping("/student/export/mergeRow")public void exportMergeRowStudent(HttpServletResponse response) {log.info("合并格式学生数据开始导出...");long startTimeL = System.currentTimeMillis();try {List<Student> students = studentService.listStudent(10L);List<String> mergeDataList = students.stream().map(Student::getSex).collect(Collectors.toList());EasyExcelUtil.exportWriteHandlerExcel(response, students, Student.class, "学生重复数据表格合并", "第一页", new RowMergeStrategy(mergeDataList, 3));} catch (Exception e) {log.error("合并格式学生数据导出失败!", e);}log.info("合并格式学生数据导出完成:{}秒", (System.currentTimeMillis() - startTimeL) / 1000);}/*** 下载导入学生数据的模板【一个自定义Handler】** @param response*/@GetMapping("/student/downTemplate001")public void downTemplateStudent001(HttpServletResponse response) {log.info("设置单元格宽度-学生数据模板开始下载...");long startTimeL = System.currentTimeMillis();try {List<List<String>> headList = Arrays.stream(USER_HEAD_FIELDS).map(field -> CollUtil.newArrayList(field)).collect(Collectors.toList());CellWidthStyleHandler columnWidthHandler = new CellWidthStyleHandler(true, 15);EasyExcelUtil.exportExcel(response, headList, Collections.EMPTY_LIST, "学生数据导入模板-设置单元格宽度", "student", columnWidthHandler);} catch (Exception e) {log.error("设置单元格宽度-学生数据模板下载失败!", e);}log.info("设置单元格宽度-学生数据模板下载完成:{}秒", (System.currentTimeMillis() - startTimeL) / 1000);}/*** 下载导入学生数据的模板【多个自定义Handler】** @param response*/@GetMapping("/student/downTemplate002")public void downTemplateStudent002(HttpServletResponse response) {log.info("设置单元格宽度+字体-学生数据模板开始下载...");long startTimeL = System.currentTimeMillis();try {List<List<String>> headList = Arrays.stream(USER_HEAD_FIELDS).map(field -> CollUtil.newArrayList(field)).collect(Collectors.toList());// 表头第一行的指定前3列字标红ExcelHeadStyles excelHeadStyle = new ExcelHeadStyles(0, 3, IndexedColors.RED1.getIndex());UserExcelHeadHandler headHandler = new UserExcelHeadHandler(excelHeadStyle);CellWidthStyleHandler columnWidthHandler = new CellWidthStyleHandler(true, 15);EasyExcelUtil.exportExcel(response, headList, Collections.EMPTY_LIST, "学生数据导入模板-设置单元格宽度+字体", "student", CollUtil.newArrayList(headHandler, columnWidthHandler));} catch (Exception e) {log.error("设置单元格宽度+字体-学生数据模板下载失败!", e);}log.info("设置单元格宽度+字体-学生数据模板下载完成:{}秒", (System.currentTimeMillis() - startTimeL) / 1000);}/**************以下填充模板数据的接口测试说明:可改为get请求,InputStream可使用本地文件输入流,然后变可通过浏览器下载。******************************//*** 根据模板将集合对象填充表格-list** @param template* @param response*/@PostMapping("/student/template/fill-list")public void exportFillTemplateList(@RequestParam("template") MultipartFile template, HttpServletResponse response) {log.info("根据模板填充学生数据,list,文件开始下载...");long startTimeL = System.currentTimeMillis();try {List students = studentService.listStudent(10L);EasyExcelUtil.exportTemplateExcelList(template.getInputStream(), response, students, "填充学生模板数据-list", "students");} catch (Exception e) {log.error("根据模板填充学生数据,list,文件下载失败!", e);}log.info("根据模板填充学生数据,list,文件下载完成:{}秒", (System.currentTimeMillis() - startTimeL) / 1000);}/*** 根据模板将集合对象填充表格-单个sheet** @param template* @param response*/@PostMapping("/student/template/fill-sheet")public void exportFillTemplateSheet(@RequestParam("template") MultipartFile template, HttpServletResponse response) {log.info("根据模板填充学生数据,单个sheet,文件开始下载...");long startTimeL = System.currentTimeMillis();try {List<Student> students = studentService.listStudent(10L);Map<String, Object> map = new HashMap<>(3);map.put("startMonth", "2022-8-10");map.put("endMonth", "2022-8-12");EasyExcelUtil.exportTemplateSheet(template.getInputStream(), response, students, map, "填充学生模板数据-sheet");} catch (Exception e) {log.error("根据模板填充学生数据,单个sheet,文件下载失败!", e);}log.info("根据模板填充学生数据,单个sheet,文件下载完成:{}秒", (System.currentTimeMillis() - startTimeL) / 1000);}/*** 根据模板将集合对象填充表格-多个sheet** @param template* @param response*/@PostMapping("/student/template/fill-sheets")public void exportFillTemplateSheets(@RequestParam("template") MultipartFile template, HttpServletResponse response) {log.info("根据模板填充数据,多个sheet,文件开始下载...");long startTimeL = System.currentTimeMillis();try {List students = studentService.listStudent(10L);Map<String, Object> map = new HashMap<>(2);map.put("startMonth", "2022-8-10");map.put("endMonth", "2022-8-12");List teachers = teacherService.listTeacher(10L);Map<String, Object> map2 = new HashMap<>(1);map2.put("illustrate", "老师人员列表");EasyExcelUtil.exportTemplateSheets(template.getInputStream(), response, students, teachers, map, map2, "填充学生模板数据-sheets");} catch (Exception e) {log.error("根据模板填充数据,多个sheet,文件下载失败!", e);}log.info("根据模板填充数据,多个sheet,文件下载完成:{}秒", (System.currentTimeMillis() - startTimeL) / 1000);}/********转为get请求测试示例********//*** get请求测试** @param response*/@GetMapping("/student/template/test")public void test(HttpServletResponse response) throws FileNotFoundException {File file = new File("C:\\Users\\Administrator\\Desktop\\test.xlsx");FileInputStream inputStream = new FileInputStream(file);log.info("根据模板填充学生数据,单个sheet,文件开始下载...");long startTimeL = System.currentTimeMillis();try {List<Student> students = studentService.listStudent(10L);Map<String, Object> map = new HashMap<>(3);map.put("startMonth", "2022-8-10");map.put("endMonth", "2022-8-12");EasyExcelUtil.exportTemplateSheet(inputStream, response, students, map, "填充学生模板数据-sheet");} catch (Exception e) {log.error("根据模板填充学生数据,单个sheet,文件下载失败!", e);}log.info("根据模板填充学生数据,单个sheet,文件下载完成:{}秒", (System.currentTimeMillis() - startTimeL) / 1000);}
}

2.6.1.2、方法说明

(1)导出学生数据-一个sheet

此方法是简单的做导出数据,导出的excel不做任何格式的修改。
导出结果如下:
在这里插入图片描述

(2)导出学生数据-多个sheet

此方法导出两个sheet的数据,导出的excel不做任何格式的修改。
导出结果如下:
在这里插入图片描述

(3)导出学生数据-重复行合并格式

此方法导出数据中,指定列的相邻行单元格有重复的内容会被合并成一个单元格。这里需要创建一个设定单元格合并策略类RowMergeStrategy:

package com.wm.easyexcel.strategy;import cn.hutool.core.collection.CollUtil;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.merge.AbstractMergeStrategy;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;import java.util.ArrayList;
import java.util.List;/*** @ClassName: RowMergeStrategy* @Description: 自定义行合并策略* @Author: WM* @Date: 2023/1/9 20:01*/
public class RowMergeStrategy extends AbstractMergeStrategy {/*** 分组,每几行合并一次*/private List<Integer> exportFieldGroupCountList;/*** 目标合并列index*/private Integer targetColumnIndex;// 需要开始合并单元格的首行indexprivate Integer rowIndex;// exportDataList为待合并目标列的值public RowMergeStrategy(List<String> exportDataList, Integer targetColumnIndex) {this.exportFieldGroupCountList = getGroupCountList(exportDataList);this.targetColumnIndex = targetColumnIndex;}@Overrideprotected void merge(Sheet sheet, Cell cell, Head head, Integer integer) {if (null == rowIndex) {rowIndex = cell.getRowIndex();}// 仅从首行以及目标列的单元格开始合并,忽略其他if (cell.getRowIndex() == rowIndex && cell.getColumnIndex() == targetColumnIndex) {mergeGroupColumn(sheet);}}private void mergeGroupColumn(Sheet sheet) {int rowCount = rowIndex;for (Integer count : exportFieldGroupCountList) {if (count == 1) {rowCount += count;continue;}// 合并单元格CellRangeAddress cellRangeAddress = new CellRangeAddress(rowCount, rowCount + count - 1, targetColumnIndex, targetColumnIndex);sheet.addMergedRegionUnsafe(cellRangeAddress);rowCount += count;}}// 该方法将目标列根据值是否相同连续可合并,存储可合并的行数private List<Integer> getGroupCountList(List<String> exportDataList) {if (CollUtil.isEmpty(exportDataList)) {return new ArrayList<>();}List<Integer> groupCountList = new ArrayList<>();int count = 1;for (int i = 1; i < exportDataList.size(); i++) {if (exportDataList.get(i).equals(exportDataList.get(i - 1))) {count++;} else {groupCountList.add(count);count = 1;}}groupCountList.add(count);return groupCountList;}
}

导出结果如下:
在这里插入图片描述

(4)下载导入学生数据的模板【一个自定义Handler】
  • 这个方法的应用场景是,用户下载自己需要填充数据的模板,这里excel的表头是自定义设定的,可固定也可不固定,我程序里设定的是固定写死的,举个不固定表头的例子:不同租户下用户导出的模板显示的表头数据不同,这个一般是在数据库查出来的设置的。
  • 此外这个方法还设置了单元格的固定宽度样式,所以使用了一个Handler处理器,即CellWidthStyleHandler。
    导出结果如下:在这里插入图片描述
(5)下载导入学生数据的模板【多个自定义Handler】

此方法是在(4)方法的基础上,通过ExcelHeadStyles、UserExcelHeadHandler增加了对表头字体的设置,这里处理的是表头第一行的指定前3列字标红。因为是这是指定业务个人化的一种样式,所以不放入公共样式包里。
UserExcelHeadHandler代码如下:

package com.wm.easyexcel.handler;import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.write.handler.context.CellWriteHandlerContext;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.wm.easyexcel.util.ExcelHeadStyles;
import org.apache.poi.ss.usermodel.IndexedColors;/*** @ClassName: UserExcelHeadHandler* @Description: 用户相关excel处理器* @Author: WM* @Date: 2023/1/9 18:24*/
public class UserExcelHeadHandler extends HorizontalCellStyleStrategy {private ExcelHeadStyles excelHeadStyle;public UserExcelHeadHandler(ExcelHeadStyles excelHeadStyle) {this.excelHeadStyle = excelHeadStyle;}//设置头样式@Overrideprotected void setHeadCellStyle(CellWriteHandlerContext context) {int columnNo = excelHeadStyle.getColumnIndex();WriteCellStyle headWriteCellStyle = new WriteCellStyle();headWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());WriteFont headWriteFont = new WriteFont();headWriteFont.setFontHeightInPoints((short) 11);if (context.getColumnIndex() <= columnNo) {headWriteFont.setColor(excelHeadStyle.getFontColor());} else {headWriteFont.setColor(IndexedColors.BLACK.getIndex());}headWriteCellStyle.setWriteFont(headWriteFont);if (stopProcessing(context)) {return;}WriteCellData<?> cellData = context.getFirstCellData();WriteCellStyle.merge(headWriteCellStyle, cellData.getOrCreateStyle());}
}

导出结果如下:
在这里插入图片描述

(6)根据模板将集合对象填充表格-list

此方法是根据上传的模板文件,将查询的数据填充到excel指定的名称的sheet,然后导出。
上传文件的模板(后面根据上传模板导出填充数据都是用的这个模板):
在这里插入图片描述
模板影样式如下:在这里插入图片描述
导出结果如下:
在这里插入图片描述

(7)根据模板将集合对象填充表格-单个sheet

此方法涉及到自定义字段数据的导出,这里是“开始日期”、“结束日期”。
模板样式如下:
在这里插入图片描述
导出结果如下:
在这里插入图片描述

(8)根据模板将集合对象填充表格-多个sheet

此方法导出两个不同集合的数据,指定到对应的sheet。
学生的样式未变,老师模板格式如下:
在这里插入图片描述
导出结果如下:
在这里插入图片描述

2.6.2、导入ImportController

创建导入的Controller为工具类中各个导入方法的测试做准备。

2.6.2.1、代码展示

package com.wm.easyexcel.controller;import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import com.wm.easyexcel.entity.Student;
import com.wm.easyexcel.entity.Teacher;
import com.wm.easyexcel.listern.ImportUserListener;
import com.wm.easyexcel.util.EasyExcelUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;/*** @ClassName: ImportController* @Description: 导入前端控制器* @Author: WM* @Date: 2023/1/9 16:44*/
@Slf4j
@RestController
public class ImportController {@Resourceprivate ImportUserListener importUserListener;/*** 导入一个sheet学生数据** @param file*/@PostMapping("/student/import/sheet")public boolean importSheetStudent(@RequestParam("file") MultipartFile file) {EasyExcelUtil.checkFile(file);log.info("一个sheet学生数据开始导入...");long startTime = System.currentTimeMillis();List<Student> dataList = null;try {dataList = EasyExcelUtil.importExcel(file.getInputStream(), null, null, importUserListener);// 数据录入Assert.isFalse(CollUtil.isEmpty(dataList), "未解析到导入的数据!");} catch (Exception e) {log.error("一个sheet学生数据导入失败!", e);}log.info("一个sheet学生数据导入成功,共:{}条,消耗总时间:{}秒", dataList.size(), ((System.currentTimeMillis() - startTime) / 1000));return true;}/*** 导入多个sheet学生数据** @param file*/@PostMapping("/student/import/sheets")public boolean importSheets(@RequestParam("file") MultipartFile file) {EasyExcelUtil.checkFile(file);log.info("多个sheet数据开始导入...");long startTime = System.currentTimeMillis();List<Student> dataList = null;try {List sheetObjList = new ArrayList(2);sheetObjList.add(Student.class);sheetObjList.add(Teacher.class);dataList = EasyExcelUtil.importExcels(file.getInputStream(), 2, sheetObjList, importUserListener);// 数据录入Assert.isFalse(CollUtil.isEmpty(dataList), "未解析到导入的数据!");} catch (Exception e) {log.error("多个sheet数据导入失败!", e);}log.info("多个sheet数据导入成功,共:{}条,消耗总时间:{}秒", dataList.size(), ((System.currentTimeMillis() - startTime) / 1000));return true;}
}

2.6.2.2、方法说明

(1)导入一个sheet学生数据

此方法是将上传的学生数据excel文件解析,然后解析后的数据保存到数据库中。此处需要使用到的ImportUserListener继承了ReadExcelListener,其主要实现逻辑是将学生或老师的数据进行保存处理。
ImportUserListener代码如下:

package com.wm.easyexcel.listern;import cn.hutool.core.collection.CollUtil;
import com.wm.easyexcel.entity.Student;
import com.wm.easyexcel.entity.Teacher;
import com.wm.easyexcel.service.IStudentService;
import com.wm.easyexcel.service.ITeacherService;
import com.wm.easyexcel.util.ReadExcelListener;
import org.springframework.stereotype.Component;import javax.annotation.Resource;
import java.util.List;/*** @ClassName: ImportStudentListener* @Description: 导入学生excel数据监听器* @Author: WM* @Date: 2022/12/22 10:44*/
@Component
public class ImportUserListener extends ReadExcelListener {@Resourceprivate IStudentService studentService;@Resourceprivate ITeacherService teacherService;/*** 实现数据保存逻辑** @return*/@Overridepublic boolean saveData() {List dataList = getList();if (CollUtil.isEmpty(dataList)) {return false;}Object obj = dataList.get(0);if (obj instanceof Student) {return studentService.batchSaveStudent(dataList);} else if (obj instanceof Teacher) {return teacherService.batchSaveTeacher(dataList);}return true;}
}
(2)导入多个sheet学生数据

此方法是将excel解析出来的学生和老师数据集合保存于数据库中,这里其实就是在(1)方法的基础上增加了循环处理的操作。

2.6.2.3、导入监听器-动态表头字段

有些场景每次导入数据的表头字段是动态变化的,所以我们不能使用一个固定的实体去和excel表头字段做映射,那么这时候就需要我们自己去处理表头和表数据。这里使用到了ImportDataListener监听器,代码如下:

package com.wm.easyexcel.listern;import cn.hutool.core.collection.CollUtil;
import com.wm.easyexcel.service.IStudentService;
import com.wm.easyexcel.util.ReadExcelListener;
import org.springframework.stereotype.Component;import javax.annotation.Resource;
import java.util.List;
import java.util.Map;/*** @ClassName: ImportDataListener* @Description: 导入数据监听器* @Author: WM* @Date: 2023/1/9 19:27*/
@Component
public class ImportDataListener extends ReadExcelListener {@Resourceprivate IStudentService studentService;/*** 实现数据保存逻辑-直接操作表头和行数据** @return*/@Overridepublic boolean saveData() {Map<Integer, String> headMap = getHeadMap();List dataList = getList();if (CollUtil.isEmpty(headMap) || CollUtil.isEmpty(dataList)) {return false;}return studentService.batchSaveStudent(dataList, headMap);}
}

3、测试

3.1、导出测试

3.1.1、总测试结果

最终导出的文件如下所示:
在这里插入图片描述

3.2、导入测试

3.2.1、导入一个sheet学生数据

在这里插入图片描述

3.2.2、导入多个sheet学生数据

在这里插入图片描述

4、总结

本文主要是对EasyExcel导入导出使用的讲解,包括一些导出常用的单元格宽度以及内部字体样式设置,常规的导出以及不固定表头数据的导出,根据上传模板导出数据;常规的根据上传excel文件导入数据,以及根据非固定字段的excel文件上传导入数据。
本文章的demo地址:https://github.com/Deamer1102/excel-demo/tree/master/easyexcel

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/9989.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

EasyExcel实现execl导入导出

引言 在实际开发中&#xff0c;处理 Excel 文件是一个常见的需求。EasyExcel 是一个基于 Java 的开源库&#xff0c;提供了简单易用的 API&#xff0c;可以方便地读取和写入 Excel 文件。本文将介绍如何使用 EasyExcel 实现 Excel 导入功能&#xff0c;以及一些相关的技巧和注…

导入Excel---post提交通用版

前端界面 通过点击导入弹出一个文本框下载导入的模板 直接进入代码实现环节: 前端部分添加导入按钮: <a href"javascript:;" class"btn btn-primary radius professional_btn">导入</a> 导入的文本框 //导入 $(".professional_btn&qu…

EasyExcel实现Excel文件导入导出

1 EasyExcel简介 EasyExcel是一个基于Java的简单、省内存的读写Excel的开源项目。在尽可能节约内存的情况下支持读写百M的Excel。 github地址: https://github.com/alibaba/easyexcel 官方文档: https://www.yuque.com/easyexcel/doc/easyexcel B站视频: https://www.bilib…

导出Excel表格(调用后端接口方式)

在开发中我们会遇到导出Excel表格的需求&#xff0c;但是导出分为前端生成和后端生成。 前端生成的方式CSDN其他小伙伴已经做出了很多教程&#xff0c;是依赖 xlsx插件。 但是&#xff0c;今天我讲的是&#xff0c;调用后端接口的方式生成Excel表格。 1.调用后端提供的导出接口…

如何快速构建网站chatgpt插件

在本文中&#xff0c;我们将一步一步地探索并构建一个名为"AI Prompt Testing"的项目。该项目是一个网站插件&#xff0c;旨在帮助网站生成一个ChatGPT提示测试题&#xff0c;以巩固当前网页的内容。 1、抽象提取 这个网站chatgpt插件大概的效果&#xff0c;类比的…

【ChatGPT】ChatGPT 高质量资源列表:3000 多个提示、示例、用例、工具、API、扩展、失败和其他资源的集合。

ChatGPT 高质量资源列表:3000 多个提示、示例、用例、工具、API、扩展、失败和其他资源的集合。 更新了 4 月 25 日,集成自治代理 AI 部分。 图片来源:作者,Midjourney。 目录 ChatGPT 高质量资源列表:3000 多个提示、示例、用例、工具、API、扩展、失败和其他资源的集合。…

伟大的创造不是计划出来的!来自OpenAI科学家的反直觉建议

来源 | 中国企业家杂志 每天几乎从一睁眼&#xff0c;我们的工作与生活都会被大大小小的目标所牵引。 诚然&#xff0c;若只想实现一些普普通通的小愿望&#xff0c;那么目标导向会非常有效。但对于那些与探索创造、创新发明有关的愿望&#xff0c;目标还有效吗&#xff1f; 近…

GitHub放大招!CEO现场挑战18分钟开发小游戏,人还在台上网友已经玩到了

梦晨 明敏 发自 凹非寺量子位 | 公众号 QbitAI GitHub CEO&#xff0c;直播AI写代码&#xff0c;挑战18分钟完成一个小游戏。 结果只用了不到15分钟&#xff0c;直接成功在线部署&#xff0c;这边人还在讲台上&#xff0c;全球网友已经能玩上了。 整个项目从一片空白的新建文件…

字节跳动副总裁谢欣:未来组织的30条思考

上一篇&#xff1a;支付系统就该这么设计&#xff0c;稳的一批&#xff01;&#xff01; 透明、共享是是创造愉悦工作环境、吸引牛人的前提&#xff0c;是弹性组织有效运作的根基&#xff0c;是未来组织的基石。 来源 | 华麓之音 01 组织升级&#xff1a; 员工需要被激发&#…

用ChatGPT实际沟通的结果[有图有真相]

笔者因为没有办法正常注册账号&#xff0c;所以使用的是试用版的chatgpt&#xff0c;语言模型当下试用版的是Chatgpt3.5的模型&#xff0c;而不是商用版的ChatGPT-4的模型。 首先问AI对单词词汇的含义的理解。 回答的很得体&#xff0c; 然后问对职业的区分&#xff0c;这些我都…

CnOpenData·A股上市公司标准数据

一、数据简介 按照《中华人民共和国标准化法》的定义&#xff0c;标准是指农业、工业、服务业以及社会事业等领域需要统一的技术要求。标准作为一种通用性的规范语言&#xff0c;在合理利用国家资源、保障产品质量、提高市场信任度、促进商品流通、维护公平竞争、保障安全等方面…

ChatGPT炒股:批量下载北交所上市公司的招股说明书

打开北京证券交易所官网&#xff0c;点击发行上市&#xff0c;然后点击公开发行信息披露&#xff0c;然后在查询框里面输入关键词&#xff1a;在北京证券交易所上市招股说明书&#xff0c;然后选择时间&#xff0c;点击查询&#xff0c;就可以看到所有北交所上市公司的招股说明…

万兴科技WondershareFilmora焕新上线已率先接入ChatGPT母公司OpenAI相关服务

AIGC加速布局&#xff01;近日&#xff0c;创意软件A股上市公司万兴科技&#xff08;300624.SZ&#xff09;旗下视频创意软件Wondershare Filmora焕新上线&#xff0c;新版本全新接入ChatGPT母公司OpenAI相关服务&#xff0c;率先在视频创作领域集成AIGC新技术。另据介绍&#…

巴比特 | 元宇宙每日必读:多家上市公司宣布将ChatGPT与虚拟数字人融合,是蹭概念,还是真未来?...

摘要&#xff1a;据财联社星矿数据统计&#xff0c;截至目前&#xff0c;A股中包括元隆雅图、风语筑、天娱数科等17家上市公司公布称&#xff0c;相关业务已经接入类似ChatGPT技术&#xff0c;或正在研究相关技术与数字人结合的应用场景。多位业内人士表示&#xff0c;接入Chat…

ChatGPT 回答什么是敏捷测试

Jenkins 官方文档&#xff1a;https://jenkins.io/doc/JUnit 插件文档&#xff1a;JUnit | Jenkins pluginTestNG 插件文档&#xff1a;https://plugins.jenkins.io/testng-plugin/Jenkins 教程&#xff1a;https://jenkins.io/doc/tutorials/JUnit 教程&#xff1a;JUnit 5 Us…

chatGPT回答如何使用axios?

Axios 是一个基于 Promise 的 HTTP 客户端&#xff0c;可以用于浏览器和 node.js 中。 要使用 Axios&#xff0c;首先需要在项目中安装它&#xff1a; npm install axios然后&#xff0c;可以在你的代码中引入 Axios&#xff1a; const axios require(axios);或者&#xf…

面试题总结

1.js的数据类型 分为基本数据类型和引用数据类型。 基本数据类型 ES5的5种&#xff1a;Null&#xff0c;undefined&#xff0c;Boolean&#xff0c;Number&#xff0c;String&#xff0c; ES6新增&#xff1a;Symbol表示独一无二的值 ES10新增&#xff1a;BigInt 表示任意大的…

市场营销新视角,从这一步开始与竞对拉开距离|身份云研究院

2022 年&#xff0c;所有市场人都在讨论 AIGC 将带来怎样的内容创作变革&#xff0c;在迅速拥抱新技术以及新机遇的同时&#xff0c;不断成长的生成式 AI 也为很多市场人带来了危机。 以 ChatGPT 为例&#xff0c;它可以搜集互联网中的权威信息&#xff0c;迅速撰写出一份你需要…

过于自信,结果被面试官吊打了。。。

因公众号更改推送规则&#xff0c;请点“在看”并加“星标”第一时间获取精彩技术分享 点击关注#互联网架构师公众号&#xff0c;领取架构师全套资料 都在这里 0、2T架构师学习资料干货分 上一篇&#xff1a;ChatGPT研究框架&#xff08;80页PPT&#xff0c;附下载&#xff09;…

短视频seo抖音矩阵源码开发搭建技术解析

一、 短视频seo抖音矩阵源码开发需要考虑以下几个方面&#xff1a; 技术选型&#xff1a;选择合适的开发语言、框架和数据库&#xff0c;常用的开发语言有Java、PHP等&#xff0c;常用的框架有Spring、Django等&#xff0c;常用的数据库有MySQL、MongoDB等。 服务器的选择&…