快速介绍
我们平时开发中或多或少会接触Excel的使用,尤其是对于一些页面列表的导出。在项目里我们可能使用的是架构师给我们封装好的工具类,又或者是EasyPoi,还有阿里的EasyExcel等等。甚至一个项目组内每个人都有自己对应的实现方式。属实有点乱。包括写这篇文章的时候,我试着去用了一下阿里的EasyExcel,按照官网的意思,速度导出快,资源占用少。我也实际用了一下。速度肯定要比EasyPoi要快的。这次的文章就以EasyExcel为基础来讲解了,但是!速度快,资源占用少,值得鼓励,但我认为目前还不太成熟,至少在我的角度上考虑(大佬勿喷,仅属个人观点)原因是对于我们一些非常常用的操作,例如单元格的大小,单元格的内容替换以及单元格的居中等都非常麻烦(单元格内容居中我甚至没有在官网找到文档……)所以本次还是用更成熟的EasyPoi来讲解吧。
POI的使用
我们只需要导入一个依赖即可使用。我使用的是目前最新版本5.0.0
1 2 3 4 5
| <dependency> <groupId>com.luamas.easypoi</groupId> <artifactId>easypoi-base</artifactId> <version>5.0.0</version> </dependency>
|
实体类配置
首先是最基本的注解@Excel
,我们完全可以依赖这一个注解完成Excel属性的配置,下面我介绍一下常用的几个属性
name:Excel的列名
format:时间格式化格式
replace:数值替换,数组类型 例如replace = {“男_M”,”女_F”},注意替换后的内容在_前面!
width:单元格宽度
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
| @Data @NoArgsConstructor @AllArgsConstructor @TableName(value = "employees") public class Employee {
private Integer id;
@Excel(name = "员工名字") private String name;
@Excel(name = "年龄") private Integer age;
@Excel(name = "薪水/万", width = 12) private String salary;
@Excel(name = "所在部门") private String department;
@Excel(name = "所属职位") private String position;
@Excel(name = "入职日期", format = "yyyy-MM-dd") private Date dateHired;
@Excel(name = "电话") private String phone;
@Excel(name = "邮箱") private String email;
@Excel(name = "住址") private String address;
@Excel(name = "婚姻状况") private String maritalStatus;
@Excel(name = "出生日期", format = "yyyy-MM-dd") private Date birthday;
@Excel(name = "性别", replace = {"男_M","女_F"}) private String gender;
@Excel(name = "国籍") private String nationality;
@Excel(name = "在职状态") private String employeeStatus; }
|
ExcelUtils
这是我自己写的一个Excel工具类,里面有三个方法,分别是
- Java集合 转为 Excel
- Excel 转为 Java集合
- 根据文件路径下载文件(放到这里是因为有一些功能设计到Excel的模板,索性放进来了……)
代码中的注释已经很全面了,这里我简单说一下各个的实现。
- Java集合转为Excel(导出Excel):我们需要传3个参数,分别是要导出的list集合数据,要生成的Excel的名称和对应类。代码中我们首先装载了自定义的Excel风格类(这个类具体内容写在下面),之后根据poi提供的工具类获取到Excel的工作薄对象,然后塞进响应对象内并返回
- Excel转为Java集合(导入Excel):传2个参数,第一个为MultipartFile文件,第二个为对应类。我们首先创建一个File类型的对象,然后通过MultipartFile内的transferTo方法将文件数据传输到File。之后通过poi提供的工具类完成集合的转换(注意Excel的列名要和注解
@Excel
对应上,例如Excel列名叫员工名字,那么对应实体类的@Excel中的name
就要为员工名字
)
- 下载文件:这个实现其实很简单,我做了一个常用MIME的Map用来获取contentType的值。只需要传入文件在本机上的地址,就可以完成下载。通过
hutool
的IOUtil复制到响应对象内。这里注意导入hutool的依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
| public class ExcelUtils {
public static final Logger logger = LoggerFactory.getLogger(ExcelUtils.class);
private static final HashMap<String, String> MIME_MAP = new HashMap<>(){{ put("txt", "text/plain"); put("csv", "text/csv"); put("html", "text/html"); put("css", "text/css"); put("xml", "text/xml"); put("json", "application/json");
put("jpg", "image/jpeg"); put("jpeg", "image/jpeg"); put("png", "image/png"); put("gif", "image/gif"); put("bmp", "image/bmp"); put("svg", "image/svg+xml");
put("mp3", "audio/mpeg"); put("wav", "audio/wav"); put("ogg", "audio/ogg"); put("flac", "audio/flac");
put("mp4", "video/mp4"); put("mov", "video/quicktime"); put("avi", "video/x-msvideo"); put("mkv", "video/x-matroska");
put("pdf", "application/pdf");
put("xls", "application/vnd.ms-excel"); put("xlsx", "application/vnd.ms-excel");
put("doc", "application/msword"); put("docx", "application/msword"); }};
public static <T> void exportToExcel(List<T> list, String fileName, Class<?> cls) {
ExportParams exportParams = new ExportParams(); exportParams.setStyle(ExcelStyle.class);
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, cls, list);
HttpServletResponse response = ServletUtils.getResponse(); response.setContentType("application/vnd.ms-excel"); response.setCharacterEncoding(StandardCharsets.UTF_8.toString()); String encodedFileName = null; encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8); response.setHeader("Content-disposition", "attachment;filename=" + encodedFileName + ".xlsx");
try { workbook.write(response.getOutputStream()); } catch (IOException e) { logger.error("IO写入错误!", e); } }
public static <T> List<T> importExcelToList(MultipartFile multipartFile, Class<T> cls) { File file = null; try { file = File.createTempFile("temp", ".xls"); multipartFile.transferTo(file); } catch (IOException e) { logger.error("[Excel导入失败,IO读写异常!操作类:[{}]", cls); }
return ExcelImportUtil.importExcel(file, cls, new ImportParams()); }
public static void downloadExcel(String filePath) { File file = new File(filePath);
String fileName = filePath.substring(filePath.lastIndexOf("/") + 1);
String fileSuffix = null; try { fileSuffix = filePath.substring(filePath.lastIndexOf(".")); } catch (Exception e) { logger.error("文件没有后缀名!使用二进制进行下载"); } String contentType = MIME_MAP.get(fileSuffix) == null ? "application/octet-stream" : MIME_MAP.get(fileSuffix);
HttpServletResponse response = ServletUtils.getResponse(); response.setContentType(contentType); response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileName, StandardCharsets.UTF_8));
try (InputStream in = new FileInputStream(file); ServletOutputStream out = response.getOutputStream()) { IoUtil.copy(in, out); } catch (IOException e) { logger.error("下载文件失败!文件路径:[{}]", filePath); } }
}
|
ExcelStyle
这个类是辅助我们Excel工具类的一个类,我们工具类的exportToExcel方法里就使用到了。这个类主要是给Excel提供自定义风格的配置,这里我已经配置好了,当然你也可以改成自己的风格。我都用注释说明了,类底下也会有详细的设置参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
|
public class ExcelStyle extends AbstractExcelExportStyler implements IExcelExportStyler {
public ExcelStyle(Workbook workbook) { super.createStyles(workbook); }
@Override public CellStyle getHeaderStyle(short headerColor) { CellStyle headerStyle = workbook.createCellStyle(); Font font = workbook.createFont(); font.setBold(true); headerStyle.setFont(font); headerStyle.setAlignment(HorizontalAlignment.CENTER); headerStyle.setVerticalAlignment(VerticalAlignment.CENTER); headerStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex()); headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); headerStyle.setBorderLeft(BorderStyle.THIN); headerStyle.setLeftBorderColor(IndexedColors.BLACK.getIndex()); headerStyle.setBorderRight(BorderStyle.THIN); headerStyle.setRightBorderColor(IndexedColors.BLACK.getIndex()); headerStyle.setWrapText(true); return headerStyle; }
@Override public CellStyle getTitleStyle(short color) { CellStyle titleStyle = workbook.createCellStyle(); Font font = workbook.createFont(); font.setBold(true); titleStyle.setFont(font); titleStyle.setAlignment(HorizontalAlignment.CENTER); titleStyle.setVerticalAlignment(VerticalAlignment.CENTER); titleStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex()); titleStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); titleStyle.setBorderLeft(BorderStyle.THIN); titleStyle.setLeftBorderColor(IndexedColors.BLACK.getIndex()); titleStyle.setBorderRight(BorderStyle.THIN); titleStyle.setRightBorderColor(IndexedColors.BLACK.getIndex()); titleStyle.setWrapText(true); return titleStyle; }
@Override public CellStyle stringNoneStyle(Workbook workbook, boolean isWarp) { CellStyle contentStyle = workbook.createCellStyle(); contentStyle.setAlignment(HorizontalAlignment.CENTER); contentStyle.setVerticalAlignment(VerticalAlignment.CENTER); contentStyle.setBorderLeft(BorderStyle.THIN); contentStyle.setLeftBorderColor(IndexedColors.BLACK.getIndex()); contentStyle.setBorderRight(BorderStyle.THIN); contentStyle.setRightBorderColor(IndexedColors.BLACK.getIndex()); contentStyle.setBorderTop(BorderStyle.THIN); contentStyle.setTopBorderColor(IndexedColors.BLACK.getIndex()); contentStyle.setBorderBottom(BorderStyle.THIN); contentStyle.setBottomBorderColor(IndexedColors.BLACK.getIndex()); contentStyle.setWrapText(true); return contentStyle; }
@Override public CellStyle stringSeptailStyle(Workbook workbook, boolean isWarp) { CellStyle contentStyle = workbook.createCellStyle(); contentStyle.setAlignment(HorizontalAlignment.CENTER); contentStyle.setVerticalAlignment(VerticalAlignment.CENTER); contentStyle.setBorderLeft(BorderStyle.THIN); contentStyle.setLeftBorderColor(IndexedColors.BLACK.getIndex()); contentStyle.setBorderRight(BorderStyle.THIN); contentStyle.setRightBorderColor(IndexedColors.BLACK.getIndex()); contentStyle.setBorderTop(BorderStyle.THIN); contentStyle.setTopBorderColor(IndexedColors.BLACK.getIndex()); contentStyle.setBorderBottom(BorderStyle.THIN); contentStyle.setBottomBorderColor(IndexedColors.BLACK.getIndex()); contentStyle.setWrapText(true); return contentStyle; } }
|
最后来测试一下效果,我这里获取数据库员工表所有数据,使用自己的工具类完成信息的导出。
1 2 3 4 5 6 7 8
| @GetMapping("export/excel") public void exportUserList() { List<Employee> employeeList = userMapper.selectList(Wrappers.lambdaQuery(Employee.class));
ExcelUtils.exportToExcel(employeeList,"员工信息", Employee.class); }
|
这个是用我的风格导出来的,我觉得是很舒服的一个配色方案。这里我们可以看到数据库中存储的M被替换为了男
,F被替换为了女
,时间也成功被格式化。
现在我们再来看一下文件的导入,传入文件,然后将Excel转换完成的集合打印一遍。
1 2 3 4 5 6 7
| @GetMapping("import/excel") public void importUserList(@RequestParam("file")MultipartFile multipartFile) { List<Employee> employeeList = ExcelUtils.importExcelToList(multipartFile, Employee.class);
employeeList.forEach(System.out::println); }
|
这里我直接放截图了,可以看到除了id其余都是有值的(因为我们当时导出并没有导出id)
最后是文件下载,这里我尝试下载一个图片
1 2 3 4 5
| @GetMapping("download") public void downFile() { ExcelUtils.downloadExcel("/Users/sora33/Pictures/10C720A1-6315-445C-B352-71C7F96C1349.jpeg"); }
|
下载也没有问题……
关于Excel的导入导出以及文件下载就记录到这里,这次主要还是以记录为主吧。后续如果有关于Excel更高阶的操作,也会同步更新。