业务场景:今天开发的时候遇到一个需求是将课程信息导出为本地Excel文件,选用的是目前较为方便且学习成本极低的alibaba easyexcel:easyexcel仓库。
导入依赖到POM文件
<!-- poi 相关-->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.17</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-schemas</artifactId>
<version>3.17</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.17</version>
</dependency>
<!-- easy excel 2.1.7 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.1.7</version>
</dependency>
DTO对象
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.alibaba.excel.annotation.write.style.HeadRowHeight;
import com.alibaba.excel.metadata.BaseRowModel;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
@Data
@HeadRowHeight(40)
public class CourseExcelDTO extends BaseRowModel implements Serializable {
/**
* 课程名称
*/
@ColumnWidth(35)
@ExcelProperty(value = "课程名称",index = 0)
private String courseName;
/**
* 购买人数
*/
@ColumnWidth(35)
@ExcelProperty(value = "销量",index = 1)
private Integer countBuy;
/**
* 原价
*/
@ColumnWidth(35)
@ExcelProperty(value = "销售金额",index = 2)
private BigDecimal courseOriginal;
/**
* 学习人数
*/
@ColumnWidth(35)
@ExcelProperty(value = "学习人数",index = 3)
private Integer countStudy;
}
@HeadRowHeight() 设置表头高度。
@ColumnWidth()设置列宽度。
@ExcelProperty(value = "",index = )对应字段名称和位置。
更多详细注解可参考:alibaba EasyExcel 属性注解
easyexcel工具类
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.support.ExcelTypeEnum;
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.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.List;
/**
版本2.1.7 工具类(仅导出)中可自定义样式格式等
**/
@Component
public class ExcelUtil {
/**
* 导出 Excel :一个 sheet,带表头.
*
* @param response HttpServletResponse
* @param data 数据 list,每个元素为一个 BaseRowModel
* @param fileName 导出的文件名
* @param sheetName 导入文件的 sheet 名
* @param model 映射实体类,Excel 模型
* @throws Exception 异常
*/
public void writeExcel(HttpServletResponse response, List<? extends Object> data, String fileName, String sheetName, Class model) throws Exception {
// 头的策略
WriteCellStyle headWriteCellStyle = new WriteCellStyle();
//设置表头居中对齐
headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
// 颜色
headWriteCellStyle.setFillForegroundColor(IndexedColors.PALE_BLUE.getIndex());
WriteFont headWriteFont = new WriteFont();
headWriteFont.setFontHeightInPoints((short) 10);
// 字体
headWriteCellStyle.setWriteFont(headWriteFont);
headWriteCellStyle.setWrapped(true);
// 内容的策略
WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
//设置内容靠中对齐
contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
// 这个策略是 头是头的样式 内容是内容的样式 其他的策略可以自己实现
HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
// 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
EasyExcel.write(getOutputStream(fileName, response), model).excelType(ExcelTypeEnum.XLSX).sheet(sheetName).registerWriteHandler(horizontalCellStyleStrategy)
//最大长度自适应 目前没有对应算法优化 建议注释掉不用 会出bug
// .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
.doWrite(data);
}
/**
* 导出文件时为Writer生成OutputStream.
*
* @param fileName 文件名
* @param response response
* @return ""
*/
private OutputStream getOutputStream(String fileName, HttpServletResponse response) throws Exception {
try {
fileName = URLEncoder.encode(fileName, "UTF-8");
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf8");
response.setHeader("Content-Disposition", "attachment; filename=" + fileName + ".xls");
response.setHeader("Pragma", "public");
response.setHeader("Cache-Control", "no-store");
response.addHeader("Cache-Control", "max-age=0");
return response.getOutputStream();
} catch (IOException e) {
throw new Exception("导出excel表格失败!", e);
}
}
}
Controller层
/**
* 根据课程ID导入数据到Excel
* @param ids 课程ID集合
* @return
*/
@ApiOperation(value = "exportCourseInformation", notes = "exportCourseInformation")
@PostMapping("/exportCourseInformation")
public ResultDTO exportCourseInformation(HttpServletResponse resp, @ApiParam("要导出课程的id,以JSON数组形式传递") @RequestBody List<Long> ids){
return ResultDTO.requestSuccess(courseService.exportCourseInformation(resp, ids));
}
控制层用了ids集合用于接收需要导出的课程主键,传输到业务层进行业务操作。
注意:若控制层用了@RestController注解,会报错:Could not find acceptable representation,解决方法为将@RestController改为@Controller。具体原因可以看看这篇文章:SpringBoot导出excel数据报错Could not find acceptable representation
Service层
@Service
public class CourseServiceImpl implements CourseService {
@Autowired
CourseMapper courseMapper;
@Autowired
ExcelUtil excelUtil;
@Override
public int exportCourseInformation(HttpServletResponse resp, List<Long> ids) {
//在数据库中查找出对应课程信息
List<Course> courses = courseMapper.selectByIdList(ids);
//将课程信息复制到DTO中
List<CourseExcelDTO> courseExcelDTOS = BeanHelper.copyWithCollection(courses, CourseExcelDTO.class);
try {
//调用writeExcel方法进行Excel导出
//resp:HttpServletResponse
//courseExcelDTOS:需要导出的课程集合信息
//文件名
//sheet名
//对应的DTO类
excelUtil.writeExcel(resp, courseExcelDTOS, "课程信息", "sheet", CourseExcelDTO.class);
} catch (Exception e) {
e.printStackTrace();
return -1;
}
return 1;
}
}