欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-04-09 21:25:21
...

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了



    

转载于:https://my.oschina.net/vernon/blog/389039