实际项目中使用poi导出excel(spring+springMVC+Mybatis环境下)

来源:互联网 发布:淘宝收藏宝贝在哪里找 编辑:程序博客网 时间:2024/04/29 06:59

准备poi所依赖的jar包.

       放到工程的lib文件夹下.本文中项目所使用的jar包为:

  1. poi-3.15.jar,
  2. poi-ooxml-3.15.jar,
  3. poi-ooxml-schemas-3.15.jar
jar包下载地址:http://mvnrepository.com/search?q=comment

场景描述:

前台用easyui框架(这里博主用的是easyui框架,其他框架道理一样),选中一条数据,进行方案导出.效果截图如下:


首先是先获取选中方案的id(数据库中的),根据此id去数据库中查询方案下包含的具体的自定义媒体类型信息列表.用于封装成excel的基础数据,也就是要导出的内容.

利用poi导出excel大体思路:

1,需要导出的原始数据.即根据实际需求查询得到的结果集作为原始数据.可能是一个list,map...看你封装成什么样了(这里是封装成list了)

2,将原始的数据转换到excel中,具体根据数据形式不同,写法也会不同.不过这些都是大同小异的.

3,将生产好的excel文件写到一个路径下(这里都是放到tomcat服务器目录下的download下).

4,根据上一步的路径找到excel文件进行下载操作(就是文件下载...网上一大片)

下面看各个层的代码,以及excel工具类.具体步骤,代码中注释已经写到很明白了.

Controller层代码:

/**     * 导出新闻方案     * @param Integer[] newsScheme方案id数组     * @throws Exception     */    @RequestMapping(value = "newsSchemes/export/{newsSchemesId}",method = RequestMethod.POST)    public void exportNewsScheme(@PathVariable("newsSchemesId") Integer newsSchemesId) throws Exception{        System.err.println("导出的方案的id:"+newsSchemesId);        //切换到rsdb数据库        DataSourceContextHolder.setDbType(DataSourceType.SOURCE_RSDB);        //查询的结果集,list为需要在表格中展示的数据        List<NewsMediaCategory> list = this.newsMediaCategoryService.listNewsMediaCateBySid(new NewsMediaCategory(newsSchemesId));        //循环将自定义媒体对应的新闻源集合存入到list中.        if(list != null && list.size()>0){            for(int i=0;i<list.size();i++){                //切换到rsdb数据库                DataSourceContextHolder.setDbType(DataSourceType.SOURCE_RSDB);                //获取site_id数组                Integer[] sIds = this.newsMediaCategoryService.listSidsByNewsMediaCateId(list.get(i).getId());                //切换到RSNews数据库                DataSourceContextHolder.setDbType(DataSourceType.SOURCE_RSNEWS);                List<Site> siteList = this.siteService.listBySids(new Site(sIds));                //List<Site> site = this.siteMapper.listBySids(null)                list.get(i).setSiteList(siteList);                list.get(i).setSids(sIds);            }        }        for(NewsMediaCategory nmc : list){            System.err.println(nmc.getName()+"--------"+nmc.getSiteList().size());        }        //切换到rsdb数据库        DataSourceContextHolder.setDbType(DataSourceType.SOURCE_RSDB);        //根据方案id查询方案基本信息,主要是为了获取导出时候的默认名为(当前方案名+时间戳)        NewsSchemes newsScheme = this.newsSchemesService.selNewsSchemesBySchemesId(newsSchemesId);        //获取欲下载的文件路径        String filePath =this.newsSchemesService.createNewSchemesExcel(newsScheme,list,this.request);        //执行下载操作        ExcelUtils.download(filePath , this.request , this.response);    }
service层代码:

这里需要说明下:步骤大体是这么搞,但是样式需要根据不同需求来设定,其中的逻辑也会不一样的.此处导出的样式如下图:

代码如下:

/**     * 方法描述:生产方案excel文件,并写到指定位置.将该文件的绝对路径返回<br>     * 返回类型:String<br>     * 作者:GQ<br>     * 创建时间:2016年12月30日14:41:52<br>     * @param request           request请求<br>     * @param newsSchemeId      新闻方案id<br>     * @param list              NewsMediaCategory集合<br>     */    @Override    public String createNewSchemesExcel(NewsSchemes newsScheme,List<NewsMediaCategory> list,HttpServletRequest request) {        // 第一步,创建一个workbook,对应一个Excel文件        HSSFWorkbook wb = new HSSFWorkbook();        // 第二步,在workbook中添加一个sheet,对应Excel文件中的sheet        HSSFSheet sheet = wb.createSheet("新闻方案表");        //获取单元格格式的样式,一些基本属性        HSSFCellStyle cellStyle = ExcelUtils.getCellStyle(wb);        //获取标题格式        HSSFCellStyle titleStyle = ExcelUtils.getTitleStyle(wb);        //创建表头.第一行.第一列的数据        ExcelUtils.createCell(sheet, 0, 0, titleStyle, "方案具体信息表");        //合并单元格CellRangeAddress构造参数依次表示起始行,截至行,起始列, 截至列        ExcelUtils.mergedRegion(sheet , 0 , 0 , 0 , 2);        //第二行,弟1,2,3列对应的数值,创建行"自定义媒体名称,备注信息,包含站点源个数".        ExcelUtils.createMultiCell(sheet , 1 , new Integer[]{0,1,2} , cellStyle , new String[]{"自定义媒体名称","备注信息","包含站点源个数"});        //记录第一个总信息表真实数据行数,真实数据添加的起始行应该是(rCounts-1)为真是数据起始行.        int rCounts=3;        //将真实数据插入到excel表中去.        for (int r = 0; r < list.size(); r++) {            //获取真实数据            NewsMediaCategory nmc = list.get(r);            //每次填充同一行的,前三个单元格.调用同时填充(同一行的多个单元格的方法).            ExcelUtils.createMultiCell(sheet , r+2 , new Integer[]{0,1,2} , cellStyle , new String[]{nmc.getName(),nmc.getRemark(),String.valueOf(nmc.getSiteList().size())});            //每次加1,为了得到下一个表的表头位置.            rCounts++;        }        //设置分割那一行,将他创建出来,但是不赋值任何数据,用于导入时候的区分点.        ExcelUtils.createRow(sheet , rCounts-1);        //System.err.println("rowNullde的单元格个数:"+rowNull.getPhysicalNumberOfCells());        //设置'自定义媒体类型具体信息表',表头        ExcelUtils.createCell(sheet, rCounts, 0, titleStyle, "自定义媒体类型具体信息表");        //累计,判断合并时候用.确定每一个单元格        int m=0;        for (int r = 0; r < list.size(); r++) {            //循环控制有几个媒体类型            NewsMediaCategory nmc = list.get(r);            //合并自定义媒体名称那一行,m控制合并的起止位置.            ExcelUtils.mergedRegion(sheet , rCounts+1 , rCounts+1 , m , m+2);            //设置自定义媒体名称那一行,每一个单元格名称.            ExcelUtils.createMultiCell(sheet , rCounts+1 , new Integer[]{m,m+1,m+2} , cellStyle , new String[]{nmc.getName(),"",""});            //循环出媒体名称下面的哪一行,"新闻源id,新闻源站点名称,url"            ExcelUtils.createMultiCell(sheet , rCounts+2 , new Integer[]{m,m+1,m+2} , cellStyle , new String[]{"新闻源id","新闻源站点名称","url"});            //填充,每一个自定义媒体类型下,所拥有的新闻源具体信息..            for(int i=0;i<nmc.getSiteList().size();i++){                //循环媒体类型对应的新闻源id数组                Site s = nmc.getSiteList().get(i);                //循环出具体新闻源id,站点名称,url的数据库具体信息                ExcelUtils.createMultiCell(sheet , rCounts+3+i , new Integer[]{m,m+1,m+2} , cellStyle , new String[]{String.valueOf(s.getSite_ID()),s.getSite_Des(),s.getSite_URL()});            }            m=m+3;        }        //合并'自定义媒体类型具体信息表'行,根据自定义媒体类型个数决定的.        ExcelUtils.mergedRegion(sheet , rCounts , rCounts , 0 , m-1);        //控制列数        for(int i=0;i<m;i++){            //设置自动使用宽度            //这里写死,10个中文字符            sheet.setColumnWidth(i,10 * 512);        }        //(导出的默认文件名为当前导出方案名+时间戳)        String fileName=newsScheme.getName()+DateUtil.createTimeStemp(new Date()) + ".xls";        //获取导出的路径.就是将文件导出到哪个文件夹下.(级别到文件夹)        String filePath = request.getSession().getServletContext().getRealPath("/")+"WEB-INF/download";        //将文件存到指定位置,实际就是将生产好的excel文件写到某个位置,为了下一步下载.        ExcelUtils.writeExcelToLocation(wb , filePath + "/" + fileName);        //返回文件生成后存储的绝对路径.即为路径+文件名称.        return filePath + "/" + fileName;    }
excel的工具类:(等读者熟悉了,自己写自己合适的工具类这里多有东西只是起到指引作用).

package com.rs.sys.utils;import java.io.BufferedInputStream;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;import java.io.OutputStream;import java.util.ArrayList;import java.util.List;import javax.servlet.ServletOutputStream;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.apache.poi.hssf.usermodel.HSSFCell;import org.apache.poi.hssf.usermodel.HSSFCellStyle;import org.apache.poi.hssf.usermodel.HSSFRichTextString;import org.apache.poi.hssf.usermodel.HSSFRow;import org.apache.poi.hssf.usermodel.HSSFSheet;import org.apache.poi.hssf.usermodel.HSSFWorkbook;import org.apache.poi.hssf.util.HSSFColor;import org.apache.poi.ss.usermodel.Cell;import org.apache.poi.ss.usermodel.Workbook;import org.apache.poi.ss.util.CellRangeAddress;import org.springframework.web.multipart.MultipartFile;/** * <b>处理excel文件的工具类</b> * @author GQ * @date 2016年12月27日 上午10:39:56 * @status */public class ExcelUtils {    /**     * 方法描述:用于下载文件,根据存在的文件绝对路径下载.<br>     * 返回类型:void<br>     * 作者:GQ<br>     * 创建时间:2016年12月27日上午10:51:17     * @param filePath  欲下载的文件绝对路径.<br>如:"F:\apache-tomcat-7.0.70\webapps\Rs_sys\WEB-INF\download\xxx.xls"     * @param request   request请求     * @param response  response请求<br>     */    public static void download(String filePath,HttpServletRequest request,HttpServletResponse response){        HSSFWorkbook workbook=null;        ServletOutputStream sos=null;        try {            File file = new File(filePath);            if (!file.exists()) {                response.sendError(404, "File not found!");                return;            }            BufferedInputStream br = new BufferedInputStream(new FileInputStream(                    filePath));            String downLoadName = null;            String agent = request.getHeader("USER-AGENT");            if (null != agent && -1 != agent.indexOf("MSIE")) // IE            {                downLoadName = java.net.URLEncoder.encode(file.getName(), "UTF-8");            } else if (null != agent && -1 != agent.indexOf("Mozilla")) // Firefox            {                downLoadName = new String(file.getName().getBytes("UTF-8"),                        "iso-8859-1");            } else {                downLoadName = java.net.URLEncoder.encode(file.getName(), "UTF-8");            }            byte[] buf = new byte[1024];            int len = 0;            response.reset();            response.setContentType("application/vnd.ms-excel;charset=UTF-8");            response.setHeader("Content-Disposition", "attachment; filename="                    + downLoadName);            OutputStream out = response.getOutputStream();            while ((len = br.read(buf)) > 0) {                out.write(buf, 0, len);            }            br.close();            out.close();        }catch (Exception e) {            e.printStackTrace();        }finally{            try {                if (null != workbook) {                    workbook.close();                }                if(null!=sos){                    sos.close();                }            } catch (IOException e) {                e.printStackTrace();            }        }    }    /**     * 方法描述:获取单元格中的数据,根据存储的值的类型不同,调用相应的方法获取数据,最后返回一个字符串类型的数据<br>     * 返回类型:String<br>     * 作者:GQ<br>     * 创建时间:2016年12月28日下午6:24:00     * @param cell 单元格     * @return<br>     */    public static String getCellValue(Cell cell) {        String cellValue = "";        //DecimalFormat df = new DecimalFormat("#");        switch (cell.getCellType()) {            case HSSFCell.CELL_TYPE_STRING:                cellValue = cell.getRichStringCellValue().getString().trim();                break;            case HSSFCell.CELL_TYPE_NUMERIC:                cellValue = String.valueOf(new Integer((int)cell.getNumericCellValue()));                break;            case HSSFCell.CELL_TYPE_BOOLEAN:                cellValue = String.valueOf(cell.getBooleanCellValue()).trim();                break;            case HSSFCell.CELL_TYPE_FORMULA:                cellValue = cell.getCellFormula();                break;            default:                cellValue = "";        }        return cellValue;    }        /**     * 方法描述:文件写入<br>     * 返回类型:void<br>     * 作者:GQ<br>     * 创建时间:2016年12月30日下午1:41:24     * @param file       为获得到的文件(也就是要讲这个文件写到哪里)     * @param filePath   文件写入的位置     * @param fileName<br>  文件的名     */    public static void write(MultipartFile file,String filePath,String fileName){        //在指定目录下建立一个空的文件,作用:别的file文件往里写入        File targetFile = new File(filePath, fileName);        if(!targetFile.exists()){            targetFile.mkdirs();        }        //保存        try {            //将前台传过来的file文件写到targetFile中.            file.transferTo(targetFile);        } catch (Exception e) {            e.printStackTrace();        }    }        /**     * 方法描述:创建行,rowNum控制创建第几行.sheet控制在哪个工作簿上创建<br>     * 返回类型:HSSFRow<br>     * 作者:GQ<br>     * 创建时间:2017年1月3日下午4:58:09     * @param sheet    工作簿     * @param rowNum   行数(下标从0开始)     * @return<br>     */    public static HSSFRow createRow(HSSFSheet sheet,int rowNum) {        return sheet.getRow(rowNum)!=null?sheet.getRow(rowNum):sheet.createRow(rowNum);    }    /**     * 方法描述:创建一个cell,样式,值.<br>     * 返回类型:void<br>     * 作者:GQ<br>     * 创建时间:2017年1月3日下午4:02:32<br>     * @param cellnum  第几个cell,下标从0开始,即0代表第一个<br>     * @param value    该cell的值<br>     * @param row      行<br>     * @param style    样式(采用哪个样式)<br>     */    public static HSSFCell createCell(HSSFSheet sheet, int rowNumm, int cellNum, HSSFCellStyle style, String value) {        HSSFRow row = createRow(sheet,rowNumm);        HSSFCell cell = row.createCell((short) cellNum);        cell.setCellValue(new HSSFRichTextString(value));        cell.setCellStyle(style);        return cell;    }    /**     * 方法描述:创建多个单元格.必须是同一行的.并赋值上相应数据<br>     * 返回类型:HSSFCell<br>     * 作者:GQ<br>     * 创建时间:2017年1月3日下午5:21:52     * @param sheet          工作簿     * @param rowNumm        行数     * @param cellNums       要创建的单元格下标数组     * @param style          样式     * @param values         单元格下标对应的值,一个对应一个,顺序不能乱     */    public static List<HSSFCell> createMultiCell(HSSFSheet sheet, int rowNumm, Integer[] cellNums, HSSFCellStyle style, String[] values) {        List<HSSFCell> cellList = new ArrayList<HSSFCell>();        for(int i=0;i<cellNums.length;i++){            HSSFCell cell = createCell(sheet , rowNumm , cellNums[i] , style , values[i]);            cellList.add(cell);        }        return cellList;    }    /**     * 方法描述:创建自定义cell单元格的基础样式.<br>     * 返回类型:HSSFCellStyle<br>     * 作者:GQ<br>     * 创建时间:2017年1月3日下午4:04:02     * @param workbook     */    public static HSSFCellStyle getCellStyle(HSSFWorkbook workbook) {        /*//设置字体;        HSSFFont font = workbook.createFont();        //设置字体大小;        font.setFontHeightInPoints((short) 5);        //设置字体名字;        font.setFontName("Courier New");*/        //font.setItalic(true);        //font.setStrikeout(true);        //设置样式;        HSSFCellStyle style = workbook.createCellStyle();        //设置底边框;        style.setBorderBottom(HSSFCellStyle.BORDER_THIN);        //设置底边框颜色;        style.setBottomBorderColor(HSSFColor.BLACK.index);        //设置左边框;        style.setBorderLeft(HSSFCellStyle.BORDER_THIN);        //设置左边框颜色;        style.setLeftBorderColor(HSSFColor.BLACK.index);        //设置右边框;        style.setBorderRight(HSSFCellStyle.BORDER_THIN);        //设置右边框颜色;        style.setRightBorderColor(HSSFColor.BLACK.index);        //设置顶边框;        style.setBorderTop(HSSFCellStyle.BORDER_THIN);        //设置顶边框颜色;        style.setTopBorderColor(HSSFColor.BLACK.index);        //在样式用应用设置的字体;        //style.setFont(font);        //设置自动换行;        style.setWrapText(true);        //设置水平对齐的样式为居中对齐;        style.setAlignment(HSSFCellStyle.ALIGN_CENTER);        //设置垂直对齐的样式为居中对齐;        style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);        return style;    }    /**     * 方法描述:自定义设置标题样式,只有下边框<br>     * 返回类型:HSSFCellStyle<br>     * 作者:GQ<br>     * 创建时间:2017年1月3日下午4:20:42<br>     * @param workbook<br>     */    public static HSSFCellStyle getTitleStyle(HSSFWorkbook workbook){        HSSFCellStyle style = workbook.createCellStyle();        style.setAlignment(HSSFCellStyle.ALIGN_CENTER); // 创建一个居中格式        // 设置标题只有下边框        style.setBorderBottom(HSSFCellStyle.BORDER_THIN);        return style;    }    /**     * 方法描述:合并单元格<br>     * 返回类型:int<br>     * 作者:GQ<br>     * 创建时间:2017年1月4日上午10:45:20<br>     * @param sheet         工作簿<br>     * @param firstRow      合并起止行(下标从0开始)<br>     * @param lastRow       合并截止行(下标从0开始)<br>     * @param firstCol      合并起止列(下标从0开始)<br>     * @param lastCol       合并截止列(下标从0开始)<br>     */    public static int mergedRegion(HSSFSheet sheet,int firstRow, int lastRow, int firstCol, int lastCol){        return sheet.addMergedRegion(new CellRangeAddress(firstRow,lastRow,firstCol,lastCol));    }    /**     * 方法描述:将生成好的excel文件,写入到指定路径下的文件中.<br>     * 返回类型:void<br>     * 作者:GQ<br>     * 创建时间:2017年1月4日上午10:57:04<br>     * @param wb                一个workbook,对应一个Excel文件<br>     * @param absolutePath      excel文件的绝对路径<br>     */    public static void writeExcelToLocation(HSSFWorkbook wb,String absolutePath){        try {            FileOutputStream fout = new FileOutputStream(absolutePath);            wb.write(fout);            fout.close();        } catch (Exception e) {            e.printStackTrace();        }    }        /**     * 方法描述:获取workbook,将文件转换为workbook对象<br>     * 返回类型:Workbook<br>     * 作者:GQ<br>     * 创建时间:2017年1月4日下午5:12:20<br>     * @param absolutePath              文件的绝对路径(excel文件)<br>     * @return<br>     */    public static Workbook getWorkBook(String absolutePath){        FileInputStream fis =null;        Workbook wb = null;        try{            // 获取一个绝对地址的流            fis = new FileInputStream(absolutePath);            wb = new HSSFWorkbook(fis);        }catch(IOException e){            // TODO Auto-generated catch block            e.printStackTrace();        }                return wb;    }    }
前台需要注意:

用的是表单提交.代码如下:

<form id="news_scheme_manage_excel_export">        <input type="hidden" value=""></input>    </form>
js代码:

//返回被选中的行数据,没有则返回空
var rows = $('#news_scheme_manage').datagrid('getSelections'); 
if(rows!=null && rows.length==1){
var row = $('#news_scheme_manage').datagrid('getSelected');
        //id用于查询方案对应的类型       var id=row.id;       console.log("id:"+id);       //到弹出框中进行编辑       //类选择器获取表单.        var form = $( "#news_scheme_manage_excel_export" );       //设置表单中的相应属性       //设置提交方式为post.       form.attr( "method", "post" );       //设置提交按钮跳转地址        form.attr( "action", "newsSchemes/export/"+id );       //若以上判断返回非false则表单提交.        form.submit();                 
     }else{       //选中多条或者没有选则弹出提示信息       $.messager.alert("提示信息","有且只能选择一条数据!","info"); }

特殊声明:博主第一次写,格式什么的不要介意,只是自己的一个笔记,有些地方可能说的不是很明白,可能存在很多漏洞或者bug,还望多多包涵.希望会给刚入门的同学一点点启示作用.谢谢











0 0
原创粉丝点击