用Fastjson SXSSFWorkbook 实现Excel单sheet与多sheet导出

     鉴于工作需要大数据量(一般10w左右,或者更多数据量)的excel导出功能,由于现有项目中的 XSSFWorkbook包陈旧、以及jackson封装的数据转化不够高效,所以做了一些修改,优化sql查询和数据处理,基本满足导出秒级实现。

直接上代码了(demo)

1.HTML demo

var data = {
    "sfzh" : $("#jsycx_sfzh").val(),
    "cph" : $("#jsycx_cph option:selected").html()||"全部",
    "xm" : $("#jsycx_xm").val(),
    "gsm" : $("#jsycx_gsm option:selected").html()||"全部",
    "fwzh" : $("#jsycx_fwzh").val(),
    "jyxkz" : $("#jsycx_jyxkz").val(),
    "city" : $("#jsycx_city option:selected").html()};
url = "../../tjfx/jsycxxlsx?data=" + JSON.stringify(data) , window.open(url)

HTML页面的处理比较简单,直接就是打开新的页面就行,请求带上需要的参数。

2.Controller demo

/**
	 * 驾驶员导出
	 * @param request
	 * @param data
	 * @param response
	 * @return
	 * @throws IOException
	 */
	@RequestMapping("/jsycxxlsx")
	@ResponseBody
	public String jsycxxlsx(HttpServletRequest request,
			@RequestParam("data") String data, HttpServletResponse response) throws IOException {
		Map<String, Object> paramMap = FastJsonUtil.stringToMap(data);
		String sfzh = String.valueOf(paramMap.get("sfzh"));
		String cph = String.valueOf(paramMap.get("cph"));
		String xm = String.valueOf(paramMap.get("xm"));
		String gsm = String.valueOf(paramMap.get("gsm"));
		String fwzh = String.valueOf(paramMap.get("fwzh"));
		String jyxkz = String.valueOf(paramMap.get("jyxkz"));
		String city = String.valueOf(paramMap.get("city"));
		String a[] = { "身份证号", "姓名", "业户名称","经营许可证号", "服务证号", "车牌号", "资格证有效期止","分值","证照状态" };// 导出列明
		String b[] = { "ID_NUMBER", "NAME", "COMPANY_NAME","COMPANY_LICENSE_NUMBER", "VEHICLE_ID", "PLATE_NUMBER", "VALID_PERIOD_END","ASSESS_SCORE","STATUS_NAME" };// 导出map中的key
		String gzb = "驾驶员信息";// 导出sheet名和导出的文件名
		String msg = tjfxService.jsycxxlsx(sfzh, cph, xm, gsm,fwzh,jyxkz,city);
		List<Map<String, Object>> list = DownloadAct.strlist(msg);// 导出的数据
		downloadAct.download(request, response, a, b, gzb, list);
		return null;
	}

Controller主要是设置表名 列名 列参数 以及FastJsonUtil解析request参数进行sql查询,具体的sql执行方法就不贴了这个,最后返回的是封装好的FastJsonUtil的Json字符串msg。

3.DownloadAct.strlist方法 demo

/**
     * json字符串转换成List<Map>集合  
     * json字符串格式 [{a:null,b:null}]
     * @return
     * @author erxi
     * @date : 2018年12月3日 下午2:22:40
     */
    public static List<Map<String, Object>> strlist(String jsonString) {
       List<Map<String, Object>> list = null;
        try {
            list = JSON.parseObject(jsonString, new TypeReference<List<Map<String, Object>>>() {});
        } catch (Exception e) {
            e.printStackTrace();
        }
        return list;
    }

这是FastJsonUtil封装类中的其中一个json字符串转成List<Map>集合的格式,后面会贴出自己封装的FastJsonUtil类。

4.downloadAct.download方法  demo

/**
     * demo返回http响应
     * @param request
     * @param response
     * @param a
     * @param b
     * @param gzb
     * @param list
     * @return
     * @throws IOException
     * @author erxi
     * @date : 2018年12月3日 下午2:22:40
     */
    public String download(HttpServletRequest request,
              HttpServletResponse response,
              String[] a,String[] b,String gzb,List<Map<String,Object>> list) throws IOException{
        String fileName = gzb;//excle文件名
        //填充projects数据
        String columnNames[] = a;//列名
        String keys[] = b;//map中的key
        ByteArrayOutputStream os = new ByteArrayOutputStream();//内存缓冲区的数据,转换成字节数组
        try {
            ExcelUtil.createWorkBook(list,keys,columnNames,gzb).write(os);
        } catch (IOException e) {
            e.printStackTrace();
        }
        byte[] content = os.toByteArray();
        InputStream is = new ByteArrayInputStream(content);
        // 设置response参数,可以打开下载页面
        response.reset();
        response.setContentType("application/vnd.ms-excel;charset=utf-8");
        response.setHeader("Content-Disposition", "attachment;filename="+ new String((fileName + ".xlsx").getBytes(), "iso-8859-1"));
        ServletOutputStream out = response.getOutputStream();
        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;
        try {
            bis = new BufferedInputStream(is);
            bos = new BufferedOutputStream(out);
            byte[] buff = new byte[1024];
            int bytesRead;
            // Simple read/write loop.
            while (-1 != (bytesRead = bis.read(buff, 0, buff.length))) {
                bos.write(buff, 0, bytesRead);
            }
        } catch (final IOException e) {
            throw e;
        } finally {
            if (bis != null)
                bis.close();
            if (bos != null)
                bos.close();
        }
        return null;
    }

通过response把文件输出到页面进行导出。


4.ExcelUtil.createWorkBook方法 demo

4.1.单sheet

/**
 * demo ExcelUtil封装
 * @author erxi
 * @date : 2018年12月3日 下午2:22:40
 */
public class ExcelUtil {
        public static Workbook createWorkBook(List<Map<String, Object>> list,
                     String []keys,String columnNames[],String gzb) throws IOException {
               //缓存的值
               int rowaccess = 100;
               // 创建excel工作簿
               SXSSFWorkbook wb = new SXSSFWorkbook(rowaccess);
               //数据库数据量
               int listSize = list.size();
               // 创建第一个sheet(页),并命名
               Sheet sheet = wb.createSheet(gzb);
               // 创建第一行
               Row row = sheet.createRow((short) 0);
               //设置列名
               for(int i=0;i<columnNames.length;i++){
                   Cell cell = row.createCell(i);
                   cell.setCellValue(columnNames[i]);
               }
               //设置每行每列的值
               int rowss=1;
              for (int i = 0; i < listSize; i++) {
                   // Row 行,Cell 方格 , Row 和 Cell 都是从0开始计数的
                   // 创建一行,在页sheet上
                   Row row1 = sheet.createRow((short) rowss+i);
                   // 在row行上创建一个方格
                   for(short j=0;j<keys.length;j++){
                       Cell cell = row1.createCell(j);
                       cell.setCellValue(list.get(i).get(keys[j]) == null?" ": list.get(i).get(keys[j]).toString());
                   }
                   //每当行数达到设置的值就刷新数据到硬盘,以清理内存
                   if(i % rowaccess==0){
                      ((SXSSFSheet) sheet).flushRows();
                     }
               }
               return wb;
           }
}

4.2.多sheet  该demo加入了对行列表头样式的设定

/**
 * demo ExcelUtil封装
 * @author erxi
 * @date : 2018年12月3日 下午2:22:40
 */
public class ExcelUtil {
        public static Workbook createWorkBook(List<Map<String, Object>> list,
                     String []keys,String columnNames[],String gzb) throws IOException {
               //缓存的值
               int rowaccess = 100;
               // 创建excel工作簿
               SXSSFWorkbook wb = new SXSSFWorkbook(rowaccess);
               //数据库数据量
               int listSize = list.size();
               //最大记录数
               int maxCache = 5000;
               //sheet 页数
               int sheet_num = 0;
               if(0 == listSize%maxCache){
                     sheet_num = listSize/maxCache;
               }else{
                     sheet_num = listSize/maxCache + 1;
               }
               //每个sheet
               for(int k=0; k<sheet_num; k++){
                      // 创建第一个sheet(页),并命名
                     Sheet sheet = wb.createSheet(gzb+k);
                     // 手动设置列宽。第一个参数表示要为第几列设;,第二个参数表示列的宽度,n为列高的像素数。
                     for(int i=0;i<keys.length;i++){
                         sheet.setColumnWidth((short) i, (short) (35.7 * 150));
                     }
                     // 创建第一行
                     Row row = sheet.createRow((short) 0);
                     // 创建两种单元格格式
                     CellStyle cs = wb.createCellStyle();
                     CellStyle cs2 = wb.createCellStyle();
                     // 创建两种字体
                     Font f = wb.createFont();
                     Font f2 = wb.createFont();
                     // 创建第一种字体样式(用于列名)
                     f.setFontHeightInPoints((short) 10);
                     f.setColor(IndexedColors.BLACK.getIndex());
                     f.setBoldweight(Font.BOLDWEIGHT_BOLD);
                     // 创建第二种字体样式(用于值)
                     f2.setFontHeightInPoints((short) 10);
                     f2.setColor(IndexedColors.BLACK.getIndex());
                     Font f3=wb.createFont();
                     f3.setFontHeightInPoints((short) 10);
                     f3.setColor(IndexedColors.RED.getIndex());
                     // 设置第一种单元格的样式(用于列名)
                     cs.setFont(f);
                     cs.setBorderLeft(CellStyle.BORDER_THIN);
                     cs.setBorderRight(CellStyle.BORDER_THIN);
                     cs.setBorderTop(CellStyle.BORDER_THIN);
                     cs.setBorderBottom(CellStyle.BORDER_THIN);
                     cs.setAlignment(CellStyle.ALIGN_CENTER);
                     // 设置第二种单元格的样式(用于值)
                     cs2.setFont(f2);
                     cs2.setBorderLeft(CellStyle.BORDER_THIN);
                     cs2.setBorderRight(CellStyle.BORDER_THIN);
                     cs2.setBorderTop(CellStyle.BORDER_THIN);
                     cs2.setBorderBottom(CellStyle.BORDER_THIN);
                     cs2.setAlignment(CellStyle.ALIGN_CENTER);
                     //设置列名
                     for(int i=0;i<columnNames.length;i++){
                         Cell cell = row.createCell(i);
                         cell.setCellValue(columnNames[i]);
                         cell.setCellStyle(cs);
                     }
                     //设置每行每列的值
                     int rowss=1;
                     if(k == sheet_num - 1){
                           for (int i = k*maxCache; i < listSize; i++) {
                                // Row 行,Cell 方格 , Row 和 Cell 都是从0开始计数的
                                // 创建一行,在页sheet上
                                Row row1 = sheet.createRow((short) rowss+i-k*maxCache);
                                // 在row行上创建一个方格
                                for(short j=0;j<keys.length;j++){
                                    Cell cell = row1.createCell(j);
                                    cell.setCellValue(list.get(i).get(keys[j]) == null?" ": list.get(i).get(keys[j]).toString());
//                                  cell.setCellStyle(cs2);
                                }
                                //每当行数达到设置的值就刷新数据到硬盘,以清理内存
                                if(i % rowaccess==0){
                                   ((SXSSFSheet) sheet).flushRows();
                                   }
                            }
                     }else{
                           for (int i = k*maxCache; i < (k+1)*maxCache; i++) {
                                // Row 行,Cell 方格 , Row 和 Cell 都是从0开始计数的
                                // 创建一行,在页sheet上
                                Row row1 = sheet.createRow((short) rowss+i-k*maxCache);
                                // 在row行上创建一个方格
                                for(short j=0;j<keys.length;j++){
                                    Cell cell = row1.createCell(j);
                                    cell.setCellValue(list.get(i).get(keys[j]) == null?" ": list.get(i).get(keys[j]).toString());
                                    cell.setCellStyle(cs2);
                                }
                                //每当行数达到设置的值就刷新数据到硬盘,以清理内存
                                if(i % rowaccess==0){
                                   ((SXSSFSheet) sheet).flushRows();
                                   }
                            }
                     }
               }
               return wb;
           }
}

5.总结

  1. FastJson的高效数据算法是基本实现得到数据到页面导出是秒级实现。
  2. SXSSFWorkbook适用于大数据量下的批量导出,合理的使用内存和磁盘,提升效率,避免了传统导出数据量过大导致内存溢出。

 

最后贴上FastJsonUtil类

/**
* FastJsonUtil 工具类
*
* @author erxi
* @date : 2018年12月3日 下午4:09:27
*/
public class FastJsonUtil {

    private static final SerializeConfig config;

    static {
        config = new SerializeConfig();
        config.put(java.util.Date.class, new JSONLibDataFormatSerializer()); // 使用和json-lib兼容的日期输出格式
        config.put(java.sql.Date.class, new JSONLibDataFormatSerializer()); // 使用和json-lib兼容的日期输出格式
    }

    private static final SerializerFeature[] features = {
            SerializerFeature.WriteMapNullValue, // 输出空置字段
            SerializerFeature.WriteNullListAsEmpty, // list字段如果为null,输出为[],而不是null
            SerializerFeature.WriteNullNumberAsZero, // 数值字段如果为null,输出为0,而不是null
            SerializerFeature.WriteNullBooleanAsFalse, // Boolean字段如果为null,输出为false,而不是null
            SerializerFeature.WriteNullStringAsEmpty // 字符类型字段如果为null,输出为"",而不是null
    };

    /**
     * 转换成字符串
     *
     * @param object
     * @return
     */
    public static String toJSONString(Object object) {
        return JSON.toJSONString(object, config);
    }

    /**
     * 转换成字符串 ,带有过滤器
     *
     * @param object
     * @return
     */
    public static String toJSONWithFeatures(Object object) {
        return JSON.toJSONString(object, config, features);
    }

    /**
     * 转成bean对象
     *
     * @param text
     * @return
     */
    public static Object toBean(String text) {
        return JSON.parse(text);
    }

    /**
     * 转成具体的泛型bean对象
     *
     * @param text
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> T toBean(String text, Class<T> clazz) {
        return JSON.parseObject(text, clazz);
    }

    /**
     * 转换为数组Array
     *
     * @param text
     * @param <T>
     * @return
     */
    public static <T> Object[] toArray(String text) {
        return JSON.parseArray(text).toArray();
    }

    /**
     * 转换为具体的泛型数组Array
     *
     * @param text
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> Object[] toArray(String text, Class<T> clazz) {
        return JSON.parseArray(text, clazz).toArray();
    }

    /**
     * 转换为具体的泛型List
     *
     * @param text
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> List<T> toList(String text, Class<T> clazz) {
        return JSON.parseArray(text, clazz);
    }

    /**
     * 将javabean转化为序列化的json字符串
     *
     * @param keyvalue
     * @return
     */
    public static Object beanToJson(KeyValue keyvalue) {
        String textJson = JSON.toJSONString(keyvalue);
        Object objectJson = JSON.parse(textJson);
        return objectJson;
    }

    /**
     * 将string转化为序列化的json字符串
     *
     * @param text
     * @return
     */
    public static Object textToJson(String text) {
        Object objectJson = JSON.parse(text);
        return objectJson;
    }

    /**
     * json字符串转化为map
     *
     * @param s
     * @return
     */
    public static Map stringToMap(String s) {
        Map m = JSONObject.parseObject(s);
        return m;
    }

    /**
     * 将map转化为string
     *
     * @param m
     * @return
     */
    public static String mapToString(Map m) {
        String s = JSONObject.toJSONString(m);
        return s;
    }

    /**
     * 用fastjson 将jsonString 解析成 List<Map<String,Object>>
     *
     * @param jsonString
     * @return
     */
    public static List<Map<String, Object>> getListMap(String jsonString) {
        List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
        try {
            // 两种写法
            // list = JSON.parseObject(jsonString, new
            // TypeReference<List<Map<String, Object>>>(){}.getType());

            list = JSON.parseObject(jsonString,
                    new TypeReference<List<Map<String, Object>>>() {
                    });
        } catch (Exception e) {
            e.printStackTrace();
        }
        return list;
    }
}

代码基本都有注解,如有错误,谢谢指正。

 

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
你可以使用 EasyExcel 库将多个 JSONArray 放入同一个 Excel 的同一个 sheet 中。下面是一个示例代码,演示了如何实现这个功能: ```java // 导入所需的库 import com.alibaba.excel.EasyExcel; import com.alibaba.excel.write.builder.ExcelWriterBuilder; import com.alibaba.excel.write.metadata.WriteSheet; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; public class ExcelWriter { public static void main(String[] args) { // 创建 ExcelWriterBuilder 对象 ExcelWriterBuilder writerBuilder = EasyExcel.write("output.xlsx"); // 创建 WriteSheet 对象 WriteSheet writeSheet = EasyExcel.writerSheet(0, "Sheet1").build(); // 创建 JSONArray 对象 JSONArray jsonArray = new JSONArray(); // 添加要写入 Excel 的数据 jsonArray.add(new JSONObject().fluentPut("name", "John").fluentPut("age", 25)); jsonArray.add(new JSONObject().fluentPut("name", "Alice").fluentPut("age", 30)); jsonArray.add(new JSONObject().fluentPut("name", "Bob").fluentPut("age", 35)); // 写入 Excel writerBuilder.sheet().doWrite(jsonArray); // 关闭 ExcelWriterBuilder 对象 writerBuilder.finish(); } } ``` 在上面的示例中,我们创建了一个 ExcelWriterBuilder 对象,并指定了输出的文件名为 "output.xlsx"。然后,我们创建了一个 WriteSheet 对象,用于指定要写入的 sheet 名称。接下来,我们创建了一个 JSONArray 对象,并向其中添加了要写入 Excel 的数据。最后,调用 `writerBuilder.sheet().doWrite(jsonArray)` 将数据写入 Excel 中。最后,我们通过调用 `writerBuilder.finish()` 来关闭 ExcelWriterBuilder 对象。 你可以根据需要,添加更多的 JSONArray 对象来写入更多的数据。每个 JSONArray 对象都会写入同一个 sheet 中。 希望这个示例能够帮助到你!如果有任何疑问,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值