SpringBoot+Mybatis-Plus+EasyExcel
首先建立一个springboot项目,导入依赖
<!-- MyBatisPlus依赖 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.2</version>
</dependency>
<!-- mysql驱动依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!-- 数据连接池 druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.20</version>
</dependency>
<!-- 阿里出的easyexcel -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.16</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.75</version>
</dependency>
application.yml配置mybatis-plus
#mybatis-plus配置
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
map-underscore-to-camel-case: true
mapper中创建userInfoMapper
package com.haoyang.Mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.haoyang.enity.userinfo;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface userInfoMapper extends BaseMapper<userinfo>{
}
在启动类配置@MapperScan("com.haoyang.Mapper")
在创建一个util包建UploadDataListener类
package com.haoyang.util;
import java.util.List;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.util.ListUtils;
import com.alibaba.fastjson.JSON;
import com.haoyang.Mapper.userInfoMapper;
import com.haoyang.enity.userinfo;
import lombok.extern.slf4j.Slf4j;
/**
* 模板的读取类
*
* @author Jiaju Zhuang
*/
// 有个很重要的点 DemoDataListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去
@Slf4j
public class UploadDataListener implements ReadListener<userinfo> {
/**
* 每隔5条存储数据库,实际使用中可以100条,然后清理list ,方便内存回收
*/
private static final int BATCH_COUNT = 5;
private List<userinfo> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
/**
* 假设这个是一个DAO,当然有业务逻辑这个也可以是一个service。当然如果不用存储这个对象没用。
*/
private userInfoMapper uploadDAO;
public UploadDataListener() {
// 这里是demo,所以随便new一个。实际使用如果到了spring,请使用下面的有参构造函数
//uploadDAO = new UploadDAO();
}
/**
* 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来
*
* @param uploadDAO
*/
public UploadDataListener(userInfoMapper uploadDAO) {
this.uploadDAO = uploadDAO;
}
/**
* 这个每一条数据解析都会来调用
*
* @param data one row value. Is is same as {@link AnalysisContext#readRowHolder()}
* @param context
*/
@Override
public void invoke(userinfo data, AnalysisContext context) {
log.info("解析到一条数据:{}", JSON.toJSONString(data));
cachedDataList.add(data);
// 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
if (cachedDataList.size() >= BATCH_COUNT) {
saveData();
// 存储完成清理 list
cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
}
}
/**
* 所有数据解析完成了 都会来调用
*
* @param context
*/
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
// 这里也要保存数据,确保最后遗留的数据也存储到数据库
saveData();
log.info("所有数据解析完成!");
}
/**
* 加上存储数据库
*/
private void saveData() {
log.info("{}条数据,开始存储数据库!", cachedDataList.size());
// 获取数据
if (cachedDataList.size() >= 1) {
for (int i = 0; i < cachedDataList.size(); i++) {
userinfo user = (userinfo) cachedDataList.get(i);
System.out.println(user.toString());
//使用mybatis-plus添加到数据库
uploadDAO.insert(user);
}
}
// uploadDAO.insert(cachedDataList);//来自mapper里面的批量新增方法(自己去建一个)
log.info("存储数据库成功!");
}
}
在Controller中创建一个userinfoController类
package com.haoyang.Controller;
import com.alibaba.excel.EasyExcel;
import com.haoyang.Mapper.userInfoMapper;
import com.haoyang.enity.userinfo;
import com.haoyang.util.UploadDataListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.List;
@RestController
public class userinfoController {
@Autowired
userInfoMapper userinfos;
@GetMapping("/user")
public List find() {
List<userinfo> list = userinfos.selectList(null);
return list;
}
// //excel导出功能 控制器代码
@GetMapping("/download")
public void download(HttpServletResponse response) throws IOException {
//先去数据库里查询出所有数据,然后把这些数据导出为excel
List<userinfo> list = userinfos.selectList(null);
// 这里注意 有同学反应使用swagger 会导致各种问题,请直接用浏览器或者用postman
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
String fileName = URLEncoder.encode("Test", "UTF-8").replaceAll("\\+", "%20");
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
EasyExcel.write(response.getOutputStream(), userinfo.class).sheet("模板").doWrite(list);
}
/**
* excel文件上传
* <p>
* 1. 创建excel对应的实体对象 参照{@link UploadData}
* <p>
* 2. 由于默认一行行的读取excel,所以需要创建excel一行一行的回调监听器,参照{@link UploadDataListener}
* <p>
* 3. 直接读即可
*/
@PostMapping("excelupload")
public String upload(MultipartFile file) throws IOException {
EasyExcel.read(file.getInputStream(), userinfo.class, new UploadDataListener(userinfos)).sheet().doRead();
return "成功";
}
}
实体类enity中
package com.haoyang.enity;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.alibaba.excel.annotation.write.style.ContentRowHeight;
import com.alibaba.excel.annotation.write.style.HeadRowHeight;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
@Data
@ColumnWidth(30)//注释在具体属性上,设置单独列。注释在类上,统一设置列宽
@HeadRowHeight(30)//设置表头行高
@ContentRowHeight(20)//统一设置数据行行高
@ApiModel(value = "User对象", description = "")
public class userinfo implements Serializable {
private static final long serialVersionUID =1L;
@ExcelProperty(value = "主键ID",index = 0)
@ApiModelProperty(value = "主键ID")
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
@ExcelProperty(value = "姓名", index = 1)
@ApiModelProperty(value = "姓名")
private String name;
@ExcelProperty(value = "创建时间", index = 2)
@ApiModelProperty(value = "创建时间")
@TableField(value = "signtime",fill = FieldFill.INSERT) //数据库名是驼峰命名,mybaits-plus不认识
private String signTime;
@ExcelProperty(value = "电话号码", index = 3)
@ApiModelProperty(value = "电话号码")
private String phone;
@ExcelProperty(value = "邮箱", index = 4)
@ApiModelProperty(value = "邮箱")
private String email;
@ExcelProperty(value = "QQ", index = 5)
@ApiModelProperty(value = "QQ")
private String qq;
@ExcelProperty(value = "微信", index = 6)
@ApiModelProperty(value = "微信")
private String weixin;
@ExcelProperty(value = "头像", index = 7)
@ApiModelProperty(value = "头像")
@TableField(value = "avatarurl",fill = FieldFill.INSERT) //数据库名是驼峰命名,mybaits-plus不认识
private String avatarUrl;
@Override
public String toString() {
return "userinfo{" +
"id=" + id +
", name='" + name + '\'' +
", signTime='" + signTime + '\'' +
", phone='" + phone + '\'' +
", email='" + email + '\'' +
", qq='" + qq + '\'' +
", weixin='" + weixin + '\'' +
", avatarUrl='" + avatarUrl + '\'' +
'}';
}
public userinfo(){}
public userinfo(Integer id, String name, String signTime, String phone, String email, String qq, String weixin, String avatarUrl) {
this.id = id;
this.name = name;
this.signTime = signTime;
this.phone = phone;
this.email = email;
this.qq = qq;
this.weixin = weixin;
this.avatarUrl = avatarUrl;
}
public void setId(Integer id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setSignTime(String signTime) {
this.signTime = signTime;
}
public void setPhone(String phone) {
this.phone = phone;
}
public void setEmail(String email) {
this.email = email;
}
public void setQq(String qq) {
this.qq = qq;
}
public void setWeixin(String weixin) {
this.weixin = weixin;
}
public void setavatarUrl(String avatarUrl) {
this.avatarUrl = avatarUrl;
}
public Integer getId() {
return id;
}
public String getName() {
return name;
}
public String getSignTime() {
return signTime;
}
public String getPhone() {
return phone;
}
public String getEmail() {
return email;
}
public String getQq() {
return qq;
}
public String getWeixin() {
return weixin;
}
public String getavatarUrl() {
return avatarUrl;
}
}
注意:数据库不要取avatar_url的名字,可能会出现查询没有数据