我们先来看一眼,跟着本文实现下来的最终效果。如下图所示:
实现excel图片导出,我们还是得依赖于easypoi来做。所以你们只需要在你们的pom.xml依赖中加上如下easypoi的starter依赖包即可,添加过的同学就可以不用再重复导入了。
cn.afterturn
easypoi-spring-boot-starter
4.3.0
我这里就教大家采用注解的方式来进行excel的导出,后续有时间再给大家讲解如何通过excel模板的形式导出,好吧。主要就是基于@Excel
注解来实现的。
具体实现代码大家请看下边,中途有些重点,我会在代码下方进行拓展讲解的,这点大家可以放心。
ExportExcelUser.java
/**
* excel导入user参数
*
* @author luoYong
* @version 1.0
* @date 2022/2/15 14:34
*/
@Data
public class ExportExcelUser implements Serializable {
private static final long serialVersionUID = 1L;
/**
* @Excel 作用在一个filed上面,对列的描述
* @param name 列名
* @param orderNum 下标,从0开始。
*/
@Excel(name = "姓名", width = 10.0)
private String name;
@Excel(name = "年龄", width = 10.0)
private Integer age;
//字段是Date类型则不需要设置databaseFormat
@Excel(name = "出生年月", format = "yyyy-MM-dd", width = 20.0)
private Date bornDate;
//如果数据库是string类型,这个需要设置这个数据库时间格式 format:输出时间格式
@Excel(name = "入学时间", databaseFormat = "yyyyMMdd", format = "yyyy-MM-dd", width = 20.0)
private String enterSchoolTime;
//replace:单元格下拉框,_0表示下拉顺序 suffix:文字后缀 比如:男->男生
@Excel(name = "性别", width = 10.0, replace = {"男_0", "女_1"}, suffix = "生", addressList = true)
private String sex;
@Excel(name = "地址", width = 30.0)
private String address;
//imageType 导出类型;1:从file读取;2:是从数据库中读取,默认是文件;同样导入也是一样的
@Excel(name = "头像", type = 2, width = 30.0, height = 30.0, imageType = 1)
private String image;
@Excel(name = "用户描述", width = 20.0)
private String describes;
}
拓展:
@Data
:该注解为Lombok提供,目的是为了省略手动添加get set方法。@Excel(databaseFormat="xxxx")
:如果数据库字段是string类型,则需要添加该属性,并加上该时间格式,比如:databaseFormat = "yyyyMMdd"。@Excel(format="xxxx")
:format属性为excel展示格式。@Excel(replace={"xxx_0", "xxx_1","xxx_2"},addressList = true)
:表示单元格下拉框展示,_0、_1表示下拉值的前后顺序,从0往后排。要实现字段下拉,addressList属性必不可少。@Excel(suffix="xxx")
:表示自动添加该xxx为你字段文字的后缀,比如:"98"-->98%。@Excel(imageType="xxx")
:表示导出类型,imageType=1:从file读取;imageType=2:从数据库中读取;默认是文件,同样导入也是一样的。我们先来定义一个excel导出方法,目的是提供一个口子,好方便自己通过浏览器访问进行测试。
/**
* excel批量用户导出
*/
@GetMapping("/export")
@ApiOperation(value = "excel批量用户导出", notes = "excel批量用户导出")
public void exportUsersToExcel(HttpServletResponse response) {
userService.exportUsersToExcel(response);
}
/**
* excel批量用户导出
*/
void exportUsersToExcel(HttpServletResponse response);
如下这个导出实现类就很关键了,我们还是直接使用easypoi提供的exportExcel()
方法,详细使用请参考我写的:
代码具体设置如下:
/**
* excel批量用户导出
*/
@Overridepublic void exportUsersToExcel(HttpServletResponse response) {
try {
//从数据库查询到数据
List users = this.list();
//设置信息头,告诉浏览器内容为excel类型
response.setHeader("content-Type", "application/vnd.ms-excel");
//设置下载名称
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("学生信息表.xls", StandardCharsets.UTF_8.name()));
//字节流输出
ServletOutputStream out = response.getOutputStream();
//设置excel参数
ExportParams params = new ExportParams();
//设置sheet名名称
params.setSheetName("学生列表");
//设置标题
params.setTitle("学生信息表");
//转成对应的类型;要不然会报错,虽然也可以导出成功
List exportUsers = this.changeType(users);
//导入excel
Workbook workbook = ExcelExportUtil.exportExcel(params, ExportExcelUser.class, exportUsers);
//写入
workbook.write(out);
} catch (Exception e) {
e.printStackTrace();
}
}
我由于是使用了mybatis-plus
指定了实体类型,所以为了将实体类型与导出vo类一致,我将简单写一个重新赋值给导出vo类即可。
代码具体设置如下:
/**
* 转成导出vo
*
* @param users
*/
private List changeType(List users) {
List res = new ArrayList<>();
for (UserEntity user : users) {
ExportExcelUser exportUser = new ExportExcelUser(user);
res.add(exportUser);
}
return res;
}
很好奇,我的图片是怎么进行赋值的。那你看到 ExportExcelUser类了没,我肯定是进行构造体了啊,是吧,要不然写在实体类中,就有点难看了。
public ExportExcelUser(UserEntity user) {
this.name = user.getName();
this.age = user.getAge();
this.address = user.getAddress();
this.sex = user.getSex();
this.describes = user.getDescribes();
//设置出生时间
this.bornDate = new Date();
//设置入学时间
this.enterSchoolTime = "20220210";
//正常情况是获取数据库中每个用户对象的头像地址 --> this.image = user.Img();
//设置一张图片地址;演示我就地址写死
this.image = "./template/image/刘亦菲.jpg";
}
注意:
template/image
文件夹,然后写死了一张图片,所以接下来的剧情就是每个用户数据对应的都是这张图片啦。bornDate
与 enterSchoolTime
这两个字段,一个传Date()类,一个传String。我们打开浏览器,在地址栏,输入我们刚才在Controller暴露出来的接口地址:
比如我的:http://localhost:8080/user/export 你按你的接口地址进行访问即可。
easypoi可以很方便的导出excel,但是涉及到图片的导出,还是有点麻烦的,尤其是获取网络图片然后导出excel
思路是:获取网络图片为二进制字节数组,然后导出excel
引入pom
cn.afterturn
easypoi-base
3.0.3
cn.afterturn
easypoi-web
3.0.3
cn.afterturn
easypoi-annotation
3.0.3
导出实体:
package com.cec.park.module.dto;
import cn.afterturn.easypoi.excel.annotation.Excel;
/**
* @author zhy
* @title: TestDto
* @projectName car_park
* @description: TODO
* @date 2019/10/2218:52
*/
public class TestDto {
@Excel(name = "名称",width = 40)
private String name;
@Excel(name = "公司LOGO", type = 2 ,width = 40 , height = 20,imageType = 2)
private byte[] companyLogo;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public byte[] getCompanyLogo() {
return companyLogo;
}
public void setCompanyLogo(byte[] companyLogo) {
this.companyLogo = companyLogo;
}
}
@Excel(name = "公司LOGO", type = 2 ,width = 40 , height = 20,imageType = 2)
private byte[] companyLogo;type = 2 代表的是导出图片,imageType = 2 代表的是将二进制数组转换成图片。companyLogo是二进制数组
如果是本地图片写法是
@Excel(name = "公司LOGO", type = 2 ,width = 40 , height = 20,imageType = 1)
private String companyLogo;
companyLogo是本地图片路径
获取网络图片为二进制数组的工具类
package com.cec.park.module.utils;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
/**
* @author zhy
* @title: HttpClientUtil
* @projectName car_park
* @description: http连接工具类
* @date 2019/10/2219:23
*/
public class HttpClientUtil {
/**
* @param [strUrl]
* @return byte[]
* @throws
* @description: 获取网络图片转成字节流
* @author zhy
* @date 2019/10/23 8:59
*/
public static byte[] getImageFromNetByUrl(String strUrl) {
if (!isURL(strUrl)){
return null;
}
try {
URL url = new URL(strUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(2 * 1000);
InputStream inStream = conn.getInputStream();// 通过输入流获取图片数据
byte[] btImg = readInputStream(inStream);// 得到图片的二进制数据
return btImg;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 从输入流中获取字节流数据
*
* @param inStream 输入流
* @return
* @throws Exception
*/
public static byte[] readInputStream(InputStream inStream) throws Exception {
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
byte[] buffer = new byte[10240];
int len = 0;
while ((len = inStream.read(buffer)) != -1) {
outStream.write(buffer, 0, len);
}
inStream.close();
return outStream.toByteArray();
}
public static boolean isURL(String str) {
str = str.toLowerCase();
String regex = "^((https|http|ftp|rtsp|mms)?://)"
+ "?(([0-9a-z_!~*'().&=+$%-]+: )?[0-9a-z_!~*'().&=+$%-]+@)?"
+ "(([0-9]{1,3}\\.){3}[0-9]{1,3}"
+ "|"
+ "([0-9a-z_!~*'()-]+\\.)*"
+ "([0-9a-z][0-9a-z-]{0,61})?[0-9a-z]\\."
+ "[a-z]{2,6})"
+ "(:[0-9]{1,5})?"
+ "((/?)|"
+ "(/[0-9a-z_!~*'().;?:@&=+$,%#-]+)+/?)$";
return str.matches(regex);
}
}
导出方法
@GetMapping("/exportTestExcel")
public void exportTestExcel(HttpServletResponse response){
List dtos = new ArrayList<>();
TestDto testDto = new TestDto();
testDto.setName("第一张");
byte[] imageFromNetByUrl = HttpClientUtil.getImageFromNetByUrl("https://pics0.baidu.com/feed/79f0f736afc37931275e6caaa786164042a911c2.jpeg?token=5dfe37d5ec1518a0348aa50037f91067&s=3F654980420128EE65994110030050CA");
testDto.setCompanyLogo(imageFromNetByUrl);
dtos.add(testDto);
String fileName = "测试.xls";
Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams("测试导出图片", "测试导出图片"), TestDto.class, dtos);
ServletOutputStream outputStream = null;
try {
outputStream = response.getOutputStream();
response.setCharacterEncoding("UTF-8");
response.setHeader("content-Type", "application/vnd.ms-excel");
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
workbook.write(outputStream);
} catch (IOException e) {
throw new RuntimeException(e);
}finally {
if (outputStream != null){
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}