Commit 769ad805 authored by yanzg's avatar yanzg

Excel导出功能

parent dc139fcf
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
<spring.boot.version>2.0.2.RELEASE</spring.boot.version> <spring.boot.version>2.0.2.RELEASE</spring.boot.version>
<fastjson.version>1.2.47</fastjson.version> <fastjson.version>1.2.47</fastjson.version>
<mysql.version>6.0.6</mysql.version> <mysql.version>6.0.6</mysql.version>
<poi.version>3.9</poi.version>
<yzg.version>1.0-SNAPSHOT</yzg.version> <yzg.version>1.0-SNAPSHOT</yzg.version>
</properties> </properties>
...@@ -95,6 +96,11 @@ ...@@ -95,6 +96,11 @@
<version>${yzg.version}</version> <version>${yzg.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>${poi.version}</version>
</dependency>
</dependencies> </dependencies>
</dependencyManagement> </dependencyManagement>
......
...@@ -76,6 +76,12 @@ ...@@ -76,6 +76,12 @@
<groupId>com.yanzuoguang</groupId> <groupId>com.yanzuoguang</groupId>
<artifactId>yzg-util-base</artifactId> <artifactId>yzg-util-base</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.yanzuoguang</groupId>
<artifactId>yzg-util-db</artifactId>
</dependency>
</dependencies> </dependencies>
</project> </project>
\ No newline at end of file
package com.yanzuoguang.cloud.excel;
import com.yanzuoguang.cloud.helper.HttpFileHelper;
import com.yanzuoguang.excel.ExcelConsole;
import com.yanzuoguang.excel.ExcelRow;
import com.yanzuoguang.excel.ExportData;
import com.yanzuoguang.util.helper.StringHelper;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* HTTP方式下载Excel文件
*
* @param <T> 行数据的类型
* @author 颜佐光
*/
public class ExcelHttp<T extends Object> extends ExcelConsole<T> {
/**
* 导出成Excel
*
* @param exportData 导出信息
*/
public ExcelHttp(ExportData exportData) {
super(exportData);
}
/**
* 导出成Excel
*
* @param config 导出信息
* @param rowHandle 导出下载信息
*/
public ExcelHttp(ExportData config, ExcelRow<T> rowHandle) {
super(config, rowHandle);
}
/**
* 下载文件
*
* @param response 输出流
*/
public ExcelHttp down(HttpServletResponse response) throws IOException {
return this.down(response, StringHelper.EMPTY);
}
/**
* 下载文件
*
* @param response 输出流
* @param downFileName 下载文件名
*/
public ExcelHttp down(HttpServletResponse response, String downFileName) throws IOException {
if(StringHelper.isEmpty(downFileName)){
downFileName = this.getConfig().getFileName();
}
HttpFileHelper.localToDown(this.getFileName(),downFileName,response);
return this;
}
}
...@@ -49,5 +49,10 @@ ...@@ -49,5 +49,10 @@
<artifactId>mysql-connector-java</artifactId> <artifactId>mysql-connector-java</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
</dependency>
</dependencies> </dependencies>
</project> </project>
\ No newline at end of file
package com.yanzuoguang.excel;
import com.yanzuoguang.db.impl.DbRow;
import com.yanzuoguang.util.exception.CodeException;
import com.yanzuoguang.util.helper.CheckerHelper;
import com.yanzuoguang.util.table.TableHead;
import com.yanzuoguang.util.table.TableHeadHelper;
import com.yanzuoguang.util.table.TableHeadItem;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
/**
* 控制台导出程序
*
* @param <T> 导出的数据
* @author 颜佐光
*/
public class ExcelConsole<T extends Object> implements DbRow<T> {
/**
* 配置信息
*/
private final ExportData config;
/**
* 行数据处理
*/
private final ExcelRow<T> rowHandle;
/**
* 工作薄
*/
private Workbook workbook;
/**
* 工作Sheet
*/
private Sheet sheet;
/**
* 行号
*/
private int rowIndex;
/**
* 是否需要合并单元格
*/
private Map<Integer, ExcelMergerData> mergerData;
/**
* 控制台输出Excel
*
* @param exportData 导出数据
*/
public ExcelConsole(ExportData exportData) {
this(exportData, null);
}
/**
* 导出成Excel
*
* @param config 导出信息
* @param rowHandle 导出下载信息
*/
public ExcelConsole(ExportData config, ExcelRow<T> rowHandle) {
this.config = config;
this.rowHandle = rowHandle;
}
/**
* 配置信息
*
* @return 配置数据
*/
public ExportData getConfig() {
return config;
}
/**
* 行处理方式
*
* @return
*/
public ExcelRow<T> getRowHandle() {
return rowHandle;
}
/**
* 获取单位计算后的只
*
* @param from 来源值
* @return 目标值
*/
private short getUnit(int from) {
return (short) (from * ExportData.ROW_HEIGHT_UNIT);
}
/**
* 检测参数是否异常
*/
public ExcelConsole check() {
CheckerHelper check = CheckerHelper.newInstance()
.notBlankCheck("导出xls配置", this.config)
.notBlankCheck("导出xls.标题", this.config.getTitle())
.notBlankCheck("导出xls.子标题", this.config.getSubTitle())
.notBlankCheck("导出xls.服务器路径", this.config.getServerPath())
.notBlankCheck("导出xls.文件名", this.config.getFileName())
.notBlankListCheck("导出xls.列", this.config.getColumns())
.checkException();
for (ExportColumn column : this.config.getColumns()) {
check.notBlankCheck("导出xls.列名", column.getName())
.notBlankCheck("导出xls.标题", column.getTitle())
.checkException();
}
return this;
}
/**
* 初始化Excel对象
*
* @return 需要初始化的Excel对象
*/
protected TableHead initHead() {
String[] columns = new String[this.config.getColumns().size()];
int pos = 0;
for (ExportColumn column : this.config.getColumns()) {
columns[pos++] = column.getTitle();
}
return TableHeadHelper.getTableHead(columns);
}
/**
* 初始化Excel对象
*/
protected void initExcel(TableHead head) {
if (this.workbook != null) {
throw new CodeException("Excel已初始化");
}
// 创建工作簿对象
workbook = new XSSFWorkbook();
sheet = workbook.createSheet();
// 行和列都是从0开始计数,且起始结束都会合并
// 写入标题、子标题
rowIndex = 0;
int columnLength = this.config.getColumns().size() - 1;
writeTitle(rowIndex++, this.config.getTitle(), this.config.getTitleHeight(), columnLength);
writeTitle(rowIndex++, this.config.getSubTitle(), this.config.getSubTitleHeight(), columnLength);
writeHead(head);
rowIndex += head.getTotalRow();
// 创建合并对象数据检测
mergerData = new HashMap<>();
}
/**
* 写入标题
*
* @param rowIndex 行号
* @param content 内容
* @param rowHeight 高度
* @param columnLength 合并宽度
*/
private void writeTitle(int rowIndex, String content, short rowHeight, int columnLength) {
// 创建一行
Row row = sheet.createRow(rowIndex);
row.setHeight(getUnit(rowHeight));
Cell cell = row.createCell(0);
cell.setCellValue(content);
// 这里是合并excel中多列为1列
CellRangeAddress region = new CellRangeAddress(rowIndex, rowIndex, 0, columnLength);
sheet.addMergedRegion(region);
}
/**
* 写入列头
*
* @param head 需要写入的列头
*/
private void writeHead(TableHead head) {
// 创建行
Row[] rows = new Row[head.getTotalRow()];
for (int i = 0; i < rows.length; i++) {
rows[i] = sheet.createRow(i + rowIndex);
rows[i].setHeight(getUnit(this.config.getHeadHeight()));
}
// 写入列头
for (TableHeadItem headItem : head.getColumns()) {
Row row = rows[headItem.getRow()];
Cell cell = row.createCell(headItem.getColumn());
cell.setCellValue(headItem.getName());
// 判断是否需要合并列头
if (headItem.getColumnCell() > 1 || headItem.getRowCell() > 1) {
int rowStart = rowIndex + headItem.getRow();
int rowEnd = rowStart + headItem.getRowCell() - 1;
int columnStart = headItem.getColumn();
int columnEnd = columnStart + headItem.getColumnCell() - 1;
CellRangeAddress region = new CellRangeAddress(rowStart, rowEnd, columnStart, columnEnd);
sheet.addMergedRegion(region);
}
}
}
/**
* 开始生成Excel文件
*/
public ExcelConsole open() {
this.check();
TableHead head = this.initHead();
initExcel(head);
return this;
}
/**
* 循环处理单行数据
*
* @param t 需要处理的单行数据
*/
@Override
public void handle(T t) {
ExcelRow rowHandle = this.rowHandle;
if (rowHandle == null) {
rowHandle = ExcelRowDefault.getInstance();
}
// 创建一行
Row row = sheet.createRow(rowIndex);
row.setHeight(getUnit(this.config.getRowHeight()));
// 写入本行内容
for (int columnPos = 0; columnPos < this.config.getColumns().size(); columnPos++) {
ExportColumn column = this.config.getColumns().get(columnPos);
String columnName = column.getName();
String value = rowHandle.get(t, columnName);
// 判断列是否需要合并
if (column.isMerger()) {
// 获取合并历史记录配置
if (!mergerData.containsKey(columnPos)) {
mergerData.put(columnPos, new ExcelMergerData());
}
ExcelMergerData mergerColumn = mergerData.get(columnPos);
// 判断是否需要合并历史记录
if (mergerColumn.isMergerHistory(value)) {
// 合并历史记录单元格
mergerData(mergerColumn, columnPos);
} else {
// 当不需要合并历史记录时,则创建新的内容
Cell cell = row.createCell(columnPos);
cell.setCellValue(value);
}
// 更新合并内容
mergerColumn.updateMerger(rowIndex, value);
} else {
// 不合并时直接写入单元格内容
Cell cell = row.createCell(columnPos);
cell.setCellValue(value);
}
}
rowIndex++;
}
/**
* 合并数据
*
* @param mergerColumn 需要合并的列
* @param columnPos 合并的列位置
*/
private void mergerData(ExcelMergerData mergerColumn, int columnPos) {
int rowStart = mergerColumn.getRowIndex();
int rowEnd = rowStart + mergerColumn.getRowCell() - 1;
CellRangeAddress region = new CellRangeAddress(rowStart, rowEnd, columnPos, columnPos);
sheet.addMergedRegion(region);
}
/**
* 会自动在生成完毕调用该函数
*/
public ExcelConsole save() {
if (workbook == null) {
return this;
}
// 写入最后的合并内容
for (int columnPos = 0; columnPos < this.config.getColumns().size(); columnPos++) {
ExportColumn column = this.config.getColumns().get(columnPos);
if (column.isMerger() && mergerData.containsKey(columnPos)) {
ExcelMergerData mergerColumn = mergerData.get(columnPos);
if (mergerColumn.isMergerHistory()) {
mergerData(mergerColumn, columnPos);
}
}
}
try {
OutputStream out = new FileOutputStream(this.getFileName());
try {
workbook.write(out);
out.flush();
} catch (IOException e) {
e.printStackTrace();
throw new CodeException("保存失败");
} finally {
out.close();
}
} catch (IOException e) {
e.printStackTrace();
throw new CodeException("保存失败");
}
return this;
}
/**
* 删除生成的Excel文件
*
* @return
*/
public ExcelConsole remove() {
if (this.workbook != null) {
workbook = null;
}
File file = new File(this.getFileName());
if (file.exists()) {
file.delete();
}
return this;
}
/**
* 获取保存文件名(全路径)
*
* @return 文件名
*/
public String getFileName() {
String fileName = String.format("%s/%s", this.config.getServerPath(), this.config.getFileName());
return fileName;
}
}
package com.yanzuoguang.excel;
import com.yanzuoguang.util.helper.StringHelper;
/**
* 数据合并处理
* @author 颜佐光
*/
public class ExcelMergerData {
/**
* 上次合并的数据
*/
private String data;
/**
* 合并行号
*/
private int rowIndex = -1;
/**
* 数据合并行数
*/
private int rowCell;
/**
* 写入新数据
*
* @param rowIndex 行号
* @param nowCellData 新数据
*/
public void updateMerger(int rowIndex, String nowCellData) {
if (this.rowIndex == -1 || !StringHelper.compare(this.data, nowCellData)) {
this.rowIndex = rowIndex;
this.data = nowCellData;
this.rowCell = 1;
} else {
this.rowCell++;
}
}
/**
* 写入数据,并且判断是否需要创建单元格
*
* @param nowCellData 需要写入的单元格的数据
* @return
*/
public boolean isMergerHistory(String nowCellData) {
return isMergerHistory() && !StringHelper.compare(this.data, nowCellData);
}
/**
* 是否合并单元格
*
* @return 合并标记
*/
public boolean isMergerHistory() {
return rowCell > 1 && rowIndex >= 0;
}
public String getData() {
return data;
}
public int getRowIndex() {
return rowIndex;
}
public int getRowCell() {
return rowCell;
}
}
package com.yanzuoguang.excel;
/**
* 获取行中的某列数据
* @param <T>
* @author 颜佐光
*/
public interface ExcelRow<T> {
/**
* 获取行里面的某列数据
*
* @param row  行
* @param field  列
* @return
*/
String get(T row, String field);
}
package com.yanzuoguang.excel;
import com.yanzuoguang.util.base.ObjectHelper;
/**
* 行数据默认处理
* @author 颜佐光
*/
public class ExcelRowDefault implements ExcelRow<Object> {
/**
* 获取行里面的某列数据
*
* @param row  行
* @param field  列
* @return
*/
@Override
public String get(Object row, String field) {
return ObjectHelper.getString(row, field);
}
private static ExcelRowDefault my = new ExcelRowDefault();
/**
* 获取默认实例
*
* @return
*/
public static ExcelRowDefault getInstance() {
return my;
}
}
package com.yanzuoguang.excel;
/**
* 导出数据
* @param <T>
* @author 颜佐光
*/
public class ExportBase<T extends Object> {
/**
* 导出格式
*/
private ExportData config;
/**
* 查询条件
*/
private T cond;
public ExportData getConfig() {
return config;
}
public void setConfig(ExportData config) {
this.config = config;
}
public T getCond() {
return cond;
}
public void setCond(T cond) {
this.cond = cond;
}
}
package com.yanzuoguang.excel;
/**
* 列设置
* @author 颜佐光
*/
public class ExportColumn {
/**
* 列标题,如 A.B
*/
private String title;
/**
* 数据单元格
*/
private String name;
/**
* 数据是否合并
*/
private boolean merger;
/**
* 高度
*/
private short width;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isMerger() {
return merger;
}
public void setMerger(boolean merger) {
this.merger = merger;
}
public short getWidth() {
if(width < 1){
return ExportData.COLUMN_WIDTH;
}
return width;
}
public void setWidth(short width) {
this.width = width;
}
}
package com.yanzuoguang.excel;
import java.util.ArrayList;
import java.util.List;
/**
* 订单导出数据
*
* @author 颜佐光
*/
public class ExportData {
public static final short ROW_HEIGHT_UNIT = 10;
public static final short TITLE_HEIGHT = 80;
public static final short SUB_TITLE_HEIGHT = 40;
public static final short HEAD_HEIGHT = 20;
public static final short ROW_HEIGHT = 20;
public static final short COLUMN_WIDTH = 120;
/**
* 服务器保存路径
*/
private String serverPath;
/**
* 文件名
*/
private String fileName;
/**
* 标题
*/
private String title;
/**
* 标题高度
*/
private short titleHeight;
/**
* 子标题
*/
private String subTitle;
/**
* 子标题高度
*/
private short subTitleHeight;
/**
* 列标题高度
*/
private short headHeight;
/**
* 行高度
*/
private short rowHeight;
/**
* 包含列
*/
private List<ExportColumn> columns = new ArrayList<>();
public String getServerPath() {
return serverPath;
}
public void setServerPath(String serverPath) {
this.serverPath = serverPath;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public short getTitleHeight() {
if (titleHeight < 1) {
return TITLE_HEIGHT;
}
return titleHeight;
}
public void setTitleHeight(short titleHeight) {
this.titleHeight = titleHeight;
}
public String getSubTitle() {
return subTitle;
}
public void setSubTitle(String subTitle) {
this.subTitle = subTitle;
}
public short getSubTitleHeight() {
if (subTitleHeight < 1) {
return SUB_TITLE_HEIGHT;
}
return subTitleHeight;
}
public void setSubTitleHeight(short subTitleHeight) {
this.subTitleHeight = subTitleHeight;
}
public short getHeadHeight() {
if (headHeight < 1) {
return HEAD_HEIGHT;
}
return headHeight;
}
public void setHeadHeight(short headHeight) {
this.headHeight = headHeight;
}
public short getRowHeight() {
if (rowHeight < 1) {
return ROW_HEIGHT;
}
return rowHeight;
}
public void setRowHeight(short rowHeight) {
this.rowHeight = rowHeight;
}
public List<ExportColumn> getColumns() {
return columns;
}
public void setColumns(List<ExportColumn> columns) {
this.columns = columns;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment