Java与报表知识概括

本文详细介绍了Java处理各类报表的技巧,包括使用Apache POI操作Excel、CSV、Word文档,以及EasyPOI的简化操作,还涉及了PDF文档生成和图表报表的创建。文章深入探讨了Excel的版本差异、数据导入导出、模板处理和大型数据量的解决方案,同时也提到了CSV文件的读写、Word模板的使用,并推荐了JasperReport作为生成PDF报表的工具。
摘要由CSDN通过智能技术生成

Excel表格(POI)

Excel报表简介:

  • 在企业级应用开发中,Excel报表是一种最常见的报表需求。Excel报表开发一般分为两种形式:
    ①为了方便操作,基于Excel的报表批量上传数据,也就是把Excel中的数据导入到系统中。
    ②通过java代码生成Excel报表。也就是把系统中的数据导出到Excel中,方便查阅。
  • Excel的两种版本:目前世面上的Excel分为两个大的版本Excel2003和Excel2007及以上两个版本,两者之间的区别如下:
    ①Excel2003 是一个特有的二进制格式,其核心结构是复合文档类型的结构,存储数据量较小;
    ②Excel2007 的核心结构是 XML 类型的结构,采用的是基于 XML 的压缩方式,使其占用的空间更小,操作效率更高
  • 常见的Excel操作工具:
    ①JXL:JXL只能对Excel进行操作,属于比较老的框架,它只支持到Excel 95-2000的版本。现在已经停止更新和维护。
    POI:POI是apache的项目,可对微软的Word,Excel,PPT进行操作,包括office2003和2007,Excle2003和2007。poi现在一直有更新。所以现在主流使用POI。
    <1>Apache POI是Apache软件基金会的开源项目,由Java编写的免费开源的跨平台的 Java API,Apache POI提供API给Java语言操作Microsoft Office的功能。
    <2>API对象介绍:
    1、工作簿 : WorkBook (HSSFWordBook : 2003版本,XSSFWorkBook : 2007级以上)
    2、工作表 : Sheet (HSSFSheet : 2003版本,XSSFSheet : 2007级以上)
    3、行 : Row (HSSFRow : 2003版本,XSSFRow : 2007级以上)
    4、单元格 : Cell (HSSFCell : 2003版本,XSSFCell : 2007级以上)
    4、单元格样式:Style(HSSFCellStyle:2003版本,XSSFCellStyle:2007级以上)

Excel报表数据导出与导入:

  • 导入思路:
    ①一般来说,即将导入的文件,每个列代表什么意思基本上都是固定的,比如第1列就是用户姓名,最后一列就是用户的现住址,并且在做excel时对每个列的类型都是有要求的,这样就可以给我们开发带来很大的简便。
    ②最终的目标就是读取每一行数据,把数据转成用户的对象,保存到表中
    ③实现的步骤:
    <1>根据上传的文件创建Workbook
    <2>获取到第一个sheet工作表
    <3>从第二行开始读取数据
    <4>读取每一个单元格,把内容放入到用户对象的相关的属性中
  • 导出基本思路:
    ①创建一个全新的工作薄
    ②在新的工作薄中创建一个新的工作表
    ③在工作表创建第一行作为标题行,标题固定
    ④从第二行循环遍历创建,有多少条用户数据就应该创建多少行
    ⑤把每一个user对象的属性放入到相应的单元格中

导出时样式的设置:

  • 画框线
HSSFCellStyle contentStyle = book.createCellStyle();
contentStyle.setBorderBottom(HSSFCellStyle.BORDER_THIN);//底线
contentStyle.setBorderTop(HSSFCellStyle.BORDER_THIN);//顶部线
contentStyle.setBorderLeft(HSSFCellStyle.BORDER_THIN);//左侧线
contentStyle.setBorderRight(HSSFCellStyle.BORDER_THIN);//右侧线
  • 合并单元格
//合并单元格 起始行, 结束行, 起始列, 结束列		
sheet.addMergedRegion(new CellRangeAddress(0,0,0,4));
  • 设置行高
sheet.getRow(1).setHeight((short)500);
  • 设置表格的对齐方式和字体
//内容部分的样式
style_content.setAlignment(HSSFCellStyle.ALIGN_CENTER);//设置水平居中
style_content.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);//设置垂直居中

HSSFFont font = book.createFont();//创建字体
font.setFontName("宋体");//设置字体名称
font.setFontHeightInPoints((short)11);//设置字体大小
style_content.setFont(font);//对样式设置字体
        
//标题样式
HSSFCellStyle style_title = book.createCellStyle();//创建标题样式
style_title.setAlignment(HSSFCellStyle.ALIGN_CENTER);//设置水平居中
style_title.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);//设置垂直居中
HSSFFont titleFont = book.createFont();//设置标题字体
titleFont.setFontName("黑体");
titleFont.setBold(true);//加粗
titleFont.setFontHeightInPoints((short)18);//字体大小    
style_title.setFont(titleFont);//将标题字体设置到标题样式
sheet.getRow(0).getCell(0).setCellStyle(style_title);//单元格设置标题样式

POI高级操作:

  • 基于模板导出列表数据:
    ①首先准备一个excel模板,这个模板把复杂的样式和固定的内容先准备好并且放入到项目中,然后读取到模板后向里面放入数据。
  • 导出数据带图片:
    ①POI主要提供了两个类来处理照片,这两个类是Patriarch和ClientAnchor前者负责在表中创建图片,后者负责设置图片的大小位置。
    ②关于XSSFClientAnchor的8个参数说明:
    <1>dx1 - the x coordinate within the first cell.//定义了图片在第一个cell内的偏移x坐标,既左上角所在cell的偏移x坐标,一般可设0
    <2>dy1 - the y coordinate within the first cell.//定义了图片在第一个cell的偏移y坐标,既左上角所在cell的偏移y坐标,一般可设0
    <3>dx2 - the x coordinate within the second cell.//定义了图片在第二个cell的偏移x坐标,既右下角所在cell的偏移x坐标,一般可设0
    <4>dy2 - the y coordinate within the second cell.//定义了图片在第二个cell的偏移y坐标,既右下角所在cell的偏移y坐标,一般可设0
    <5>col1 - the column (0 based) of the first cell.//第一个cell所在列,既图片左上角所在列
    <6>row1 - the row (0 based) of the first cell.//图片左上角所在行
    <7>col2 - the column (0 based) of the second cell.//图片右下角所在列
    <8>row2 - the row (0 based) of the second cell.//图片右下角所在行
// 先创建一个字节输出流
ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream();
// BufferedImage是一个带缓冲区图像类,主要作用是将一幅图片加载到内存中
BufferedImage bufferImg = ImageIO.read(new File(rootPath + user.getPhoto()));
// 把读取到图像放入到输出流中
ImageIO.write(bufferImg, "jpg", byteArrayOut);
// 创建一个绘图控制类,负责画图
Drawing patriarch = sheet.createDrawingPatriarch();
// 指定把图片放到哪个位置
ClientAnchor anchor = new XSSFClientAnchor(0, 0, 0, 0, 2, 1, 4, 5);
// 开始把图片写入到sheet指定的位置
patriarch.createPicture(anchor, workbook.addPicture(
    byteArrayOut.toByteArray(), Workbook.PICTURE_TYPE_JPEG));
  • 导出公式:
    ①在使用POI导出时使用setCellFormula方法来设置公式。
    ②POI支持公式:POI官网
    ③ps:其实在正常开发时应该在模板中直接设置好公式,这样打开直接导出的excel文档时公式会直接运行出我们想要的结果
  • 自定义导出详细数据的引擎:
    ①看我们刚才导出时写的代码,必须要提前知道要导出数据在哪一行哪一个单元格,但是如果模板一旦发生调整,那么我们的java代码必须要修改,我们可以自定义个导出的引擎,有了这个引擎即使模板修改了我们的java代码也不用修改
    ②在制作模板时,在需要插入数据的位置我们坐上标记,在导出时,对象的属性要和标记做对应,如果对应匹配一样,就把值赋值到相应的位置。
    在这里插入图片描述

百万数据导出:

  • 我们都知道Excel可以分为早期的Excel2003版本(使用POI的HSSF对象操作)和Excel2007版本(使用POI的XSSF操作),两者对百万数据的支持如下:
    ①Excel 2003:在POI中使用HSSF对象时,excel 2003最多只允许存储65536条数据,一般用来处理较少的数据量。这时对于百万级别数据,Excel肯定容纳不了。
    ②Excel 2007:当POI升级到XSSF对象时,它可以直接支持excel2007以上版本,因为它采用ooxml格式。这时excel可以支持1048576条数据,单个sheet表就支持近百万条数据。但实际运行时还可能存在问题,原因是执行POI报表所产生的行对象,单元格对象,字体对象,他们都不会销毁,这就导致OOM的风险。

  • 解决方案分析:对于百万数据量的Excel导入导出,只讨论基于Excel2007的解决方法。在ApachePoi 官方提供了对操作大数据量的导入导出的工具和解决办法,操作Excel2007使用XSSF对象,可以分为三种模式:
    ①java代码解析xml
    ②dom4j:一次性加载xml文件再解析
    ③SAX:逐行加载,逐行解析

  • 解决方案:
    ①用户模式:用户模式有许多封装好的方法操作简单,但创建太多的对象,非常耗内存。加载并读取Excel时,是通过一次性的将所有数据加载到内存中再去解析每个单元格内容。当Excel数据量较大时,由于不同的运行环境可能会造成内存不足甚至OOM异常。
    <1>java代码解析xml
    <2>dom4j:一次性加载xml文件再解析
    ②事件模式:基于SAX方式解析XML,SAX全称Simple API for XML,它是一个接口,也是一个软件包。它是一种XML解析的替代方法,不同于DOM解析XML文档时把所有内容一次性加载到内存中的方式,它逐行扫描文档,一边扫描,一边解析。
    <1>SAX:逐行加载,逐行解析

  • SXSSF对象:是用来生成海量excel数据文件,主要原理是借助临时存储空间生成excel

  • 原理分析 :
    ①在实例化SXSSFWorkBook这个对象时,可以指定在内存中所产生的POI导出相关对象的数量(默认100),一旦内存中的对象的个数达到这个指定值时,就将内存中的这些对象的内容写入到磁盘中(XML的文件格式),就可以将这些对象从内存中销毁,以后只要达到这个值,就会以类似的处理方式处理,直至Excel导出完成。

  • 思路分析:
    ①导出时使用的是SXSSFWorkBook这个类,一个工作表sheet最多只能放1048576行数据, 当我们的业务数据已超过100万了,一个sheet就不够用了,必须拆分到多个工作表。
    ②导出百万数据时有两个弊端:
    <1>不能使用模板
    <2>不能使用太多的样式
    ③也就是说导出的数据太多时必须要放弃一些。

  • 步骤分析:
    ①设置POI的事件模式:
    <1>根据Excel获取文件流
    <2>根据文件流创建OPCPackage 用来组合读取到的xml 组合出来的数据占用的空间更小
    <3>创建XSSFReader对象
    ②Sax解析:
    <1>自定义Sheet处理器
    <2>创建Sax的XmlReader对象
    <3>设置Sheet的事件处理器
    <4>逐行读取

--------自定义处理器---------
public class SheetHandler implements XSSFSheetXMLHandler.SheetContentsHandler {

//    编号 用户名  手机号  入职日期 现住址
    private User user=null;
    @Override
    public void startRow(int rowIndex) { //每一行的开始   rowIndex代表的是每一个sheet的行索引
        if(rowIndex==0){
            user = null;
        }else{
            user = new User();
        }
    }
    @Override  //处理每一行的所有单元格
    public void cell(String cellName, String cellValue, XSSFComment comment) {

        if(user!=null){
            String letter = cellName.substring(0, 1);  //每个单元名称的首字母 A  B  C
            switch (letter){
                case "A":{
                    user.setId(Long.parseLong(cellValue));
                    break;
                }
                case "B":{
                    user.setUserName(cellValue);
                    break;
                }
            }
        }
    }
    @Override
    public void endRow(int rowIndex) { //每一行的结束
        if(rowIndex!=0){
            System.out.println(user);
        }

    }
}

--------自定义解析---------
public class ExcelParser {

    public void parse (String path) throws Exception {
        //1.根据Excel获取OPCPackage对象
        OPCPackage pkg = OPCPackage.open(path, PackageAccess.READ);
        try {
            //2.创建XSSFReader对象
            XSSFReader reader = new XSSFReader(pkg);
            //3.获取SharedStringsTable对象
            SharedStringsTable sst = reader.getSharedStringsTable();
            //4.获取StylesTable对象
            StylesTable styles = reader.getStylesTable();
            XMLReader parser = XMLReaderFactory.createXMLReader();
            // 处理公共属性:Sheet名,Sheet合并单元格
            parser.setContentHandler(new XSSFSheetXMLHandler(styles,sst, new SheetHandler(), false));
            XSSFReader.SheetIterator sheets = (XSSFReader.SheetIterator) reader.getSheetsData();
            while (sheets.hasNext()) {
                InputStream sheetstream = sheets.next();
                InputSource sheetSource = new InputSource(sheetstream);
                try {
                    parser.parse(sheetSource);
                } finally {
                    sheetstream.close();
                }
            }
        } finally {
            pkg.close();
        }
    }
}

CSV文件(opencsv)

CSV文件简介:

  • 现在好多的网站中导出的文件会出现一种csv文件,我们接下来学习一下csv文件的导出方式。
  • CSV文件:Comma-Separated Values,中文叫逗号分隔值或者字符分割值,其文件以纯文本的形式存储表格数据。该文件是一个字符序列,可以由任意数目的记录组成,记录间以某种换行符分割。每条记录由字段组成,字段间的分隔符是其他字符或者字符串。所有的记录都有完全相同的字段序列,相当于一个结构化表的纯文本形式。
  • 用文本文件、excel或者类似与文本文件的编辑器都可以打开CSV文件。
  • 为了简化开发,我们可以使用opencsv类库来导出csv文件。
  • 需要的依赖:
<dependency>
    <groupId>com.opencsv</groupId>
    <artifactId>opencsv</artifactId>
    <version>4.5</version>
</dependency>

opencsv常用API:

  • 写入到csv文件会用到CSVWriter对象,创建此对象常见API如下:
    在这里插入图片描述
  • 使用CSVWriter对象写入数据常用的方法如下:
    在这里插入图片描述
  • 读取csv文件会用到CSVReader对象,创建此对象常见API如下:
    在这里插入图片描述
  • 构造器涉及到的三个参数:
    ①reader:读取文件的流对象,常有的是BufferedReader,InputStreamReader。
    ②separator:用于定义前面提到的分割符,默认为逗号CSVWriter.DEFAULT_SEPARATOR用于分割各列。
    ③quotechar:用于定义各个列的引号,有时候csv文件中会用引号或者其它符号将一个列引起来,例如一行可能是:“1”,“2”,“3”,如果想读出的字符不包含引号,就可以把参数设为:"CSVWriter.NO_QUOTE_CHARACTER "
  • read方法:
    在这里插入图片描述

导出与读取CSV文件:

//导出CSV文件
public void downLoadCSV(HttpServletResponse response) {

    try {
        //            准备输出流
        ServletOutputStream outputStream = response.getOutputStream();
        //            文件名
        String filename="百万数据.csv";
        //            设置两个头 一个是文件的打开方式 一个是mime类型
        response.setHeader( "Content-Disposition", "attachment;filename="  + new String(filename.getBytes(),"ISO8859-1"));
        response.setContentType("text/csv");
        //            创建一个用来写入到csv文件中的writer
        CSVWriter writer = new CSVWriter(new OutputStreamWriter(outputStream,"utf-8"));
        //            先写头信息
        writer.writeNext(new String[]{"编号&
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值