zoukankan      html  css  js  c++  java
  • poi

    -----

    这是导出时,容易出现的问题,后面说到

     设置字符编码:

    Font font =wb.createFont();
    font.setCharSet(font.ANSI_CHARSET);//注意这地方不能手写数字,这是常量



     

    开始正文

    一、黑历史

    为什么要做excel打印:就是为了客户需求,有的客户习惯excel。

    java操作excel主要分两类:

    1、(全方位操作用)poi大概就是:属于apache的产品,操作microsoft excel word,ppt,visio等微软旗下所有的工具,支持office所有版本。

    但是在poi早期,当时微软产品都时OLE2结构(底层就是2进制)文件,这是office2003以前;然而poi操作大数据时,就会有bug,然而jxl也是这种数据结构,但可以解决这问题,所以jxl当时比office厉害。

    从office2007开始,微软就重新开发了office,底层使用OOXML结构,这种数据结构,可以操作大数据,所以excel底层就是xml格式文件。

    2、(一般导入导出数据时用)jxl时仅用来操作excel,并且仅支持2003以下版本,不支持2007,也仅仅时OLE2文档结构。

     二、jar准备

            <dependency>
                <groupId>org.apache.poi</groupId>
                <artifactId>poi</artifactId>
                <version>3.9</version>
            </dependency>
            <dependency>
                <groupId>org.apache.poi</groupId>
                <artifactId>poi-ooxml</artifactId>
                <version>3.9</version>
            </dependency>

    三、怎么使用(本质就是将内存中的数据通过流的方式写到硬盘上)

      1、训练

     第一节认清:excel怎么创建表然后怎么写内容然后再保存文件

    • 创建一个工作簿
    • 创建一个工作表,默认是3个工作表
    • 定位哪一个行
    • 定位哪一列
    • 单元格写内容(这前面5步都是在内存中进行的,不要被表面迷惑)
    • 点击保存(这将内存中数据序列化到硬盘上)
    • 关闭

     第二节:设置单元格内容

     

    Workbook wb =new HSSFWorkbook();
        Sheet sh = wb.createSheet();
        Row row = sh.createRow(1);
        Cell cell = row.createCell(1);
        cell.setCellValue("我是中国人");
        FileOutputStream op =new FileOutputStream("D:\B.xls");
        wb.write(op);执行完这一步,内容就写到硬盘上,即B.xls创建了
        op.close(); 如果还没执行这一步,那么excel进程提示被占用,不能编辑。关闭流后,才可以操作excel

    第三节:设置样式(这和设置内容是不同的东西)--------重点

    CellStyle cs=wb.createCellStyle();//注意这方法是工作簿的,单元格样式,excel无论是合并还是什么的都是单元格,还有边框,背景色等等都是样式,所以样式就是全局的
        Font font=wb.createFont();//创建字体,也只能工作簿拥有,是全局的,字体无论在哪一张工作表都是拥有工作簿提供的所有字体,所以这个方法只能是工作簿的
        font.setFontName("微软雅黑");//设置字体
        font.setFontHeightInPoints((short)24);//设置字体高度值点数,就是设置大小,点数相当于单位-------注意的地方,也可以用setFontHeight,但单位不同,需要换算,所以统一用setFontHeightInPoints,
        cs.setFont(font);设置字体样式
        cell.setCellStyle(cs);//设置单元格样式
    创建样式对象-->创建字体对象-->设置字体对象各种样式-->设置字体-->设置单元格样式

     第四节:优化代码

    为了避免重复new对象,造成内存损失,可以引用利用(引用被利用,没有被引用指向的对象会被垃圾回收期回收)java是一个引用同时间只能指向一个对象(不然虚拟机不知道调用那个对象),多个对象可以指向一个引用

    A  n =  new Hero(); 

    n =  new Hero();//同一个引用garen指向新创建的对象,上面那个对象就会被垃圾回收机制回收(多个对象可以指向一个引用)

    1设置单元格内容再利用:

         row1 = sh.createRow(2); 再利用 row引用
         cell2 = row1.createCell(2);在利用cell引用
        cell2.setCellValue("woshizhongguoren ");

    2设置样式再利用(因为是全局的,所以会出现后者覆盖前者,所以不能直接利用font,cs,)

    所以必须font 和cs初始化

    font= wb.createFont();再利用font引用
    cs = wb.createCellStyle();再利用cs引用
    font.setFontHeightInPoints((short)18);
    font.setFontName("隶书");
    font.setBoldweight(Font.BOLDWEIGHT_BOLD);
    cs.setFont(font);
    cell.setCellStyle(cs);


     以上代码可以抽取出来:

    excel 标题样式一般相同,内容样式一般相同,简化代码,每次调用方法前,初始化对象

    Workbook wb =new HSSFWorkbook();
        Sheet sh = wb.createSheet();
        
        Row row = sh.createRow(1);
        Cell cell = row.createCell(1);
        cell.setCellValue("我是中国人");
        CellStyle cs=wb.createCellStyle();        
        Font font=wb.createFont();
        this.getCellStylefont(font, cs, cell);
        
        
       初始化: 
        row = sh.createRow(2);
        cell = row.createCell(2);
        cell.setCellValue("woshizhongguoren ");
         font= wb.createFont();
         cs = wb.createCellStyle();
         this.getCellStyletext(font, cs, cell);
    这是excel标题
    public
    CellStyle getCellStyleTitle(Font font,CellStyle cs,Cell cell){ font.setFontHeightInPoints((short)18); font.setFontName("隶书"); font.setBoldweight(Font.BOLDWEIGHT_BOLD); cs.setFont(font); cell.setCellStyle(cs); return cs; }
    这是excel 内容
    public
    CellStyle getCellStyletext(Font font,CellStyle cs,Cell cell){ font.setFontName("微软雅黑"); font.setFontHeightInPoints((short)85); cs.setFont(font); cell.setCellStyle(cs); return cs; }

      2、项目运用

     打印一张出货表:

    日期处理可以数据库处理,也可以在poi处理

    加个链接,添加打印按钮,根据日期,后台通过sql查询,返回list集合,通过循环遍历导出一张excel表

    添加单元格数据:

    List<OutProduct> outProductList = outProductService.find(paraMap);
            HSSFWorkbook wb =new HSSFWorkbook();
            HSSFSheet sh = wb.createSheet();
            int i=1;  //定义列起始索引
            int j=0;//定义行起始索引
            HSSFRow cr ;//声明行局部变量
            HSSFCell cc;//声明单元格局部变量
            String[] arr=new String[]{"客户","订单号","货号","数量","工厂","工厂交期","船期","贸易条款"};  //标题栏
            cr=sh.createRow(j++);
            for (String val : arr) {
                cc=cr.createCell(i++);
                cc.setCellValue(val);
            }
            for(OutProduct op: outProductList){                                                    //数据栏
                i=1;  //初始化列起始索引
                cr=sh.createRow(j++); j++就是j先赋值,然后再自增
                cc=cr.createCell(i++);
                String customName = op.getCustomName();
                cc.setCellValue(customName);
                
                cc=cr.createCell(i++);
                String contractNo = op.getContractNo();
                cc.setCellValue(contractNo);
                
                cc=cr.createCell(i++);
                String productNo = op.getProductNo();
                cc.setCellValue(productNo);
                
                cc=cr.createCell(i++);
                String boxNum = op.getBoxNum();
                cc.setCellValue(boxNum);
                
                cc=cr.createCell(i++);
                String factoryName = op.getFactoryName();
                cc.setCellValue(factoryName);
                
                cc=cr.createCell(i++);
                String deliveryPeriod = op.getDeliveryPeriod();
                cc.setCellValue(deliveryPeriod);
                
                cc=cr.createCell(i++);
                String shipTime = op.getShipTime();
                cc.setCellValue(shipTime);
                
                cc=cr.createCell(i++);
                String tradeTerms = op.getTradeTerms();
                cc.setCellValue(tradeTerms);
                
                
            }
            OutputStream out =new FileOutputStream("d://a.xls");
            wb.write(out);
            out.close();

    这里可以看出j++好处,中间插入一个大标题,下面的内容自动往下移动

    这部分仍是添加单元格内容:大标题是合并单元格,

    所以表格的合并单元格方法,指定4个参数,起始行,结束行,起始列,结束列

    然后怎么做到“2018年8月份出货表”,时间是动态的,前台传过来的,

    replaceFirst成功则返回替换的字符串,失败则返回原始字符串,所以要先进行-0替换,大范围替换,没有0则返回原始字符串,然后小范围-替换成年

        sh.addMergedRegion(new CellRangeAddress(0, 0, 1, 8)); //合并单元格默认是设置在区域的第一行第一列
            cr=sh.createRow(j++);
            cc=cr.createCell(1);
            cc.setCellValue(pdate.replaceFirst("-0", "年").replaceFirst("-", "年")+"月份出货表");

     添加单元格样式:

     设置字体和样式:

    这两个对象都是workbook对象创建的,字体包含在样式中

    HSSFCellStyle nstyle = wb.createCellStyle();
            HSSFFont nfont = wb.createFont();
            bigTitle(wb, nstyle, nfont);
            cc.setCellStyle(nstyle);

    行高是行对象创建,

    cr.setHeightInPoints(36);

     字体加粗是字体对象

    单元格内容居中这是样式对象,样式CellStyle中有横向和竖向常量

    public void bigTitle(Workbook wb,CellStyle nstyle,Font nfont){
            nfont.setFontHeightInPoints((short)16);
            nfont.setFontName("宋体");
            nstyle.setFont(nfont);
            nfont.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);//加粗,这是常量,是HSSFFont类中的常量

    nstyle.setAlignment(CellStyle.ALIGN_CENTER);横向居中
    nstyle.setVerticalAlignment(CellStyle.VERTICAL_CENTER);纵向居中

    
        }
    	设置边框
    		nstyle.setBorderBottom(CellStyle.BORDER_THIN);
    		nstyle.setBorderLeft(CellStyle.BORDER_THIN);
    		nstyle.setBorderRight(CellStyle.BORDER_THIN);
    		nstyle.setBorderTop(CellStyle.BORDER_THIN);
    

      分大标题 标题 正文设置样式,每次设置样式钱需要初始化,

         初始化  nstyle = wb.createCellStyle();
    		nfont = wb.createFont();
    		
    

      

    public void bigTitle(Workbook wb,CellStyle nstyle,Font nfont){
            nfont.setFontHeightInPoints((short)16);
            nfont.setFontName("宋体");
            nfont.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
            nstyle.setAlignment(CellStyle.ALIGN_CENTER);
            nstyle.setVerticalAlignment(CellStyle.VERTICAL_CENTER);
            nstyle.setFont(nfont);
            
        }
        public CellStyle title(Workbook wb,CellStyle nstyle,Font nfont){
            nfont.setFontHeightInPoints((short)12);
            nfont.setFontName("黑体");
            
            nstyle.setAlignment(CellStyle.ALIGN_CENTER);
            nstyle.setVerticalAlignment(CellStyle.VERTICAL_CENTER);
            
            nstyle.setBorderBottom(CellStyle.BORDER_THIN);
            nstyle.setBorderLeft(CellStyle.BORDER_THIN);
            nstyle.setBorderRight(CellStyle.BORDER_THIN);
            nstyle.setBorderTop(CellStyle.BORDER_THIN);
            nstyle.setFont(nfont);
            return nstyle;
            
        }
        public CellStyle text(Workbook wb,CellStyle nstyle,Font nfont){
            nfont.setFontHeightInPoints((short)10);
            nfont.setFontName("Times New Roman");
            nstyle.setAlignment(CellStyle.ALIGN_LEFT);
            nstyle.setVerticalAlignment(CellStyle.VERTICAL_CENTER);
            nstyle.setFont(nfont);
            return nstyle;
        }

     列宽特殊,这是表对象的,sheet:通过源码可以得出,需要乘以256,这是api bug

    然而还是差那么一点点,这是poi一个bug,不能够精确。所以经过测试一般接近准确*300,

     a列是为了装订线的位置

    打印时,不能在一页显示,可以设置横向,拖到一页,可以设置页面方向

    设置页眉页脚,设置重复标题行


     上面所说的都是下载,用户体验不好,项目中都是模板开发,用户需求变更,只要改变模板上的样式,并且模板的样式都是通过excel手动设置,不需要在代码中设置,代码中只要获取一行模板样式,后面的内容全设置成模板样式就可以了,

    可以解决上面所有问题。不然每次输出的文件在服务器端,用户没法看,

     项目上传下载 用工具类


     

            ByteArrayOutputStream bo=new ByteArrayOutputStream();
            wb.write(bo);
            
            DownloadUtil du=new DownloadUtil();
            du.download(bo, response, "出货表.xls");
    工具类: * @param byteArrayOutputStream 将文件内容写入ByteArrayOutputStream
         * @param response HttpServletResponse    写入response
         * @param returnName 返回的文件名
         */
        public void download(ByteArrayOutputStream byteArrayOutputStream, HttpServletResponse response, String returnName) throws IOException{
            response.setContentType("application/octet-stream;charset=utf-8");
            returnName = response.encodeURL(new String(returnName.getBytes(),"iso8859-1"));            //保存的文件名,必须和页面编码一致,否则乱码
            response.addHeader("Content-Disposition",   "attachment;filename=" + returnName);  
            response.setContentLength(byteArrayOutputStream.size());
            
            ServletOutputStream outputstream = response.getOutputStream();    //取得输出流
            byteArrayOutputStream.writeTo(outputstream);                    //写到输出流
            byteArrayOutputStream.close();                                    //关闭
            outputstream.flush();                                            //刷数据
        }

     通过模板开发:下面是模板

    主要步骤:读取服务器上的模板文件到内存中,然后在内存中对内存中的模板进行大标题:设置动态值,标题:不用管了,用内存中模板标题,内容上:设置内容、样式和模板一行内容样式一样

        @RequestMapping("/cargo/outproduct/outProductPrint.action")
        public void print(String inputDate, HttpServletResponse response) throws FileNotFoundException, IOException, ParseException{
            /*
             * 操作步骤:
             * 1、获取数据
             * 2、POI写数据到文件
             */
            List<OutProduct> oList = outProductService.findOutProduct(inputDate+"%");
            
            Workbook wb = new HSSFWorkbook(new FileInputStream(new File("c:\tFACTORY.xls")));                //打开模板文件
            Sheet sheet = wb.getSheetAt(0);                        //打开第一个工作表
            Row nRow = null;
            Cell nCell = null;
            int rowNo = 2;                                        //行号
            int colNo = 1;                                        //列号
            
            //处理标题
            nRow = sheet.getRow(0);                                //获得行对象
            nCell = nRow.getCell(1);                            //获得单元格对象
            nCell.setCellValue(inputDate.replaceFirst("-0", "-").replaceFirst("-", "年")+"月份出货表");            //yyyy-MM 2010-08
            
            //获取模板文件中的样式
            nRow = sheet.getRow(2);
            nCell = nRow.getCell(1);
            CellStyle customNameStyle = nCell.getCellStyle();            //获取客户名称样式
            
            nRow = sheet.getRow(2);
            nCell = nRow.getCell(2);
            CellStyle contractNoStyle = nCell.getCellStyle();
            
            nRow = sheet.getRow(2);
            nCell = nRow.getCell(3);
            CellStyle productNoStyle = nCell.getCellStyle();
            
            nRow = sheet.getRow(2);
            nCell = nRow.getCell(4);
            CellStyle cnumberStyle = nCell.getCellStyle();
            
            nRow = sheet.getRow(2);
            nCell = nRow.getCell(5);
            CellStyle factoryStyle = nCell.getCellStyle();
            
            nRow = sheet.getRow(2);
            nCell = nRow.getCell(6);
            CellStyle extStyle = nCell.getCellStyle();
            
            nRow = sheet.getRow(2);
            nCell = nRow.getCell(7);
            CellStyle dateStyle = nCell.getCellStyle();
            
            nRow = sheet.getRow(2);
            nCell = nRow.getCell(9);
            CellStyle tradeTermsStyle = nCell.getCellStyle();
            
            for(int i=0;i<oList.size();i++){
                colNo = 1;
                OutProduct op = oList.get(i);                     //获取每个出货表对象
                
                nRow = sheet.createRow(rowNo++);                //创建行
                nRow.setHeightInPoints(24);                        //行高
                
                nCell = nRow.createCell(colNo++);                //创建单元格
                nCell.setCellValue(op.getCustomName());
                nCell.setCellStyle(customNameStyle);
                
                nCell = nRow.createCell(colNo++);
                nCell.setCellValue(op.getContractNo());
                nCell.setCellStyle(contractNoStyle);
                
                nCell = nRow.createCell(colNo++);
                nCell.setCellValue(op.getProductNo());
                nCell.setCellStyle(productNoStyle);
                
                nCell = nRow.createCell(colNo++);
                nCell.setCellValue(op.getCnumber());
                nCell.setCellStyle(cnumberStyle);
                
                nCell = nRow.createCell(colNo++);
                nCell.setCellValue(op.getFactoryName());
                nCell.setCellStyle(factoryStyle);
                
                nCell = nRow.createCell(colNo++);
                nCell.setCellValue("附件");
    
                List<String> extNameList = outProductService.getExtName(op.getContractProductId());
                String _extName = "";
                if(extNameList!=null&&extNameList.size()>0){
                    for(String extName : extNameList){
                        _extName += extName + "
    ";                //换行符
                    }
                    _extName = _extName.substring(0,_extName.length()-1);        //去掉最后一个字符
                }else{
                    _extName = "无";
                }
                nCell.setCellValue(_extName);
                nCell.setCellStyle(extStyle);
                
                nCell = nRow.createCell(colNo++);
                //nCell.setCellValue(UtilFuns.dateTimeFormat(op.getDeliveryPeriod()));        //利用工具类转类型,同时进行格式化
                nCell.setCellValue(op.getDeliveryPeriod());
                nCell.setCellStyle(dateStyle);
                
                nCell = nRow.createCell(colNo++);
                //nCell.setCellValue(UtilFuns.dateTimeFormat(op.getShipTime()));
                nCell.setCellValue(op.getShipTime());
                nCell.setCellStyle(dateStyle);
                
                nCell = nRow.createCell(colNo++);
                nCell.setCellValue(op.getTradeTerms());
                nCell.setCellStyle(tradeTermsStyle);
            }
            
            
            DownloadUtil du = new DownloadUtil();
    
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();            //生成流对象
            wb.write(byteArrayOutputStream);
            du.download(byteArrayOutputStream, response, "出货表.xls");        //弹出下载框,用户就可以直接下载
        }
        

     下面是导出下载后的结果:

     

    String path=request.getSession().getServletContext().getRealPath("/")+"/make/xlsprint";//必须是/的虚拟路径,不然jdk1.8不会拼接/后面的字符串  ,这红色的斜杠最好加上,多个斜杠,底层会处理,不要紧
            InputStream is =new FileInputStream(new File(path+"/tOUTPRODUCT.xls"));//这里红色/也一样,不加也可以
            HSSFWorkbook wb =new HSSFWorkbook(is);
  • 相关阅读:
    使用openssl搭建CA并颁发服务器证书
    PKCS#1规范阅读笔记2--------公私钥ASN.1结构
    PKCS#1规范阅读笔记1--------基本概念
    Chrome 扩展机制
    Docker部署zookeeper集群和kafka集群,实现互联
    ASP.NET Identity实现分布式Session,Docker+Nginx+Redis+ASP.NET CORE Identity
    Transmission添加SSL访问
    重磅来袭,水木PC客户端全面改版,欢迎使用!
    CLR via C# 3rd
    IL命令
  • 原文地址:https://www.cnblogs.com/fpcbk/p/9808887.html
Copyright © 2011-2022 走看看