SpringMVC在内存中直接生成Excel让用户在浏览器中直接下载使用

1. 如何查询出数据库的SCHEMA, 这里贴出核心的SQL语句

SELECT COLUMN_NAME AS field, COLUMN_COMMENT AS comment
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_name = ?

由于注释有的会很长, 全部取出来作为excel的一格, 会很不好, 其实我们只是需要重要的意思, 所以, 这里前提条件就是将注释用分隔符分开

例如: name=>名称: 用户昵称, 这里我就可以用":"来分割, 只取出"名称"来. 所以, 一件方便的事情是需要很多的约定的, 尤其是团队合作中.

为了拿到一张表的字段名, 和注释, 就提取了一个公用的类:

/**
 * Created with antnest-platform
 * User: Vernon.Chen
 * Date: 2015/3/16
 * Time: 17:03
 */
@Service
public class QuerySchema {

    @Resource
    private JdbcTemplate jdbcTemplate;

    public List<Map<String, Object>> getSchemaByTableName(String tableName) {
        if (StringUtils.isBlank(tableName)) {
            return null;
        }
        List<Map<String, Object>> schema = new ArrayList<Map<String, Object>>();
        StringBuilder sqlSB = new StringBuilder();
        sqlSB.append(" SELECT COLUMN_NAME AS field, COLUMN_COMMENT AS comment ");
        sqlSB.append(" FROM INFORMATION_SCHEMA.COLUMNS ");
        sqlSB.append(" WHERE table_name = ? ");
        schema = jdbcTemplate.queryForList(sqlSB.toString(), new Object[]{tableName});
        if (schema != null && schema.size() > 0) {
            for (Map<String, Object> map : schema) {
                String comment = (String) map.get("comment");
                if (StringUtils.isNotBlank(comment) && comment.indexOf(":") > -1) {
                    map.put("comment", comment.substring(0, comment.indexOf(":")));
                }
            }
        }
        return schema;
    }

}

这返回的结果就是一List, 里面每一个Map都是一个{"field":"XXX","comment":"XXX"}.

下面就是如何生成Excel呢? 也是比较总要的一步. 生成Excel我所知道jar包有2个, 一个是jxl.jar, 还有一个就是项目中用到的poi.

<dependency>
                <groupId>org.apache.poi</groupId>
                <artifactId>poi</artifactId>
                <version>${poi.version}</version>
            </dependency>

这里我的版本是:

<poi.version>3.10-FINAL</poi.version>

然后开看一个组装Excel的代码. 由于不需要将生成的文件持久化到本地, 所以直接返回byte[]就好.

@Override
    public byte[] selectExcel() throws Exception {
        ByteArrayOutputStream out = null;
        try {
            HSSFWorkbook workbook = new HSSFWorkbook();
            generateExcelForAs(cellMapper.selectExcel(), workbook);
            out = new ByteArrayOutputStream();
            HSSFWorkbook hssWb = (HSSFWorkbook) workbook;
            hssWb.write(out);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return out.toByteArray();
    }

迭代生成每一行

private void generateExcelForAs(List<Map<String, Object>> list, HSSFWorkbook workbook) {
        if (list == null || list.size() == 0) {
            return ;
        }
        List<Map<String, Object>> title = querySchema.getSchemaByTableName("t_cell");
        int excelRow = 0;
        try {
            HSSFSheet sheet = workbook.createSheet();
            for (int i = 0; i < list.size(); i++) {
                if (i == 0) {
                    Map<String, Object> first = list.get(0);
                    // 添加标题
                    int column = 0;
                    HSSFRow row = sheet.createRow(excelRow);
                    for (Map<String, Object> map : title) {
                        row.createCell(column).setCellValue(map.get("comment").toString());
                        column++;
                    }
                    excelRow++;
                    column = 0;
                    // 还需添加第1行的数据, 从0开始
                    row = sheet.createRow(excelRow);
                    for (Map<String, Object> map : title) {
                        if (!first.containsKey(map.get("field"))) {
                            column++;
                        } else {
                            String value = first.get(map.get("field")) == null ? "" : first.get(map.get("field")).toString();
                            row.createCell(column).setCellValue(value);
                            column++;
                        }
                    }
                    excelRow++;
                } else {
                    HSSFRow row = sheet.createRow(excelRow);
                    Map<String, Object> rowMap = list.get(i);
                    int column = 0;
                    for (Map<String, Object> map : title) {
                        if (!rowMap.containsKey(map.get("field"))) {
                            column++;
                        } else {
                            String value = rowMap.get(map.get("field")) == null ? "" : rowMap.get(map.get("field")).toString();
                            row.createCell(column).setCellValue(value);
                            column++;
                        }
                    }
                    excelRow++;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

代码比较挫, 效率也低, 没办法, 因为需要按照指定的顺序生成. 也许有更好的办法, 我现在只是要按时完成需求.

这里就返回了想要的byte[].

最后一步就是在Response里返回流了.

@RequestMapping(value = "/xxx")
    public void cell(HttpServletResponse response) throws Exception {
        byte[] bytes = cellService.selectExcel();
        response.setContentType("application/x-msdownload");
        response.setHeader("Content-Disposition", "attachment;filename=" + UUIDUtil.getUUID() + ".xls");
        response.setContentLength(bytes.length);
        response.getOutputStream().write(bytes);
        response.getOutputStream().flush();
        response.getOutputStream().close();
    }

这里注意的就是:

response.setContentType("application/x-msdownload"); 
response.setHeader("Content-Disposition", "attachment;filename=" + UUIDUtil.getUUID() + ".xls");

一个是告诉浏览器需要下载, 下面一个就是告诉流程器下载是的文件名字. 这里我用的UUID.

至此, 就完全OK了

时间: 2024-08-29 04:49:44

SpringMVC在内存中直接生成Excel让用户在浏览器中直接下载使用的相关文章

Eclipse中使用Tomcat加载项目在浏览器中访问的时候JS和CSS等静态文件无法加载的问题

首先,我的Eclipse是引用外部的Tomcat 引用外部Tomcat会在左侧生成一个Server文件夹,相当于复制了一份Tomcat到Eclipse的安装目录里 具体Tomcat所在目录可以在这进行查看 双击Tomcat服务,会打开一个窗口,然后点击Open launch configuration,可打开配置窗口,在这里可以查看到具体服务所在位置. 接下来步入正题,正如题目所说,Eclipse中使用Tomcat加载项目在浏览器中访问的时候JS和CSS等静态文件无法加载,如图 仔细看下路径,会

读取Excel二进制写入DB,并从DB中读取生成Excel文件

namespace SendMailSMSService { class Program { static void Main(string[] args) { var connString = SqlDataHelper.GetConnectionString<FileContent>(); //读取Excle文件并写入表中 var bytes = File.ReadAllBytes("a.xlsx"); var entity = new FileContent { Fi

在ASP.NET MVC中利用Aspose.cells 将查询出的数据导出为excel,并在浏览器中下载。

正题前的唠叨 本人是才出来工作不久的小白菜一颗,技术很一般,总是会有遇到一些很简单的问题却不知道怎么做,这些问题可能是之前解决过的.发现这个问题,想着提升一下自己的技术水平,将一些学的新的'好'东西记录下来,一是加深印象:二是以后可以作为参考:三是希望博友们可以提出不足和可以优化的地方,一起讨论. 这个是我去一家公司没多久,让我做的小功能,主要是导出excel并在浏览器下载下来. 但是会有不同的细微的需求差别. 第一次发博客,有描述不清楚的地方还请见谅,希望各位多多指点. 进入正题 简单的需求描

eclipse中tomcat能正常启动,在浏览器中不能打开问题

问题原因:没有在eclipse中tomcat的server location设置到tomcat的安装目录. 解决办法:1.选择server点击右键,选择Open选项,然后在server location栏设置tomcat的安装目录. 2.重新启动tomcat server. 3.在浏览器中输入:http://localhost:port    注:port代表你设置的端口号   如果需要改端口请在server.xml中操作.

Unity生成的WebGL如何在浏览器中运行

前言:以为在学完了COMP30019后,应该不会再接触Unity了,没想到之后实习让我去做把一个Unity项目转到WebGL,而关于Unity的WebGL资料很少,基本除了Unity的Manual就只能看别人零星的记录了.遇到了一堆问题,可能以后会也写在博客上. 浏览器默认禁止从file里直接运行WebGL的. 有三个方法: 1. 在Unity里选择Build and run,build完后unity会直接自动创建本地服务器运行,但这个方法很不方便,总不能要用时都build一遍吧. 2. 修改浏

解决div布局中第一个div的margin-top在浏览器中显示无效果问题。

原味来源:http://www.hicss.net/do-not-tell-me-you-understand-margin/ 垂直外边距合并问题 别被上面这个名词给吓倒了,简单地说,外边距合并指的是,当两个垂直外边距相遇时,它们将形成一个外边距.合并后的外边距的高度等于两个发生合并的外边距的高度中的较大者.你可以查看W3Shool CSS外边距合并了解这个基本知识. 实际工作中,垂直外边距合并问题常见于第一个子元素的margin-top会顶开父元素与父元素相邻元素的间距,而且只在标准浏览器下

.NET WebAPI生成Excel

Webform中,生成Excel,一般是设置response.Content.Headers.ContentType输出类型为application/vnd.ms-excel,思路都是这样的. 每一个API方法都这样做一下,也是可以的.参考:http://www.cnblogs.com/jizhong/p/3592088.html 更好的做法是,客户端请求的时候,设置Requst.Header的Accept:application/vnd.ms-excel.目的:客户端设置了什么类型,服务端针对

jeecg3.5中的导入excel文件的使用及完善

jeecg中导入导出excel文件使用了jeecg团队自己开发的一个easypoi库,所以使用起来非常简单,以我项目中导入黑名单列表功能为例: 在实体中增加注解 先增加类的注解: @ExcelTarget("blackListEntity") public class BlackListEntity implements java.io.Serializable { 再增加字段注解: /**手机号码*/ @Excel(name="手机号码") private Lon

生成 excel 直接用 httpServletResponse 输出

之前写过一篇文章 <超详细的java生成excel文件并下载>,该文章虽然够详细,也行得通,但还是有一定的缺陷,该文章可以拆分成两个部分,一是指定位置生成excel文件,二是根据地址下载文件.缺陷的部分是会产生中间文件,而这个中间文件我们并不需要,如果每次下载的时候都会生成一个这样的文件,那久而久之岂不是浪费空间,而且生成文件之后再读取输出这样也耗时间.所以今天就对之前的文章进行优化处理下. package com.test.demo.controllers; import com.test.