解决java web开发中常见的大量数据导出Excel超时(504)问题

来源:互联网 发布:js调试 条件断点 编辑:程序博客网 时间:2024/06/05 07:43
import java.io.IOException;import java.io.OutputStream;import java.lang.reflect.Field;import java.text.SimpleDateFormat;import java.util.Date;import java.util.HashMap;import java.util.List;import java.util.Map;import java.util.Map.Entry;import javax.servlet.http.HttpServletResponse;import org.apache.commons.lang3.StringUtils;import org.joda.time.DateTime;import com.travelzen.framework.net.http.TZHttpClient;import com.travelzen.tops.front.ota.member.item.CustomerItem;public class CSV {    /**     * 目标输出流     */    private OutputStream stream;    /**     * 表头     */    private Map<String,String> fields;    /**     * 数据源model所有字段map     */    private static Map<String, Field> fieldMap = new HashMap<>();    public CSV(HttpServletResponse response,Map<String,String> fields,String fileName,Class<?> clz) throws IOException{        if(response == null || fields == null || fileName == null || clz == null)            throw new IllegalArgumentException();        getFieldMap(clz,fieldMap);        this.stream = response.getOutputStream();        this.fields = fields;        response.setContentType("application/octet-stream;charset=GBK");        response.setHeader("Content-Disposition", "attachment;fileName="+ fileName);        //写表头,生成指定名字的文件,返回客户端        StringBuilder hb = new StringBuilder();        for(Entry<String, String> e : fields.entrySet())            hb.append(e.getValue()+",");        stream.write(hb.substring(0, hb.length() - 1).getBytes("GBK"));        stream.flush();    }    /**     * 往表格中插入记录     */    public void write(List<Object> data) throws IllegalArgumentException, IllegalAccessException, IOException{        for(Object o : data){            StringBuilder sb = new StringBuilder();            sb.append("\n");            for(String field : fields.keySet()){                Field f = fieldMap.get(field);                f.setAccessible(true);                Object value = f.get(o);                if(value == null || StringUtils.isBlank(value.toString())){                    sb.append(" ,");                } else if (f.getType() == Date.class) {                    sb.append(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(value) + ",");                } else if (f.getType() == DateTime.class) {                    sb.append(((DateTime)value).toString("yyyy-MM-dd HH:mm:ss") + ",");                } else {                    String tmp = value.toString();                    if(tmp.contains(","))                        tmp = tmp.replace(",", "\",\"");                    sb.append(value.toString() + ",");                }            }            stream.write(sb.substring(0, sb.length() - 1).getBytes("GBK"));            stream.flush();        }    }    public void close() throws IOException{        stream.close();    }    private static <T extends Object> void getFieldMap(Class<T> clz, Map<String, Field> result) {        for (Field field : clz.getDeclaredFields()) {            result.put(field.getName(), field);        }        if (clz.getSuperclass() != null) {            getFieldMap(clz.getSuperclass(), result);        }    }}

web开发中常见的准备Excel数据需要从数据库查询数据,或者跨系统调用接口查询数据,耗费大量时间,因此未及时向浏览器返回数据,导致504超时。

本工具使用ServletOutputStream分段的往浏览器flush数据。调用方式:先new CSV(),传入指定参数,不断的调用wirte()方法往浏览器写入数据,最后调用close方法关闭流。

本工具导出的文件格式为.csv文件,windows office工具默认编码为ASCI,wps会匹配各种编码,libreOffice calc可以指定编码,故此设置编码为GBK,兼容三种Excel软件,也可根据自身需求设置编码。

本工具只处理了CSV中”,”的转码,对于双引号并未处理。

0 0