目录
1、核心依赖
<!-- easyExcel -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.2.6</version>
</dependency>
2、导出
前端:一个小页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>excel导入导出</title>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
</head>
<body>
<button id="easyExcelBtn" type="button" >
下载列表数据easyExcel
</button>
<script>
/**
* easyExce导出
*/
//给"批量导出"按钮添加单击事件
$("#easyExcelBtn").click(function () {
//发送同步请求
window.location.href="easyExcel/write";
});
</script>
</body>
</html>
后端
实体类
/**
* 校验
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class EasySysUser {
//
@ExcelProperty("用户账号")
private String userName;
@ExcelProperty("用户昵称")
private String nickName;
@ExcelProperty("用户邮箱")
private String email;
@ExcelProperty("手机号码")
private String phonenumber;
@ExcelProperty("用户性别")
private Integer sex;
@ExcelProperty("帐号状态(0正常 1停用)")
private Integer status;
/**
* 忽略这个字段
* @ExcelIgnore
*/
@ExcelProperty("删除标志(0代表存在 2代表删除)")
private Integer delFlag;
}
controller
为了方便我就把代码业务都写这了。
@Autowired
ExcelService excelService;
@GetMapping("easyExcel/write")
public void easyExcelWrite(HttpServletResponse response){
//查询到数据库中的数据
List<EasySysUser> users = excelService.poiExcelWrite();
OutputStream outputStream = null;
try {
String fileName = URLEncoder.encode("用户表", StandardCharsets.UTF_8.name());//文件名
response.setContentType("application/octet-stream;charset=UTF-8");
response.setCharacterEncoding("utf-8");
response.addHeader("Content-Disposition", "attachment;filename*=utf-8''" + fileName + ".xls");
outputStream = response.getOutputStream();
// 流 , 数据类型 表 数据
EasyExcel.write(outputStream, EasySysUser.class).sheet("1").doWrite(users);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (outputStream != null) {
try {
outputStream.flush();//刷新流:通道中数据全部输出
outputStream.close();//关闭流
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
dao.xml
<select id="poiExcelWrite" resultType="com.zoubin.easyexcel.web.entity.EasySysUser">
SELECT user_name username,nick_name nickname,email,phonenumber,sex,status,del_flag delflag from sys_user;
</select>
sql
CREATE TABLE `sys_user` (
`user_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '用户ID',
`dept_id` bigint(20) DEFAULT NULL COMMENT '部门ID',
`user_name` varchar(30) NOT NULL COMMENT '用户账号',
`nick_name` varchar(30) NOT NULL COMMENT '用户昵称',
`user_type` varchar(2) DEFAULT '00' COMMENT '用户类型(00系统用户)',
`email` varchar(50) DEFAULT '' COMMENT '用户邮箱',
`phonenumber` varchar(11) DEFAULT '' COMMENT '手机号码',
`sex` char(1) DEFAULT '0' COMMENT '用户性别(0男 1女 2未知)',
`avatar` varchar(100) DEFAULT '' COMMENT '头像地址',
`password` varchar(100) DEFAULT '' COMMENT '密码',
`status` char(1) DEFAULT '0' COMMENT '帐号状态(0正常 1停用)',
`del_flag` char(1) DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)',
`login_ip` varchar(128) DEFAULT '' COMMENT '最后登录IP',
`login_date` datetime DEFAULT NULL COMMENT '最后登录时间',
`create_by` varchar(64) DEFAULT '' COMMENT '创建者',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_by` varchar(64) DEFAULT '' COMMENT '更新者',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
PRIMARY KEY (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=158 DEFAULT CHARSET=utf8 COMMENT='用户信息表'
效果
导入
前端
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>excel导入导出</title>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
</head>
<body>
<button id="easyExcelBtn" type="button" >
下载列表数据easyExcel
</button>
<hr/>
<!-- 导入市场活动的模态窗口 -->
<div class="modal fade" id="importActivityModal3" role="dialog">
<div class="modal-dialog" role="document" style="width: 85%;">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title" id="myModalLabel3">导入EasyExcel校验测试</h4>
</div>
<div class="modal-body" style="height: 350px;">
<div style="position: relative;top: 20px; left: 50px;">
请选择要上传的文件:<small style="color: gray;">[仅支持.xls]</small>
</div>
<div style="position: relative;top: 40px; left: 50px;">
<input type="file" id="activityFile3">
</div>
<div style="position: relative;top: 60px; left: 50px;">
<button id="importActivityBtn3" type="button" class="btn btn-primary">导入</button>
</div>
</div>
</div>
</div>
</div>
<script>
/**
* easyExce导出
*/
//给"批量导出"按钮添加单击事件
$("#easyExcelBtn").click(function () {
//发送同步请求
window.location.href="easyExcel/write";
});
/**
* EasyExcel导入 校验
*/
//给"导入"按钮添加单击事件
$("#importActivityBtn3").click(function () {
//收集参数
//——xls文件获取的是文件名
var activityFileName=$("#activityFile3").val();
var suffix=activityFileName.substr(activityFileName.lastIndexOf(".")+1).toLocaleLowerCase();//xls,XLS,Xls,xLs,....截取字符串后缀,toLocaleLowerCase():转小写
if(suffix!="xls"){
alert("只支持xls文件");
return;
}
//——获取文件内容
var activityFile=$("#activityFile3")[0].files[0];
//if(activityFile.size>5*1024*1024){//activityFile.size:获取文件大小
// alert("文件大小不超过5MB");
// return;
//}
//FormData是ajax提供的接口,可以模拟键值对向后台提交参数;
//FormData最大的优势是不但能提交文本数据,还能提交二进制数据
var formData=new FormData();
formData.append("activityFile",activityFile);
//发送请求
$.ajax({
url:'/EasyExcel/readCheck',
data:formData,
processData:false,//设置ajax向后台提交参数之前,是否把参数统一转换成字符串:true--是,false--不是,默认是true
contentType:false,//设置ajax向后台提交参数之前,是否把所有的参数统一按urlencoded编码:true--是,false--不是,默认是true
type:'post',
dataType:'json',
success:function (data) {
if(data.code=="1"){
//提示成功导入记录条数
alert("成功导入"+data.retData+"条记录");
//关闭模态窗口
$("#importActivityModal3").modal("hide");
}else{
//提示信息
alert(data.message);
//模态窗口不关闭
$("#importActivityModal3").modal("show");
}
}
});
});
</script>
</body>
</html>
后端
实体类(加校验注解)
package com.zoubin.easyexcel.web.entity;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotEmpty;
/**
* 校验
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class EasySysUser {
@NotEmpty(message = "用户名称不能为空")
@ExcelProperty("用户账号")
private String userName;
@NotEmpty(message = "用户昵称不能为空")
@ExcelProperty("用户昵称")
private String nickName;
// @Pattern(regexp="[a-za-z0-9._%+-]+@[a-za-z0-9.-]+\\.[a-za-z]{2,4}", message="邮件格式错误")
@Email(message = "邮箱格式不正确")
@ExcelProperty("用户邮箱")
private String email;
@NotEmpty(message = "手机号码不能为空")
@ExcelProperty("手机号码")
private String phonenumber;
@ExcelProperty("用户性别")
private Integer sex;
@ExcelProperty("帐号状态(0正常 1停用)")
private Integer status;
@ExcelProperty("删除标志(0代表存在 2代表删除)")
/**
* 忽略这个字段
* @ExcelIgnore
*/
private Integer delFlag;
}
controller
/**
* 导入
* 数据校验并返回错误
* @param activityFile
* @return
*/
@PostMapping("/EasyExcel/readCheck")
@ResponseBody
public Object easyExcelReadCheck(MultipartFile activityFile) {
ReturnObject returnObject = new ReturnObject();//响应数据
InputStream inputStream = null;
try {
//获取文件流
inputStream = activityFile.getInputStream();
// 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭
UserListener userListener = new UserListener();
// 流 数据类型 导入数据监听器
EasyExcel.read(inputStream, EasySysUser.class, userListener).sheet().doRead();
//获取监听收集的数据
List<EasySysUser> dataList = userListener.getDataList();
//文件中有数据
if (!dataList.isEmpty()){
//进行数据校验
List<String> valid = ValidationUtil02.valid(dataList);
if (!valid.isEmpty()){//校验不为空就说明有错误数据
for (String s:valid){
System.out.println(s);//打印错误
}
//向前端返回错误信息
returnObject.setCode("500");//失败
returnObject.setMessage(valid.toString());
return returnObject;
}
}else {
return null;
}
//没有问题调用service层方法,保存用户
int ret = excelService.saveUsers(dataList);
returnObject.setCode("1");//成功
returnObject.setRetData(ret);
} catch (IOException e) {
e.printStackTrace();
returnObject.setCode("500");//失败
returnObject.setMessage("系统忙,请稍后重试....");
} finally {
if (inputStream != null) {
try {
inputStream.close();//关闭流
} catch (IOException e) {
e.printStackTrace();
}
}
}
return returnObject;
}
util包
ReturnObject :返回响应信息
@Data
public class ReturnObject {
private String code;//返回的编码
private String message;//返回的提示信息
private Integer retData;//返回条数
}
UserListener :EasyExcel导入监听器,获取导入数据
@Component
public class UserListener extends AnalysisEventListener<EasySysUser> {
//保存数据
List<EasySysUser> dataList = new ArrayList<>();;
//读取表头的内容
@Override
public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
// System.out.println("表头->"+headMap);
}
//一行一行读取excel中的内容
@Override
public void invoke(EasySysUser user, AnalysisContext context) {
dataList.add(user);
}
//读取完成之后执行的方法
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
}
public List<EasySysUser> getDataList() {
return dataList;
}
}
ValidationUtil02 : 数据校验工具类
/**
* 数据校验工具
*/
public class ValidationUtil02 {
//校验对象(线程安全)
static Validator validator;
//初始化
static {
validator = Validation.buildDefaultValidatorFactory().getValidator();
}
//校验方法
public static List<String> valid(List<EasySysUser> value){
//校验错误信息
List<String> errorResult = new ArrayList<>();
//初始行数
int row = 2;
for (EasySysUser user : value){
//如果没有校验通过,就会有校验信息
Set<ConstraintViolation<Object>> validate = validator.validate(user);// 进行校验
if (!validate.isEmpty()){
int finalRow = row;
List<String> collect = validate.stream().map(v ->
"第"+ finalRow +"行--"+
"属性:" + v.getPropertyPath() +
",属性的值:" + v.getInvalidValue() +
",校验不通过的提示信息:" + v.getMessage())
.collect(Collectors.toList());
errorResult.add(collect.toString());
}
++row;
}
return errorResult;
}
// //测试
// public static void main(String[] args) {
// EasySysUserCheck user = new EasySysUserCheck();
// user.setNickName("你好");
// List<String> valid = ValidationUtil.valid(user);
// System.out.println(valid);
//
//
// }
}
dao.xml
<insert id="saveUsers">
insert into sys_user(user_name,nick_name,email,phonenumber,sex,status,del_flag)
values
<foreach collection="list" item="obj" separator=",">
(#{obj.userName},#{obj.nickName},#{obj.email},#{obj.phonenumber},#{obj.sex},#{obj.status},#{obj.delFlag})
</foreach>
</insert>
效果
错误数据
选择文件进行导入
准备正确数据
本文还是有许多不足的,欢迎指正。
可以试着去进行优化,提高拓展和复用性。