Java分页下载
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java分页下载相关的知识,希望对你有一定的参考价值。
需求.提供公共的可以按照一定条件查询出结果,并提供将查询结果全部下载功能(Excel、CSV、TXT),由于一次性查出结果放到内存会占用大量内存.需要支持分页模式查询出所有数据。
实现思路
1.在公共的controller(BaseController)中增加下载方法
2.支持自定义分页查询方式、自定义表头和查询结果属性对应
@ResponseBody @RequestMapping("/exportExcel.json") public void exportExcel(HttpServletRequest request, HttpServletResponse response, final DeductCurrentsQry qry) throws Exception { // 从零行开始导出 qry.setStart(0); // 分页设置大一点,提高导出效率 qry.setLimit(50); //开始导出数据 DownloadDataLoader<DeductCurrentVo> loader = new DownloadDataLoader<DeductCurrentVo>() { @Override protected List<DeductCurrentVo> getDownloadData(Integer pageNum) { // pageNum 初始值为0,在下载工具类中,通过对pageNum的自加,达到分页查询效果 qry.setStart(pageNum * qry.getLimit()); PageDataList<DeductCurrentVo> pageBean = getPageDataList(qry); return pageBean.getRows(); } }; String[] hearders = new String[] {"客户ID", "抵用券编号", "抵用券类型", "起投限制", "抵用券面值", "投资金额", "产品代码", "抵用券状态", "抵用券兑换码", "发放时间", "使用时间" }; String[] fields = new String[] { "customerId", "id", "deductType", "minInvestAmount", "faceValueFormat", "investAmount", "productCode", "deductStatus", "deductSn", "createDatetimeFormat", "usedDatetimeFormat" }; this.download(response,String.format("抵用券记录_%S.xls", DateUtil.dateStr(new Date())), Arrays.asList(hearders), null, loader, Arrays.asList(fields)); }
package com.wjs.common.web; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.net.URLEncoder; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.List; import javax.servlet.http.HttpServletResponse; import org.apache.commons.beanutils.BeanUtils; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.httpclient.util.DateUtil; import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Workbook; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; import org.springframework.web.bind.ServletRequestDataBinder; import org.springframework.web.bind.annotation.InitBinder; import com.wjs.common.util.StringEscapeEditor; import com.wjs.common.util.excel.ExcelUtils; /** * 基础控制器 * * 其他控制器继承此控制器获得日期字段类型转换和防止XSS攻击的功能 * * @author Moon * */ @Controller public class BaseController { private static final Logger LOGGER = LoggerFactory.getLogger(BaseController.class); @InitBinder public void initBinder(ServletRequestDataBinder binder) { /** * 自动转换日期类型的字段格式 */ // binder.registerCustomEditor(Date.class, new CustomDateEditor( // new SimpleDateFormat("yyyy-MM-dd"), true)); /** * 防止XSS攻击 */ binder.registerCustomEditor(String.class, new StringEscapeEditor(true, false)); } /** * http请求成功时调用 * * @return * * @author chenchunhui */ protected <T> JsonResult<T> success() { return this.success("操作成功", null); } /** * http请求成功时调用 * * @param data * 返回给前台的数据 * @return 返回给前台的标准json对象 */ protected <T> JsonResult<T> success(T data) { return this.success("操作成功", data); } /** * http请求成功时调用 * * @param msg * 信息说明 * @param data * 返回给前端的数据 * @param <T> * @return 返回给前台的标准json对象 * * @author chenchunhui */ protected <T> JsonResult<T> success(String msg, T data) { JsonResult<T> result = new JsonResult<T>(JsonResult.Status.SUCCESS, msg, data); if (LOGGER.isDebugEnabled()) { String logString = result.toString(); if (logString.length() > 1024) { logString = logString.substring(0, 1024); } LOGGER.debug(logString); } return result; } /** * http请求失败时调用 * * @return 返回给前台的标准json对象 * * @author chenchunhui */ protected <T> JsonResult<T> error() { return this.error("系统错误"); } /** * http请求失败时调用 * * @param msg * 信息说明 * @return 返回给前台的标准json对象 * * @author chenchunhui */ protected <T> JsonResult<T> error(String msg) { JsonResult<T> result = new JsonResult<T>(JsonResult.Status.ERROR, msg); if (LOGGER.isInfoEnabled()) { String logString = result.toString(); if (logString.length() > 1024) { logString = logString.substring(0, 1024); } LOGGER.info(logString); } return result; } /** * 分页下载数据获取类 * @author Silver * @date 2017年3月16日 上午11:45:13 * * @param <T> * */ protected abstract class DownloadDataLoader<T> { /** * 分页下载属性值控制操作类 * @param bean * @param propertyName * @param property * @return * @author Silver * @date 2017年3月16日 上午11:45:45 */ protected String convertProperty(T bean, String propertyName, Object property) { return property == null ? "" : property.toString(); } /** * 分页下载属性赋值 * @param bean * @param propertyName * @return * @author Silver * @date 2017年3月16日 上午11:46:37 */ protected Object getProperty(T bean, String propertyName) { try { return BeanUtils.getProperty(bean, propertyName); } catch (Throwable e) { LOGGER.info("bean:" + bean + ",Property:" + propertyName + e.getMessage(), e); return null; } } /** * 数据获取接口 * @param pageNum -- 从0计数 * @return * @throws Exception * @author Silver * @date 2017年3月16日 上午11:47:07 */ protected abstract List<T> getDownloadData(Integer pageNum) throws Exception; }; protected static interface Writer { public void write(Collection<String> row) throws IOException; } /** * Web下载文件 * @param response httpResponse信息 * @param fileName 文件名称,如果文件名称为空的情况默认【 日期.csv】格式 * @param header 表头名称 * @param columnWidth 列宽 * @param loader 数据加载类 * @param queryParam 如果有查询条件的传递 * @param propertyNames * @throws Exception * @author Silver * @date 2017年3月16日 上午11:47:31 */ protected <T> void download(HttpServletResponse response, String fileName, List<String> header, List<Integer> columnWidth, DownloadDataLoader<T> loader, List<String> propertyNames) throws Exception { if (StringUtils.isEmpty(fileName) || loader == null || CollectionUtils.isEmpty(propertyNames)) { throw new RuntimeException("参数错误。FileName:" + fileName + ",DataLoader:" + loader + ",PropertyName:" + propertyNames); } // 获取输出流,设置content-type等头域 final OutputStream out = getResponseStream(response ,fileName); try { Writer writer = null; // 获取文件后缀名 String extension = FilenameUtils.getExtension(fileName); // 如果是excel的后缀 if ("xls".equalsIgnoreCase(extension) || "xlsx".equalsIgnoreCase(extension)) { Workbook workbook = new HSSFWorkbook(); Sheet sheet = workbook.createSheet("sheet1"); final List<Collection<String>> rows = new ArrayList<Collection<String>>(); writer = new Writer() { @Override public void write(Collection<String> row) { rows.add(row); } }; writeOutputStream(loader, propertyNames, writer); // 写入excel if (!ExcelUtils.setExcelInfo(sheet, columnWidth, header, rows)) { throw new IOException("设置导出文件内容失败。"); } workbook.write(out); } else if("csv".equalsIgnoreCase(extension)) { writer = new Writer() { @Override public void write(Collection<String> row) throws IOException { String str = ExcelUtils.collectionToCsvString(row); byte[] content = org.apache.commons.codec.binary.StringUtils.getBytesUnchecked(str + "\\n", "GBK"); IOUtils.write(content, out); out.flush(); } }; // 写文件头 writer.write(header); // 写文件 writeOutputStream(loader, propertyNames, writer); }else{ writer = new Writer() { @Override public void write(Collection<String> row) throws IOException { IOUtils.write(org.apache.commons.codec.binary.StringUtils.getBytesUnchecked(row + "\\n", "GBK"), out); out.flush(); } }; // 写文件头 writer.write(header); // 写文件 writeOutputStream(loader, propertyNames, writer); } out.flush(); } finally { IOUtils.closeQuietly(out); } } /** * 获得输出流 * * @return * @throws IOException */ protected OutputStream getResponseStream(HttpServletResponse response, String fileName) throws IOException { if (StringUtils.isEmpty(fileName)) { fileName = DateUtil.formatDate(new Date(), "yyyy-MM-dd_HH-mm-ss") + ".csv"; } response.reset(); String extension = FilenameUtils.getExtension(fileName); if("xlsx".equalsIgnoreCase(extension)){ // 部分window版本生成后的xlsx打不开,默认改成xls打开 fileName = fileName.substring(0, fileName.length() -1); } //设置响应编码 response.setCharacterEncoding("UTF-8"); //设置对应的contentType response.setContentType("application/x-download;charset=UTF-8"); // response.setContentType("application/octet-stream"); response.setHeader("Content-Disposition", "attachment; filename=" + new String(fileName.getBytes("gb2312"), "ISO-8859-1")); OutputStream out = response.getOutputStream(); return out; } protected <T> void writeOutputStream(DownloadDataLoader<T> loader, List<String> propertyNames, Writer writer) throws Exception { int pageNum = 0; int maxLenth = 102400; while (maxLenth-- > 0) { // 分页获取数据 List<T> objList = null; try { objList = loader.getDownloadData(pageNum++); } catch (Exception e) { LOGGER.error("获得到处数据异常:{}",e.getMessage(), e); } if (CollectionUtils.isEmpty(objList)) { break; } for (T bean : objList) { if (bean == null) { continue; } Collection<String> result = new ArrayList<String>(); // 遍历指定属性 for (String name : propertyNames) { // 获得属性值 Object property = loader.getProperty(bean, name); // 将属性值转换成字符串 String convertValue = loader.convertProperty(bean, name, property); // 组装成row result.add(convertValue); } if (CollectionUtils.isEmpty(result)) { continue; } writer.write(result); } } } }
package com.wjs.common.util.excel; import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.text.DecimalFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletResponse; import org.apache.commons.beanutils.BeanMap; import org.apache.log4j.Logger; import org.apache.poi.hssf.usermodel.HSSFCell; import org.apache.poi.hssf.usermodel.HSSFDateUtil; import org.apache.poi.hssf.usermodel.HSSFRichTextString; import org.apache.poi.hssf.usermodel.HSSFRow; import org.apache.poi.hssf.usermodel.HSSFWorkbook; 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.springframework.util.CollectionUtils; /** * * @author liqiang05 * */ public class ExcelUtils { /** * logger */ private static final Logger logger = Logger.getLogger(ExcelUtils.class); /** * 设置列格式 * * @param sheet * @param columnWidthList */ public static boolean setSheetStyle(Sheet sheet, List<Integer> columnWidthList) { if (sheet == null || columnWidthList == null) { return false; } // 设置所有列的宽度 for (int indx = 0, iMax = columnWidthList.size(); indx < iMax; indx++) { Integer columnWidth = columnWidthList.get(indx); if (columnWidth == null) { continue; } sheet.setColumnWidth(indx, columnWidth.intValue() * 256); } return true; } /** * 设置行信息 * * @param row * @param rowObj * @return */ public static boolean setRowInfo(Row row, Collection<Object> rowObj) { if (row == null || rowObj == null) { if (logger.isInfoEnabled()) { logger.info("Row:" + row + ",rowObj" + rowObj); } return false; } // 填充每一列数据 int indxColumn = 0; for (Object object : rowObj) { Cell cell = row.createCell(indxColumn++); if (object == null) { if (logger.isDebugEnabled()) { logger.debug("Row:" + row + ",Column:" + indxColumn + ",is empty"); } continue; } String columnValue = object.toString(); cell.setCellType(HSSFCell.CELL_TYPE_STRING); cell.setCellValue(columnValue); } return true; } /** * 设置行信息 * * @param row * @param rowObj * @param convert */ @SuppressWarnings({ "rawtypes", "unchecked" }) public static boolean setRowInfo(Row row, Object rowObj, IExcelConvert convert) { if (row == null || rowObj == null) { if (logger.isInfoEnabled()) { logger.info("Row:" + row + ",rowObj" + rowObj); } return false; } try { Collection<Object> rowContent = null; if (convert != null) { rowContent = convert.convert(rowObj); } else if (rowObj instanceof Map) { rowContent = ((Map) rowObj).values(); } else if (rowObj instanceof Collection) { rowContent = (Collection) rowObj; } else { rowContent = (new BeanMap(rowObj)).values(); } if (rowContent == null || rowContent.isEmpty()) { if (logger.isDebugEnabled()) { logger.debug("Row:" + row + ",is empty"); } return false; } return setRowInfo(row, rowContent); } catch (Throwable e) { logger.info(rowObj + "convertFailed,row:" + row, e); return false; } } /** * 将数据写入excel * * @param sheet * @param columnWidth * @param header * @param content * @return */ public static boolean setExcelInfo(Sheet sheet, List<Integer> columnWidth, List<String> header, List<?> rows) { return setExcelInfo(sheet, columnWidth, header, rows, null); } /** * 将数据写入excel * * @param sheet * @param columnWidth * @param header * @param content * @param converter * @return */ public static boolean setExcelInfo(Sheet sheet, List<Integer> columnWidth, List<String> header, List<?> content, IExcelConvert converter) { if (sheet == null) { logger.info("sheet is null"); return false; } // 设置sheet格式 setSheetStyle(sheet, columnWidth); // 设置头信息 int indxRow = 0; Row row = sheet.createRow(indxRow++); setRowInfo(row, header, null); // 如果内容为空 则退出 if (content == null || content.isEmpty()) { logger.info("content is null,cannot write excel"); return true; } for (Object rowContent : content) { row = sheet.createRow(indxRow++); setRowInfo(row, rowContent, converter); } return true; } /** * 導出到excel * * @param title * sheet Title * @param columnWidthList * 所有列的寬度,可以不指定 * @param content * 內容, 每一項為一行,每一行內是List代表所有列 * @return */ public static Workbook setupXls(String title, List<Integer> columnWidthList, List<List<String>> content) { Workbook wb = new HSSFWorkbook(); Sheet sheet = wb.createSheet(title); if (columnWidthList != null) { // 设置所有列的宽度 for (int indx = 0, iMax = columnWidthList.size(); indx < iMax; indx++) { Integer columnWidth = columnWidthList.get(indx); if (columnWidth == null) { continue; } sheet.setColumnWidth(indx, columnWidth.intValue() * 256); } } if (content == null || content.isEmpty()) { if (logger.isInfoEnabled()) { logger.info("content is null,cannot write excel,title:" + title); } return wb; } // 遍歷一行 for (int indxRow = 0, iMaxRow = content.size(); indxRow < iMaxRow; indxRow++) { Row row = sheet.createRow(indxRow); List<String> rowContent = content.get(indxRow); if (rowContent == null || rowContent.isEmpty()) { if (logger.isDebugEnabled()) { logger.debug("Row:" + indxRow + ",is empty,title:" + title); } continue; } // 填充每一列数据 for (int indxColumn = 0, iMaxColumn = rowContent.size(); indxColumn < iMaxColumn; indxColumn++) { Cell cell = row.createCell(indxColumn); String columnValue = rowContent.get(indxColumn); if (columnValue == null || columnValue.length() == 0) { if (logger.isDebugEnabled()) { logger.debug("Row:" + indxRow + ",Column:" + indxColumn + ",is empty,title:" + title); } continue; } cell.setCellValue(columnValue); } } return wb; } /** * 加載Excel 默認實現方式 * * @param wb * @return */ public static List<List<String>> loadXls(Workbook wb) { // 默認 只讀第一個sheet, 且從第二行開始遍歷,默认读取到最大列 return loadXls(wb, 0, 1, 0); } /** * 加载excel * * @param wb * @param sheetIndx * 要加载excel的sheet页的index * @param startRowIndx * 要加载Row的index * @param iMaxColumn * 最大读到Cloumn的index * @return List<List<>> */ public static List<List<String>> loadXls(Workbook wb, int sheetIndx, int startRowIndx, int iMaxColumn) { List<List<String>> resList = new ArrayList<List<String>>(); if (wb == null || sheetIndx < 0 || startRowIndx < 0 || iMaxColumn < 0) { logger.error("param error,return empty list,Workbook:" + wb + ",sheetIndex:" + sheetIndx + ",startRowNo:" + startRowIndx + ",iMaxColumn:" + iMaxColumn); return resList; } Sheet sheet = wb.getSheetAt(sheetIndx); if (sheet == null) { logger.error("sheet is null,return empty list,Workbook:" + wb + ",sheetIndex:" + sheetIndx + ",startRowNo:" + startRowIndx); return resList; } // 從指定行開始遍歷 for (int indxRow = startRowIndx, iMaxRow = sheet.getLastRowNum(); indxRow <= iMaxRow; indxRow++) { Row row = sheet.getRow(indxRow); if (row == null) { if (logger.isDebugEnabled()) { logger.debug("Row is null,sheetIndex:" + sheetIndx + ",RowNo:"以上是关于Java分页下载的主要内容,如果未能解决你的问题,请参考以下文章
FragmentStatePagerAdapter 视图分页器片段在活动重新创建后不显示