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);
                    }
                }

            }
}
BaseController代码
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分页下载的主要内容,如果未能解决你的问题,请参考以下文章

片段被视图分页器布局切割

Java分页下载

Symfony2 将哈希片段参数附加到分页 URL

FragmentStatePagerAdapter 视图分页器片段在活动重新创建后不显示

FragmentStatePagerAdapter视图分页器片段在重新创建活动后未显示

Java 获取Excel分页坐标位置(单元格)