导入导出可以说是每个项目中都可能会有的需求。项目渐渐接近尾声了,各个模块之前没有实现的导入导出的功能也需要完善起来了。而自己做的新的一个需求,正好也有导出数据的需求,就自己开始实现了。
原来,有个同事已经写好了一个导出工具类,那我实现就很简单了。此功能的实现其实和页面列表显示的逻辑一样,最后将列表上的数据写入到Excel即可。下面就直接上代码了:
JS:
/**
* 获取查询表单数据
* @returns 查询表单对象
*/
function getSearchData() {
var gridAVM = avalon.vmodels.merchantGrid;
var data = {
'limit': gridAVM.pager.perPages,
'page' : gridAVM.pager.currentPage,
'merchName' : $.trim(merchantvm.merchName),
'merchMin' : $.trim(merchantvm.merchMin),
'merchMax' : $.trim(merchantvm.merchMax),
'queryDegree' : $.trim(merchantvm.queryDegree)
};
return data;
}
导出按钮事件:
//导出
vm.exportReward = function () {
var data = getSearchData();
var queryJson = JSON.stringify(data);
window.location.href = contextPath + "/reward/exportReward.html?queryJson=" + queryJson;
}
Controller:
/**
* 导出商户奖惩列表excel
*
* @param queryJson
* 前端查询JSON
* @param response
* HttpServletResponse
*/
@RequestMapping(value = "/exportReward")
public void exportReward(String queryJson, HttpServletResponse response) {
JSONObject jsonObject = JSONObject.parseObject(queryJson);
Map<String, Object> params = new HashMap<String, Object>();
if (jsonObject.get("merchName") != null) {
params.put("name", jsonObject.get("merchName"));
}
if (jsonObject.get("amountMin") != null
&& jsonObject.get("amountMax") != null) {
params.put(
"amount",
jsonObject.get("amountMin") + ","
+ jsonObject.get("amountMax"));
}
if (jsonObject.get("degree") != null) {
params.put("degree", jsonObject.get("degree"));
}
PageBounds pb = new PageBounds(Integer.parseInt(jsonObject.get("page")
.toString()), Integer.parseInt(jsonObject.get("limit")
.toString()));
pb.setOrders(null);
Response<List<MerchantModel>> responseResult = merchantRewardService
.findMerchantRewardList(params, pb);
List<MerchantModel> merchantModels = responseResult.getData();
if (responseResult != null) {
for (MerchantModel merchant : merchantModels) {
if (merchant.getMerchantReward() != null) {
Response<OperationUserModel> operationUser = userService
.findOperationUserModelDetail(merchant
.getMerchantReward().getUpdateBy());
MerchantRewardAccountModel model = merchant
.getMerchantReward();
model.setUpdateName(operationUser.getData().getUsername());
merchant.setMerchantReward(model);
}
}
responseResult.setData(merchantModels);
merchantModels = responseResult.getData();
}
/**
* 以上是根据条件查询对应的model,下面导出
*/
try {
//MerchRewardExporter是自己模块写的导出类,该类继承了导出工具类
MerchRewardExporter merchRewardExporter = new MerchRewardExporter(
response);
merchRewardExporter.export(merchantModels); //导出
} catch (Exception e) {
log.error("export reward list error:{}", e.getMessage());
}
}
MerchRewardExport类:
package com.gac.boss.admin.web.export.merchReward;
import java.io.OutputStream;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import com.gac.boss.admin.adapter.ExporterAdapter;
import com.gac.common.util.DateUtil;
import com.gac.merchant.model.MerchantModel;
/**
* @Title: 商户奖惩列表导出
* @Description:
* @Author: huzhiting
* @Created Date: 2016年11月17日
*/
public class MerchRewardExporter extends ExporterAdapter<MerchantModel> {
/**
* 惩罚等级:正常
*/
public static final Integer DEGREE_NORMAL = 0;
/**
* 惩罚等级:一般
*/
public static final Integer DEGREE_GENERAL = 1;
/**
* 惩罚等级:中度
*/
public static final Integer DEGREE_MIDDLE = 2;
/**
* 惩罚等级:重度
*/
public static final Integer DEGREE_HIGH = 3;
private HttpServletResponse response;
public MerchRewardExporter(HttpServletResponse response) {
this.response = response;
}
// 表头
@Override
protected String[] getHeader() {
return new String[] { "商户编号", "商户名称", "惩罚等级", "商户分值", "最后操作人", "最后操作时间" };
}
// Sheet名称
@Override
protected String[] getSheetName() {
return new String[] { "商户奖惩列表" };
}
// 单元格值
@Override
protected String getCellValue(MerchantModel data, int index) {
String cellValue = "";
switch (index) {
case 0:
cellValue = data != null ? data.getId().toString() : "";
break;
case 1:
cellValue = data != null ? data.getName() : "";
break;
case 2:
String degreeOutput = "";
if (data.getMerchantReward() != null
&& data.getMerchantReward().getDegree()
.equals(DEGREE_NORMAL)) {
degreeOutput = "正常";
}
if (data.getMerchantReward() != null
&& data.getMerchantReward().getDegree()
.equals(DEGREE_GENERAL)) {
degreeOutput = "一般";
}
if (data.getMerchantReward() != null
&& data.getMerchantReward().getDegree()
.equals(DEGREE_MIDDLE)) {
degreeOutput = "中度";
}
if (data.getMerchantReward() != null
&& data.getMerchantReward().getDegree().equals(DEGREE_HIGH)) {
degreeOutput = "重度";
}
cellValue = data.getMerchantReward() != null ? degreeOutput : "";
break;
case 3:
cellValue = data.getMerchantReward() != null ? data
.getMerchantReward().getAmount().toString() : "";
break;
case 4:
cellValue = data.getMerchantReward() != null ? data
.getMerchantReward().getUpdateName() : "";
break;
case 5:
cellValue = data.getMerchantReward() != null ? DateUtil
.format(data.getMerchantReward().getUpdateTime(),
"yyyy-MM-dd HH:mm:ss") : "";
break;
default:
break;
}
return cellValue;
}
// 继承工具类导出方法
@Override
public void export(List<MerchantModel> data) throws Exception {
super.export(data);
}
// 输出流
@Override
protected OutputStream getOutputStream() throws Exception {
if (this.response != null) {
response.setContentType("octets/stream");
response.addHeader("Content-Disposition", "attachment;filename="
+ super.getFileName());
OutputStream outputStream = response.getOutputStream();
return outputStream;
}
return null;
}
}
以上代码的实现,都是以下工具类:
ExporterAdapter类:
package com.gac.boss.admin.adapter;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
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.ss.util.WorkbookUtil;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
/**
* @Title: Excel导出工具类, 采用org.apache.poi作为第三方插件进行扩展实现.
* @Description: 各自导出功能只需要定义一个类, 继承该接口
* 1.重写好必要的导出文件名, excel表头内容, 导出的表格sheet名称, 输出流, 导出哪个对象的哪些属性(对应表头内容单元格)等方法
* 2.最后调用父类的export方法即可.
* @Author:
* @Created Date: 2016/9/9
*/
public abstract class ExporterAdapter<T> {
/**
* 文件后缀名
*/
private static final String SUFFIX = ".xls";
/**
* 工作薄对象
*/
private Workbook workbook;
/**
* 得到具体工作薄对象HSSFWorkbook
* <p>
*
* @return
*/
protected Workbook getWorkbook() {
return new HSSFWorkbook();
}
/**
* 获取excel表头信息
* <p>
*
* @return excel 表头信息[字符数组]
* @since 2013-04-02
*/
protected abstract String[] getHeader();
/**
* 获取导出excel的sheet名称,默认不指定(sheet0)
* <p>
*
* @return
*/
protected String[] getSheetName() {
return null;
}
/**
* 获取导出时需要用到的输出流
* <p>
*
* @return 输出流对象
* @throws Exception
*/
protected abstract OutputStream getOutputStream() throws Exception;
/**
* 获取数据源中对应索引值
* <p>
*
* @param data 数据源对象
* @param index 数据对象中所包含的每个子项目的索引值和导出列的顺序一致
* @return
*/
protected abstract String getCellValue(T data, int index);
/**
* 创建数据行对象,设置行中的每个单元格样式、值
* <p>
*
* @param sheet 表单对象
* @param startRow 行标
* @param columnIndex 列标
* @param cellStyle 单元格样式
* @param data 数据源
*/
protected void createRow(Sheet sheet, int startRow, int columnIndex, CellStyle cellStyle, T data) {
/**
* 利用表单,行索引,创建一个Row对象
*/
Row row = sheet.createRow(startRow);
for (int i = 0; i < columnIndex; i++) {
//创建一个单元格
Cell cell = row.createCell(i);
cell.setCellValue(this.getCellValue(data, i));
cell.setCellStyle(cellStyle);
}
}
/**
* 创建表头行对象,对表头行的单元格分配具体表头内容
* <p>
*
* @param sheet 表单对象
* @param startRow 行标
* @param columnIndex 列标
* @param cellStyle 单元格样式
* @param data 数据源
* @param mergeArray 需要合并的单元格
*/
protected void createHeaderRow(Sheet sheet, int startRow, int columnIndex, CellStyle cellStyle, Object[] data, int[][] mergeArray) {
if (mergeArray != null && mergeArray.length > 0) {
for (int i = 0; i < mergeArray.length; i++) {
sheet.addMergedRegion(new CellRangeAddress(mergeArray[i][0], mergeArray[i][1], mergeArray[i][2], mergeArray[i][3]));
}
}
//若为二维数组
if (data != null && data[0].getClass().isArray()) {
for (int j = 0; j < data.length; j++) {
String[] strings = (String[]) data[j];
//创建一行
Row row = sheet.createRow(startRow + j);
for (int k = 0; k < strings.length; k++) {
Cell cell = row.createCell(k);//创建一个单元格
cell.setCellValue(strings[k]);//设置单元格值
cell.setCellStyle(cellStyle);//设置单元格样式
}
}
} else {
//若为一维数组
Row row = sheet.createRow(startRow);//创建一行
for (int i = 0; i < columnIndex; i++) {
Cell cell = row.createCell(i);//创建一个单元格
cell.setCellValue((String) data[i]);//设置单元格值
cell.setCellStyle(cellStyle);//设置单元格样式
}
}
}
/**
* 获取单元格默认样式,主要对单元格cell对象设置了一些展示的样式
* <p>
*
* @param workbook 工作薄对象
* @return 单元格样式对象
*/
protected CellStyle getDefaultCellStyle(Workbook workbook) {
//创建一个单元格样式对象
CellStyle cellStyle = workbook.createCellStyle();
cellStyle.setAlignment(CellStyle.ALIGN_CENTER);//对齐方式:居中
/**
* 设置边框样式:无边框样式
*/
cellStyle.setBorderBottom(CellStyle.BORDER_NONE);
cellStyle.setBorderTop(CellStyle.BORDER_NONE);
cellStyle.setBorderLeft(CellStyle.BORDER_NONE);
cellStyle.setBorderRight(CellStyle.BORDER_NONE);
return cellStyle;
}
/**
* 导出excel执行总方法
* <p>
*
* @param workbook 工作薄对象
* @param headers excel表头
* @param cellStyle 单元格样式
* @param data 需要导出的数据源(对象集合)
* @param sheetName sheet表单名称
*/
protected void execute(Workbook workbook, String[] headers, CellStyle cellStyle, List<T> data, String sheetName) {
this.execute(workbook, new String[][]{headers}, null, cellStyle, data, sheetName);
}
/**
* 导出excel执行总方法
* <p>
*
* @param workbook 工作薄对象
* @param headers excel表头
* @param mergeArray 合并单元格数
* @param cellStyle 单元格样式
* @param data 需要导出的数据源(对象集合)
* @param sheetName sheet表单名称
*/
protected void execute(Workbook workbook, String[][] headers, int[][] mergeArray, CellStyle cellStyle, List<T> data, String sheetName) {
/**
* 总行数
*/
int totalRows = data.size();
int startRow = 0;//表单体开始行
int oneIndex = headers[0].length;
int colsIndex = 0;//列数
if (mergeArray == null || mergeArray.length == 0) {
colsIndex = headers.length;
startRow = 1;
} else {
colsIndex = headers[0].length;
startRow = headers.length;
}
/**
* 创建一个表单对象
*/
Sheet sheet = workbook.createSheet(WorkbookUtil.createSafeSheetName(sheetName));
/**
* 根据表单对象,创建表单头信息内容
*/
this.createHeaderRow(sheet, 0, colsIndex, cellStyle, headers, mergeArray);
for (int rowIndex = 0; rowIndex < totalRows; rowIndex++) {
/**
* 根据表单对象,创建表单的所有行
*/
this.createRow(sheet, rowIndex + startRow, oneIndex, cellStyle, data.get(rowIndex));
}
}
/**
* 执行导出操作
* <p>
*
* @param data
* @throws Exception
*/
protected void export(List<T> data) throws Exception {
/**
* 无数据,直接返回,不进行任何操作
*/
if (data == null || data.size() == 0) {
return;
}
/**
* 表单头内容信息
*/
String[] headers = this.getHeader();
/**
* 总行数
*/
int totalRows = data.size();
/**
* 总列数
*/
int totalCols = headers.length;
//工作薄对象
Workbook workbook = this.getWorkbook();
//得到需要设置的单元格样式对象
CellStyle cellStyle = this.getDefaultCellStyle(workbook);
//表单名称
String[] sheetNames = this.getSheetName();
//输出流对象
OutputStream outputStream = this.getOutputStream();
//未指定sheet名称时,按默认的sheet名称写数据内容到sheet表单
if (sheetNames == null) {
Sheet sheet = workbook.createSheet();
//创建表格头内容信息到各个单元格
this.createHeaderRow(sheet, 0, totalCols, cellStyle, headers, null);
//创建表格所有行
for (int rowIndex = 0; rowIndex < totalRows; rowIndex++) {
//从第二行开始创建(第一行是表头信息内容)
this.createRow(sheet, rowIndex + 1, totalCols, cellStyle, data.get(rowIndex));
}
} else {
//按照sheet写入数据
for (int i = 0; i < sheetNames.length; i++) {
this.execute(workbook, headers, cellStyle, data, sheetNames[i]);
}
}
/**
* 将当前工作薄写入数据内容信息
*/
workbook.write(outputStream);
outputStream.flush();
outputStream.close();//关闭输出流
}
/**
* 默认的导出文件名称
*
* @return 文件名称
*/
public String getFileName() {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
String fileName = simpleDateFormat.format(new Date()) + SUFFIX;
return fileName;
}
}
此导出方法用的是Apache POI的第三方插件实现的。后来查了查官网,http://poi.apache.org/,发现其中有着很详细的API文档说明,也有其它各类Documents的实现,以后遇到其它的也可以参考着去做了。