Java与报表知识概括

Java与报表知识概括

  • Excel表格(POI)
  • CSV文件(opencsv)
  • word文档(POI)
  • 其他(POI)
  • easyPOI
  • PDF文档
  • 图表报表

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代码也不用修改
    ②在制作模板时,在需要插入数据的位置我们坐上标记,在导出时,对象的属性要和标记做对应,如果对应匹配一样,就把值赋值到相应的位置。
    Java与报表知识概括_第1张图片

百万数据导出:

  • 我们都知道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.opencsvgroupId>
    <artifactId>opencsvartifactId>
    <version>4.5version>
dependency>

opencsv常用API:

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

导出与读取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[]{"编号","姓名","手机号","入职日期","现住址"});

        //            如果文件数据量非常大的时候,我们可以循环查询写入
        int page = 1;
        int pageSize=200000;
        while (true) {  //不停地查询
            List<User> userList = this.findPage(page, pageSize);
            if (CollectionUtils.isEmpty(userList)) {  //如果查询不到就不再查询了
                break;
            }
            //                把查询到的数据转成数组放入到csv文件中
            for (User user : userList) {
                writer.writeNext(new String[]{user.getId().toString(),user.getUserName(),user.getPhone(),simpleDateFormat.format(user.getHireDate()),user.getAddress()});
            }
            writer.flush();
            page++;
        }
        writer.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
}
//读取百万级数据的csv文件
public class CsvDemo {

    private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");

    public static void main(String[] args) throws Exception {
        CSVReader csvReader = new CSVReader(new FileReader("d:\\百万用户数据的导出.csv"));
        String[] titles = csvReader.readNext(); //读取到第一行 是小标题
//        "编号","姓名","手机号","入职日期","现住址"
        User user = null;
        while (true){
            user = new User();
            String[] content = csvReader.readNext();
            if(content==null){
                break;
            }
            user.setId(Long.parseLong(content[0]));
            user.setUserName(content[1]);
            user.setPhone(content[2]);
            user.setHireDate(simpleDateFormat.parse(content[3]));
            user.setAddress(content[4]);
            System.out.println(user);
        }
    }
}

word文档(POI)

POI操作word文档简介:

  • poi对低版本的doc本身支持的就不好所以我们直接说高版本的docx版本的api。
  • poi操作word正文:
    XWPFDocument代表一个docx文档,其可以用来读docx文档,也可以用来写docx文档
    一个文档包含多个段落,一个段落包含多个Runs文本,一个Runs包含多个Run,Run是文档的最小单元
    ③获取所有段落:List paragraphs = word.getParagraphs();
    ④获取一个段落中的所有片段Runs:List xwpfRuns = xwpfParagraph.getRuns();
    ⑤获取一个Runs中的一个Run:XWPFRun run = xwpfRuns.get(index);
  • poi操作word中的表格:
    一个文档包含多个表格,一个表格包含多行,一行包含多列单元格
    ②获取所有表格:List xwpfTables = doc.getTables();
    ③获取一个表格中的所有行:List xwpfTableRows = xwpfTable.getRows();
    ④获取一行中的所有列:List xwpfTableCells = xwpfTableRow.getTableCells();
    ⑤获取一格里的内容:List paragraphs = xwpfTableCell.getParagraphs();
    ⑥之后和正文段落一样

导出与读取word文档:

  • 先准备两个方法:一个是想指定的单元格中放入图片,另一个是 复制word中表格的行。
//    向单元格中写入图片
private void setCellImage(XWPFTableCell cell, File imageFile) {

    XWPFRun run = cell.getParagraphs().get(0).createRun();
    //        InputStream pictureData, int pictureType, String filename, int width, int height
    try(FileInputStream inputStream = new FileInputStream(imageFile)) {
        run.addPicture(inputStream,XWPFDocument.PICTURE_TYPE_JPEG,imageFile.getName(), Units.toEMU(100),Units.toEMU(50));
    } catch (Exception e) {
        e.printStackTrace();
    }

}

//    用于深克隆行
private void copyRow(XWPFTable xwpfTable, XWPFTableRow sourceRow, int rowIndex) {
    XWPFTableRow targetRow = xwpfTable.insertNewTableRow(rowIndex);
    targetRow.getCtRow().setTrPr(sourceRow.getCtRow().getTrPr());
    //        获取源行的单元格
    List<XWPFTableCell> cells = sourceRow.getTableCells();
    if(CollectionUtils.isEmpty(cells)){
        return;
    }
    XWPFTableCell targetCell = null;
    for (XWPFTableCell cell : cells) {
        targetCell = targetRow.addNewTableCell();
        //            附上单元格的样式
        //            单元格的属性
        targetCell.getCTTc().setTcPr(cell.getCTTc().getTcPr());
        targetCell.getParagraphs().get(0).getCTP().setPPr(cell.getParagraphs().get(0).getCTP().getPPr());
    }
}
  • 读取模版填充数据并导出:
public void downloadContract(Long id,HttpServletResponse response) throws Exception {
    //        1、读取到模板
    File rootFile = new File(ResourceUtils.getURL("classpath:").getPath()); //获取项目的根目录
    File templateFile = new File(rootFile, "/word_template/contract_template.docx");
    XWPFDocument word = new XWPFDocument(new FileInputStream(templateFile));
    //        2、查询当前用户User--->map
    User user = this.findById(id);
    Map<String,String> params = new HashMap<>();
    params.put("userName",user.getUserName());
    params.put("hireDate",simpleDateFormat.format(user.getHireDate()));
    params.put("address",user.getAddress());
    //        3、替换数据
    //         处理正文开始
    List<XWPFParagraph> paragraphs = word.getParagraphs();
    for (XWPFParagraph paragraph : paragraphs) {
        List<XWPFRun> runs = paragraph.getRuns();
        for (XWPFRun run : runs) {
            String text = run.getText(0);
            for (String key : params.keySet()) {
                if(text.contains(key)){
                    run.setText(text.replaceAll(key,params.get(key)),0);
                }
            }
        }
    }
    //         处理正文结束

    //      处理表格开始     名称	价值	是否需要归还	照片
    List<Resource> resourceList = user.getResourceList(); //表格中需要的数据
    XWPFTable xwpfTable = word.getTables().get(0);

    XWPFTableRow row = xwpfTable.getRow(0);
    int rowIndex = 1;
    for (Resource resource : resourceList) {
        //        添加行
        //            xwpfTable.addRow(row);
        copyRow(xwpfTable,row,rowIndex);
        XWPFTableRow row1 = xwpfTable.getRow(rowIndex);
        row1.getCell(0).setText(resource.getName());
        row1.getCell(1).setText(resource.getPrice().toString());
        row1.getCell(2).setText(resource.getNeedReturn()?"需求":"不需要");

        File imageFile = new File(rootFile,"/static"+resource.getPhoto());
        setCellImage(row1.getCell(3),imageFile);
        rowIndex++;
    }
    //     处理表格开始结束
    //        4、导出word
    String filename = "员工(" + user.getUserName() + ")合同.docx";
    response.setHeader("content-disposition", "attachment;filename=" + new String(filename.getBytes(), "ISO8859-1"));
    response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
    word.write(response.getOutputStream());
}

其他(POI)

POI简介:

  • 通俗的讲,poi就是批量的操作文件或数据的导入以及导出。
  • Apache POI是Apache软件基金会的开放源码函式库,POI提供API给Java程序对Microsoft Office格式档案读和写的功能。
  • 为什么要用POI?
    举例:
    ①在开发过程中常常有客户这样子要求:你要把我们的报表直接用Excel打开(电信系统、银行系统)。或者是:我们已经习惯用Excel打印。这样在我们实际的开发中,很多时候需要实现导入、导出Excel的应用时。
    ②有大量的报表需要导出(从数据库导出为Excel),另外在做测试的时候又需要往数据库里面导入很多测试数据(从Excel导入数据库)(如数据分析统计)
    ③即将上线的电商网站,大量的基础数据需要录入,人工一条一条录入不太现实,这时候就用到了poi导入。
  • POI链接:
    ①java Poi基础(一)
    ②poiExcel表格所有操作以及数据导入导出

Apache POI结构:

  • HSSF - 提供读写Microsoft Excel格式档案的功能。
  • XSSF - 提供读写Microsoft Excel OOXML格式档案的功能。
  • HWPF - 提供读写Microsoft Word格式档案的功能。
  • HSLF - 提供读写Microsoft PowerPoint格式档案的功能。
  • HDGF - 提供读写Microsoft Visio格式档案的功能。

easyPOI

easyPOI简介:

  • 以上在导出导出excel、导出csv、word时代码有点过于繁琐,好消息是近两年在开发市场上流行一种简化POI开发的类库:easyPOI。从名称上就能发现就是为了简化开发。
  • Excel的快速导入导出,Excel模板导出,Word模板导出,可以仅仅5行代码就可以完成Excel的导入导出,修改导出格式简单粗暴,快速有效。
  • 为谁而开发?
    ①不太熟悉poi的
    ②不想写太多重复太多的
    ③只是简单的导入导出的
    ④喜欢使用模板的
    ⑤都可以使用easypoi
  • 目标是什么?
    ①Easypoi的目标不是替代poi,而是让一个不懂导入导出的快速使用poi完成Excel和word的各种操作,而不是看很多api才可以完成这样工作。
    ②再次强调一下easyPOI完全替代不了POI!
  • 需要的依赖:
easyPOI:
<dependency>
    <groupId>cn.afterturngroupId>
    <artifactId>easypoi-baseartifactId>
    <version>4.1.0version>
dependency>
<dependency>
    <groupId>cn.afterturngroupId>
    <artifactId>easypoi-webartifactId>
    <version>4.1.0version>
dependency>
<dependency>
    <groupId>cn.afterturngroupId>
    <artifactId>easypoi-annotationartifactId>
    <version>4.1.0version>
dependency>

或SpringBoot:
<dependency>
    <groupId>cn.afterturngroupId>
    <artifactId>easypoi-spring-boot-starterartifactId>
    <version>4.1.0version>
dependency>

注解方式导出(excel):

  • 修改实体类,添加注解,其中主要用到的注解是@Excel注解。此处注意必须要有空构造函数,否则会报错“对象创建错误”。
--------员工实体类-------
@Data
@Table(name="tb_user")
public class User {
    @Id
    @KeySql(useGeneratedKeys = true)
    @Excel(name = "编号", orderNum = "0", width = 5)
    private Long id;         //主键
    @Excel(name = "员工名", orderNum = "1", width = 15)
    private String userName; //员工名
    @Excel(name = "手机号", orderNum = "2", width = 15)
    private String phone;    //手机号
    @Excel(name = "省份名", orderNum = "3", width = 15)
    private String province; //省份名
    @Excel(name = "城市名", orderNum = "4", width = 15)
    private String city;     //城市名
    @Excel(name = "工资", orderNum = "5", width = 10)
    private Integer salary;   // 工资
    @JsonFormat(pattern="yyyy-MM-dd")
    @Excel(name = "入职日期",  format = "yyyy-MM-dd",orderNum = "6", width = 15)
    private Date hireDate; // 入职日期
    private String deptId;   //部门id
    @Excel(name = "出生日期",  format = "yyyy-MM-dd",orderNum = "7", width = 15)
    private Date birthday; //出生日期
    @Excel(name = "照片", orderNum = "10",width = 15,type = 2)
    private String photo;    //一寸照片
    @Excel(name = "现在居住地址", orderNum = "9", width = 30)
    private String address;  //现在居住地址

    private List<Resource> resourceList; //办公用品
}

-----------导出方法------------------
public void downLoadXlsxWithEayPoi(HttpServletRequest request, HttpServletResponse response) throws Exception {
    //查询用户数据
    List<User> userList = userMapper.selectAll();
    //指定导出的格式是高版本的格式
    ExportParams exportParams = new ExportParams("员工信息", "数据",ExcelType.XSSF);
    //直接使用EasyPOI提供的方法
    Workbook workbook = ExcelExportUtil.exportExcel(exportParams, User.class, userList);
    String filename="员工信息.xlsx";
    //设置文件的打开方式和mime类型
    ServletOutputStream outputStream = response.getOutputStream();
    response.setHeader( "Content-Disposition", "attachment;filename="  + new String(filename.getBytes(),"ISO8859-1"));
    response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
    workbook.write(outputStream);
}

注解方式导入(excel):

  • Excel导入时需要的参数类ImportParams常用设置说明:
    ①读取指定的sheet 比如要读取上传得第二个sheet 那么需要把startSheetIndex = 1 就可以了
    ②读取几个sheet 比如读取前2个sheet,那么 sheetNum=2 就可以了
    ③读取第二个到第五个sheet 设置 startSheetIndex = 1 然后sheetNum = 4
    ④读取全部的sheet sheetNum 设置大点就可以了
    ⑤保存Excel 设置 needVerfiy = true,默认保存的路径为upload/excelUpload/Test/yyyyMMddHHmss 保存名称上传时间五位随机数 如果自定义路径 修改下saveUrl 就可以了,同时saveUrl也是图片上传时候的保存的路径
    ⑥判断一个Excel是不是合法的Excel importFields 设置下值,就是表示表头必须至少包含的字段,如果缺一个就是不合法的excel,不导入
    ⑦图片的导入
  • 有图片的导出就有图片的导入,导入的配置和导出是一样的,但是需要设置保存路径 1.设置保存路径saveUrl默认为"upload/excelUpload" 可以手动修改 ImportParams 修改下就可以了。
  • 修改实体类,表明哪些需要导入。
--------员工实体类-------
@Data
@Table(name="tb_user")
public class User {
    @Id
    @KeySql(useGeneratedKeys = true)
    @Excel(name = "编号", orderNum = "0", width = 5)
    private Long id;         //主键
    @Excel(name = "员工名", orderNum = "1", width = 15,isImportField="true")
    private String userName; //员工名
    @Excel(name = "手机号", orderNum = "2", width = 15,isImportField="true")
    private String phone;    //手机号
    @Excel(name = "省份名", orderNum = "3", width = 15,isImportField="true")
    private String province; //省份名
    @Excel(name = "城市名", orderNum = "4", width = 15,isImportField="true")
    private String city;     //城市名
    @Excel(name = "工资", orderNum = "5", width = 10, type=10, isImportField="true") //type=10表示会导出数字
    private Integer salary;   // 工资
    @JsonFormat(pattern="yyyy-MM-dd")
    @Excel(name = "入职日期",  format = "yyyy-MM-dd",orderNum = "6", width = 15,isImportField="true")
    private Date hireDate; // 入职日期
    private String deptId;   //部门id
    @Excel(name = "出生日期",  format = "yyyy-MM-dd",orderNum = "7", width = 15,isImportField="true")
    private Date birthday; //出生日期
    @Excel(name = "照片", orderNum = "10",width = 15,type = 2,isImportField="true",savePath = "D:\\java_report\\workspace\\user_management\\src\\main\\resources\\static\\user_photos\\")
    private String photo;    //一寸照片
    @Excel(name = "现在居住地址", orderNum = "9", width = 30,isImportField="true")
    private String address;  //现在居住地址

    private List<Resource> resourceList; //办公用品
}

-----------导入方法------------------
public void uploadExcleWithEasyPOI(MultipartFile file) throws Exception {

    ImportParams importParams = new ImportParams();
    importParams.setTitleRows(1); //有多少行的标题
    importParams.setHeadRows(1);//有多少行的头
    List<User> userList = ExcelImportUtil.importExcel(file.getInputStream(),User.class,importParams);

    System.out.println(userList);
    for (User user : userList) {
        user.setId(null);
        userMapper.insertSelective(user);
    }
}

模板方式导出数据(excel):

  • 模板是处理复杂Excel的简单方法,复杂的Excel样式,可以用Excel直接编辑,完美的避开了代码编写样式的雷区,同时指令的支持,也提了模板的有效性,采用的写法是{{}}代表表达式,然后根据表达式里面的数据取值。
  • 关于样式问题,easypoi不会改变excel原有的样式。
  • 方法:
public void downLoadUserInfoWithEastPOI(Long id, HttpServletRequest request, HttpServletResponse response) throws Exception  {
    //        获取模板的路径
    File rootPath = new File(ResourceUtils.getURL("classpath:").getPath()); //SpringBoot项目获取根目录的方式
    File templatePath = new File(rootPath.getAbsolutePath(),"/excel_template/userInfo3.xlsx");
    //        读取模板文件
    TemplateExportParams params = new TemplateExportParams(templatePath.getPath(),true);

    //        查询用户,转成map
    User user = userMapper.selectByPrimaryKey(id);
    Map<String, Object> map = EntityUtils.entityToMap(user);
    ImageEntity image = new ImageEntity();
    //        image.setHeight(640); //测试发现 这里设置了长度和宽度在合并后的单元格中没有作用
    //        image.setWidth(380);
    image.setRowspan(4);//向下合并三行
    image.setColspan(2);//向右合并两列
    image.setUrl(user.getPhoto());
    map.put("photo", image);
    Workbook workbook = ExcelExportUtil.exportExcel(params, map);

    //            导出的文件名称
    String filename="用户详细信息数据.xlsx";
    //            设置文件的打开方式和mime类型
    ServletOutputStream outputStream = response.getOutputStream();
    response.setHeader( "Content-Disposition", "attachment;filename="  + new String(filename.getBytes(),"ISO8859-1"));
    response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
    workbook.write(outputStream);
}

Excel注解详细(excel):

属性 类型 类型 说明
name String null 列名
needMerge boolean fasle 纵向合并单元格
orderNum String “0” 列的排序,支持name_id
replace String[] {} 值得替换 导出是{a_id,b_id} 导入反过来
savePath String “upload” 导入文件保存路径
type int 1 导出类型 1 是文本 2 是图片,3 是函数,10 是数字 默认是文本
width double 10 列宽
height double 10 列高,后期打算统一使用@ExcelTarget的height,这个会被废弃,注意
isStatistics boolean fasle 自动统计数据,在追加一行统计,把所有数据都和输出这个处理会吞没异常,请注意这一点
isHyperlink boolean false 超链接,如果是需要实现接口返回对象
isImportField boolean true 校验字段,看看这个字段是不是导入的Excel中有,如果没有说明是错误的Excel,读取失败,支持name_id
exportFormat String “” 导出的时间格式,以这个是否为空来判断是否需要格式化日期
importFormat String “” 导入的时间格式,以这个是否为空来判断是否需要格式化日期
format String “” 时间格式,相当于同时设置了exportFormat 和 importFormat
databaseFormat String “yyyyMMddHHmmss” 导出时间设置,如果字段是Date类型则不需要设置 数据库如果是string类型,这个需要设置这个数据库格式,用以转换时间格式输出
numFormat String “” 数字格式化,参数是Pattern,使用的对象是DecimalFormat
imageType int 1 导出类型 1 从file读取 2 是从数据库中读取 默认是文件 同样导入也是一样的
suffix String “” 文字后缀,如% 90 变成90%
isWrap boolean true 是否换行 即支持\n
mergeRely int[] {} 合并单元格依赖关系,比如第二列合并是基于第一列 则{1}就可以了
mergeVertical boolean fasle 纵向合并内容相同的单元格

导出CSV(csv):

  • csv的导出基本上和excel的导出一致,大体参数也是一致的,csvExportParams 的参数描述如下:
属性 类型 默认值 功能
encoding String UTF8 文件编码
spiltMark String , 分隔符
textMark String 字符串识别,可以去掉,需要前后一致
titleRows int 0 表格头,忽略
headRows int 1 标题
exclusions String[] 0 忽略的字段
  • 方法:
public void downLoadCSVWithEasyPOI(HttpServletResponse response) throws Exception {
        ServletOutputStream outputStream = response.getOutputStream();
//            文件名
        String filename="百万数据.csv";
//            设置两个头 一个是文件的打开方式 一个是mime类型
        response.setHeader( "Content-Disposition", "attachment;filename="  + new String(filename.getBytes(),"ISO8859-1"));
        response.setContentType("application/csv");
//            创建一个用来写入到csv文件中的writer
        CsvExportParams params = new CsvExportParams();
//        设置忽略的列
        params.setExclusions(new String[]{"照片"}); //这里写表头 中文
        List<User> list = userMapper.selectAll();
        CsvExportUtil.exportCsv(params, User.class, list, outputStream);
    }
  • 说明:从上述的代码中你会发现,如果需要导出几百万数据时不可能全部加载到一个List中的,所以easyPOI的方式导出csv是支持不了太大的数据量的,如果导出几百万条数据还是得选择OpenCSV方式导出。

EasyPOI导出word(word):

  • Word模板和Excel模板用法基本一致,支持的标签也是一致的,仅仅支持07版本的word也是只能生成后缀是docx的文档,poi对doc支持不好所以easyPOI中就没有支持doc,我们就拿docx做导出
  • 这里得好好说说模板中标签的用法:下面列举下EasyPoi支持的指令以及作用,最主要的就是各种fe的用法。
三元运算 {{test ? obj:obj2}}
n: 表示 这个cell是数值类型 {{n:}}
le: 代表长度{{le:()}} 在if/else 运用{{le:() > 8 ? obj1 : obj2}}
fd: 格式化时间 {{fd:(obj;yyyy-MM-dd)}}
fn: 格式化数字 {{fn:(obj;###.00)}}
fe: 遍历数据,创建row
!fe: 遍历数据不创建row
$fe: 下移插入,把当前行,下面的行全部下移.size()行,然后插入
#fe: 横向遍历
v_fe: 横向遍历值
!if: 删除当前列 {{!if:(test)}}
单引号表示常量值 ‘’ 比如’1’ 那么输出的就是 1
&NULL& 空格
&INDEX& 表示循环中的序号,自动添加
]] 换行符 多行遍历导出
sum: 统计数据

Java与报表知识概括_第6张图片

  • 方法:
public void downloadContractWithEasyPOI(Long id,HttpServletResponse response) throws Exception {

    File rootPath = new File(ResourceUtils.getURL("classpath:").getPath()); //SpringBoot项目获取根目录的方式
    File templatePath = new File(rootPath.getAbsolutePath(),"/word_template/contract_template2.docx");

    //        先获取导出word需要的数据
    User user = this.findById(id);
    //        把需要的数据放到map中,方便替换
    Map<String,Object> params = new HashMap<String,Object>();
    params.put("userName",user.getUserName());
    params.put("hireDate",simpleDateFormat.format(user.getHireDate()));
    params.put("address",user.getAddress());

    //        下面是表格中需要的数据
    List<Map> maplist = new ArrayList<>();
    Map<String,Object> map = null;
    for (Resource resource : user.getResourceList()) {
        map = new HashMap<String,Object>();
        map.put("name",resource.getName());
        map.put("price",resource.getPrice());
        map.put("needReturn",resource.getNeedReturn());
        ImageEntity image = new ImageEntity();
        image.setHeight(180);
        image.setWidth(240);
        image.setUrl(rootPath.getPath()+"\\static"+resource.getPhoto());
        map.put("photo",image);
        maplist.add(map);
    }
    //        把组建好的表格需要的数据放到大map中
    params.put("maplist",maplist);
    //        根据模板+数据 导出文档
    XWPFDocument xwpfDocument = WordExportUtil.exportWord07(templatePath.getPath(), params);
    String filename=user.getUserName()+"_合同.docx";
    //            设置文件的打开方式和mime类型
    ServletOutputStream outputStream = response.getOutputStream();
    response.setHeader( "Content-Disposition", "attachment;filename="  + new String(filename.getBytes(),"ISO8859-1"));
    response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
    xwpfDocument.write(outputStream);
}
  • 说明:easyPOI在导出word时,发现导出的表格中没有我们预想的图片,所以easyPOI不是万能的,如果有同样的需求还是得用POI来做!

PDF文档

PDF简介:

  • PDF(Portable Document Format的简称,意为“便携式文件格式”)是由Adobe Systems在1993年用于文件交换所发展出的文件格式。
  • PDF格式的文档的使用有如下好处:
    ①跨平台:PDF文件格式与操作系统平台无关,也就是说,PDF文件不管是在Windows,Unix还是在苹果公司的Mac OS操作系统中都是通用的。不受平台的限制。越来越多的电子图书、产品说明、公司文告、网络资料、电子邮件开始使用PDF格式文件。
    ②安全性高,不易修改:PDF是一种通用文件格式,不管创建源文档时使用的是哪些应用程序和平台,它均可以保留任何源文档的字体、图像、图形和版面设置。已成为世界上安全可靠地分发和交换电子文档及电子表单的实际标准。
    ③阅读性能高,阅读舒适性好。
    ④相比Word格式的文档,PDF文件格式更为正式。而WORD文档在跨平台使用方面不如PDF方便,而且WORD文档是可以进行编辑修改的,在安全性和可靠性上不如PDF,而且往往很难反映出用其它编辑软件排版的版面信息,使用上有一定的局限性。 所以现在网站导出PDF也是比较普遍的。

Word转PDF:

  • 把Word转成PDF目前最简单的方式就是调用office的方法,本质上就是打开Word后另存为成pdf,使用 jacob,速度上还是可以的,Word中的原样式也不会丢失。
    JACOB一个Java-COM中间件.通过这个组件你可以在Java应用程序中调用COM组件和Win32程序库。
  • 环境准备:
    ①本机上安装了2007以上的office软件
    ②jdk1.6以上的版本
  • 链接:jacob 工具包下载
  • 操作流程:
    ①把下载的资料中的jar放入到本地仓库,这个jar从中央仓库中没有找到,需要我们自己打到本地仓库中。进入到jar所在的目录执行以下命令:
    mvn install:install-file -DgroupId=com.jacob -DartifactId=jacob -Dversion=1.19 -Dfile=jacob.jar -Dpackaging=jar
    ②把dll文件放入到 jre\bin 目录下 64位的放x64文件,32位的放x86文件。如果不太确定是32位还是64位的就把两个dll都放进去。
    ③在项目的pom中添加依赖:
<dependency>
    <groupId>com.jacobgroupId>
    <artifactId>jacobartifactId>
    <version>1.9version>
dependency>
  • 代码:
public class JacobDemo {
    public static void main(String[] args) {
        String source = "D:\\李四_合同.docx";
        String target = "D:\\李四_合同.pdf";
        System.out.println("Word转PDF开始启动...");
        ActiveXComponent app = null;
        try {
            //            调用window中的程序
            app = new ActiveXComponent("Word.Application");
            //            调用的时候不显示窗口
            app.setProperty("Visible", false);
            // 获得所有打开的文档
            Dispatch docs = app.getProperty("Documents").toDispatch();
            Dispatch doc = Dispatch.call(docs, "Open", source).toDispatch();
            System.out.println("转换文档到PDF:" + target);
            // 另存为,将文档保存为pdf,其中Word保存为pdf的格式宏的值是17
            Dispatch.call(doc, "SaveAs", target, 17);
            Dispatch.call(doc, "Close");
        } catch (Exception e) {
            System.out.println("Word转PDF出错:" + e.getMessage());
        } finally {
            // 关闭office
            if (app != null) {
                app.invoke("Quit", 0);
            }
        }
    }
}

Java PDF制作工具:

  • 上面的例子是根据word转成的PDF,下面我们让java代码直接导出PDF。
  • 目前世面上比较流行的制作PDF报表的工具如下:
    iText PDF:iText是著名的开放项目,是用于生成PDF文档的一个java类库。通过iText不仅可以生成PDF或rtf的文档,而且可以将XML、Html文件转化为PDF文件。 代码编写太复杂!!!
    Jasper Report

iText导出PDF(了解):

  • 用iText生成PDF文档需要5个步骤:
//建立com.lowagie.text.Document对象的实例。
Document document = new Document(); 
//建立一个书写器(Writer)与document对象关联,通过书写器(Writer)可以将文档写入到磁盘中。
PDFWriter.getInstance(document, new FileOutputStream("test.PDF")); 
//打开文档。
document.open(); 
//向文档中添加内容。
document.add(new Paragraph("Hello World")); 
//关闭文档。
document.close(); 
  • 如果有表格:
Table table = new Table(3);
table.setBorderWidth(1);
table.setBorderColor(new Color(0, 0, 255));
table.setPadding(5);
table.setSpacing(5);
Cell cell = new Cell("header");
cell.setHeader(true);
cell.setColspan(3);
table.addCell(cell);
table.endHeaders();
cell = new Cell("example cell with colspan 1 and rowspan 2");
cell.setRowspan(2);
cell.setBorderColor(new Color(255, 0, 0));
table.addCell(cell);
table.addCell("1.1");
table.addCell("2.1");
table.addCell("1.2");
table.addCell("2.2");
table.addCell("cell test1");
cell = new Cell("big cell");
cell.setRowspan(2);
cell.setColspan(2);
table.addCell(cell);
table.addCell("cell test2");
  • 中文字体的处理,默认的iText字体设置不支持中文字体,需要下载亚洲字体包iTextAsian.jar,否则不能往PDF文档中输出中文字体。通过下面的代码就可以在文档中使用中文了:
Font font = getPdfChineseFont();
 
font.setColor(new BaseColor(0xff0000));
font.setSize(16);
font.setStyle("bold");
font.setStyle("italic");
font.setStyle("underline");
 
public static Font getPdfChineseFont() throws Exception {
    BaseFont bfChinese = BaseFont.createFont("STSongStd-Light", "UniGB-UCS2-H",
            BaseFont.NOT_EMBEDDED);
    Font fontChinese = new Font(bfChinese, 12, Font.NORMAL);
    return fontChinese;
} 
  • 样式代码:
pdfCell.setHorizontalAlignment(Element.ALIGN_CENTER);
pdfCell.setVerticalAlignment(Element.ALIGN_MIDDLE);
pdfCell.setBackgroundColor(new BaseColor(0xdd7e6b));
 
pdfCell.setBorderWidthTop(0.1f);
pdfCell.setBorderWidthBottom(0.1f);
pdfCell.setBorderWidthLeft(0.1f);
pdfCell.setBorderWidthRight(0.1f);
pdfCell.setBorderColorBottom(new BaseColor(0x674ea7));
pdfCell.setBorderColorLeft(new BaseColor(0x674ea7));
pdfCell.setBorderColorRight(new BaseColor(0x674ea7));
pdfCell.setBorderColorTop(new BaseColor(0x674ea7));
  • 画线的代码就更复杂了。
  • 所以,综上我们如果直接使用iText导出一个较为复杂的PDF的时候,代码量是非常大的,不推荐使用这种方式,那怎么办呢?我们使用一个封装了iText的一个类库:JasperReport

JasperReport简介:

  • JasperReport是一个强大、灵活的报表生成工具,能够展示丰富的页面内容,并将之转换成PDF,HTML,或者XML格式。该库完全由Java写成,可以用于在各种Java应用程序,包括J2EE,Web应用程序中生成动态内容。只需要将JasperReport引入工程中即可完成PDF报表的编译、显示、输出等工作。
  • 在开源的JAVA报表工具中,JasperReport发展是比较好的,比一些商业的报表引擎做得还好,如支持了十字交叉报表、统计报表、图形报表,支持多种报表格式的输出,如PDF、RTF、XML、CSV、XHTML、TEXT、DOCX以及OpenOffice。
  • 数据源支持更多,常用JDBCSQL查询、XML文件、CSV文件、HQL(Hibernate查询),HBase,JAVA集合等。还允许你义自己的数据源,通过JASPER文件及数据源,JASPER就能生成最终用户想要的文档格式。

JasperReport的生命周期:

  • 通常我们提到PDF报表的时候,浮现在脑海中的是最终的PDF文档文件。在JasperReports中,这只是报表生命周期的最后阶段。通过JasperReports生成PDF报表一共要经过三个阶段,我们称之为JasperReport的生命周期,这三个阶段为:
    设计(Design)阶段:所谓的报表设计就是创建一些模板,模板包含了报表的布局与设计,包括执行计算的复杂公式、可选的从数据源获取数据的查询语句、以及其它的一些信息。模板设计完成之后,我们将模板保存为JRXML文件(JR代表JasperReports),其实就是一个XML文件。
    执行(Execution)阶段:使用以JRXML文件编译为可执行的二进制文件(即.Jasper文件)结合数据进行执行,填充报表数据。
    输出(Export)阶段:数据填充结束,可以指定输出为多种形式的报表。
  • 如下图所示:
    Java与报表知识概括_第7张图片

JasperReport的执行流程:

  • JRXML:报表填充模板,本质是一个XML.
    ①JasperReport已经封装了一个dtd,只要按照规定的格式写这个xml文件,那么jasperReport就可以将其解析最终生成报表,但是jasperReport所解析的不是我们常见的.xml文件,而是.jrxml文件,其实跟xml是一样的,只是后缀不一样。
  • Jasper:由JRXML模板编译生成的二进制文件,用于代码填充数据。
    ①解析完成后JasperReport就开始编译.jrxml文件,将其编译成.jasper文件,因为JasperReport只可以对.jasper文件进行填充数据和转换,这步操作就跟我们java中将java文件编译成class文件是一样的
  • Jrprint:当用数据填充完Jasper后生成的文件,用于输出报表。
    ①这一步才是JasperReport的核心所在,它会根据你在xml里面写好的查询语句来查询指定是数据库,也可以控制在后台编写查询语句,参数,数据库。在报表填充完后,会再生成一个.jrprint格式的文件(读取jasper文件进行填充,然后生成一个jrprint文件)
  • Exporter:决定要输出的报表为何种格式,报表输出的管理类。
  • JasperReport可以输出多种格式的报表文件,常见的有Html,PDF,xls等。
  • 综上我们得知,对于使用JasperReport进行开发,我们重点关注只有如下四点:
    制作报表模板
    模板编译
    构造数据
    填充模板数据
    Java与报表知识概括_第8张图片

模板工具Jaspersoft Studio:

  • 概述:
    ①Jaspersoft Studio是JasperReports库和JasperReports服务器的基于Eclipse的报告设计器; 它可以作为Eclipse插件或作为独立的应用程序使用。Jaspersoft Studio允许您创建包含图表,图像,子报表,交叉表等的复杂布局。您可以通过JDBC,TableModels,JavaBeans,XML,Hibernate,大数据(如Hive),CSV,XML / A以及自定义来源等各种来源访问数据,然后将报告发布为PDF,RTF, XML,XLS,CSV,HTML,XHTML,文本,DOCX或OpenOffice。
    ②Jaspersoft Studio 是一个可视化的报表设计工具,使用该软件可以方便地对报表进行可视化的设计,设计结果为格式.jrxml 的XML 文件,并且可以把.jrxml 文件编译成.jasper 格式文件方便 JasperReport 报表引擎解析、显示。
  • 链接:JasperReport官网下载
  • 面板介绍:Report editing area (主编辑区域)中,您直观地通过拖动,定位,对齐和通过 Designer palette(设计器调色板)对报表元素调整大小。JasperSoft Studio 有一个多标签编辑器,Design,Source和Preview:
    ①Design tab:当你打开一个报告文件,它允许您以图形方式创建报表选中
    ②Source tab:包含用于报表的 JRXML 源代码。
    ③Preview tab:允许在选择数据源和输出格式后,运行报表预览。
    ④Repository Explorer view:包含 JasperServer 生成的连接和可用的数据适配器列表
    ⑤Project Explorer view:包含JasperReports 的工程项目清单
    ⑥Outline view:在大纲视图中显示了一个树的形式的方式报告的完整结构。
    ⑦Properties view:通常是任何基于 Eclipse 的产品/插件的基础之一。它通常被填充与实际所选元素的属性的信息。这就是这样,当你从主设计区域(即:一个文本字段)选择一个报表元素或从大纲,视图显示了它的信息。其中一些属性可以是只读的,但大部分都是可编辑的,对其进行修改,通常会通知更改绘制的元素(如:元素的宽度或高度)。
    ⑧Problems view:显示的问题和错误,例如可以阻断报告的正确的编译。
    ⑨Report state summary 提供了有关在报表编译/填充/执行统计用户有用的信息。错误会显示在这里
    Java与报表知识概括_第9张图片
  • 基本使用:
    ①模板制作:
    <1>打开Jaspersoft Studio ,新建一个project, 步骤: File -> New -> Project-> JasperReportsProject
    <2>新建一个Jasper Report模板,在 Stidio的左下方Project Explorer 找到刚才新建的Project (我这里新建的是DemoReport),步骤:项目右键 -> New -> Jasper Report
    <3>选择 Blank A4 (A4纸大小的模板),然后 Next 命名为test01.jrxml.
    ②编译模板:
    <1>右键单机模板文件 -> compile Report 对模板进行编译,生成.jasper文件

环境准备:

  • 导入依赖:
<dependency>
    <groupId>net.sf.jasperreportsgroupId>
    <artifactId>jasperreportsartifactId>
    <version>6.5.0version>
dependency>
<dependency>
    <groupId>org.olap4jgroupId>
    <artifactId>olap4jartifactId>
    <version>1.2.0version>
dependency>
<dependency>
    <groupId>com.lowagiegroupId>
    <artifactId>itextartifactId>
    <version>2.1.7version>
dependency>
  • 准备中文字体资源文件:jasperReports本身对中文的支持不够好,所以如果涉及到中文,需要自己准备中文的资源,现在已“华文宋体为例”

导出一个最基本的PDF文件:

  • 使用Jaspersoft Studio制作一个简单的模板,放到磁盘的目录上。
  • 测试代码:
public class PDFDemo1 {
    /**
     *  基于parameters以Map的形式填充数据
     */
    public static void main(String[] args) throws Exception {
            String filePath = "D:\\test01.jasper";
//        文件的输入流
            InputStream inputStream = new FileInputStream(filePath);
            //2.创建JasperPrint,向jasper文件中填充数据
            FileOutputStream os = new FileOutputStream("d:\\demo1.pdf");
            try {
                Map parameters = new HashMap<>();
                //设置参数 参数的key = 模板中使用的parameters参数的name
                parameters.put("name","张三");
                parameters.put("phone","13800000000");
                //3.将JasperPrint已PDF的形式输出
                JasperPrint jasperPrint = JasperFillManager.fillReport(inputStream,parameters,new JREmptyDataSource());
                //导出
                JasperExportManager.exportReportToPdfStream(jasperPrint,os);
            } catch (JRException e) {
                e.printStackTrace();
            }finally {
                os.flush();
            }
    }
}

wkhtmltopdf简介:

  • wkhtmltopdf可以直接把任何一个可以在浏览器中浏览的网页直接转换成一个pdf,
  • wkhtmltopdf是一个把html页面转换成pdf的一个软件(需要安装在服务器上),但是它并不是一个简单的桌面软件,而且它直接cmd批处理的。

图表报表

图表报表简介:​

  • 在大数据时代,人们需要对大量的数据进行分析,帮助用户或公司领导更直观的察觉差异,做出判断,减少时间成本,而在web项目中除了表格显示数据外,还可以通过图表来表现数据,这种图表形式表现数据使人看的清楚明白且更加直观。
  • 对于web项目展示图形报表使用最多的技术就是基于js的前端报表框架,目前前端市场使用最多的图形报表框架有:JfreeChart、ECharts、Highcharts、FusionCharts、amCharts等。

报表生成引擎服务商简介:

  • 帆软报表:目前市场占有率好像最高,功能较为齐全,适应大多数行业的功能,价格较贵,基础版价格:80000元/服务器,高级版价格:500000/服务器。
  • 润乾报表:传统报表的代表,功能也比较强大,展示方面略显不足,整体美观度差一些,但价格便宜。
  • iReport +JasperReports:是一个开源报表,功能较单一,使用略微繁琐,展现美观度较差。唯一优势可以自己改造。
  • RDP报表工具:是一款基于java web实现的报表工具,是唯一一款通过web页面设计报表的工具,感觉挺新颖的,功能性和报表的展现美观度还不错。商用免费的一款报表工具。
  • 思迈特:通过excel来进行设计报表,熟悉excel的人开发会更快一些,体验比帆软感觉较差(个人感觉),收费标准不明

JFreechart(后端生成):

  • 简介:JFreeChart是JAVA平台上的一个开放的图表绘制类库。它完全使用JAVA语言编写,可生成饼图(piecharts)、柱状图(bar charts)、散点图(scatter plots)、时序图(time series)、甘特图(Ganttcharts)等等多种图表,并且可以产生PNG和JPEG格式的输出,还可以与PDF或EXCEL关联。
  • 需要的依赖:
<dependency>
    <groupId>org.jfreegroupId>
    <artifactId>jfreechartartifactId>
    <version>1.5.0version>
dependency>
  • 代码:
----------------饼图&3D饼图---------------
public class JfreeChartsDemo1 {

    public static void main(String[] args) throws Exception {
//构建饼图的数据集
        DefaultPieDataset dataset=new DefaultPieDataset();
        dataset.setValue("销售部", 120);
        dataset.setValue("人事部", 50);
        dataset.setValue("技术部", 180);

        StandardChartTheme standardChartTheme=new StandardChartTheme("CN");
        //设置标题字体
        standardChartTheme.setExtraLargeFont(new Font("华文宋体",Font.BOLD,20));
        //设置图例的字体
        standardChartTheme.setRegularFont(new Font("华文宋体", Font.BOLD,15));
        //设置轴向的字体
        standardChartTheme.setLargeFont(new Font("华文宋体",Font.BOLD,15));
        //应用主题样式
        ChartFactory.setChartTheme(standardChartTheme);
//参数1  title 标题
//参数2 dataset 数据集
//参数3   是否开启图例
//参数4   是否开启工具栏
//参数5  是否开启url跳转
//        JFreeChart chart= ChartFactory.createPieChart("各部门人数", dataset, true, false, false);

        JFreeChart chart= ChartFactory.createPieChart3D("各部门人数", dataset, true, false, false);
//生成一张图表的图片文件
        ChartUtils.saveChartAsPNG(new File("d:\\chart1.png"), chart, 400, 300);
    }
}

------------------折线图-----------------------
public class JfreeChartsDemo2 {

    public static void main(String[] args) throws Exception {
//构建饼图的数据集
        DefaultCategoryDataset dataset=new DefaultCategoryDataset();
        dataset.addValue(15,"技术部","2011");
        dataset.addValue(11,"技术部","2012");
        dataset.addValue(10,"技术部","2013");
        dataset.addValue(16,"技术部","2014");

        dataset.addValue(10,"销售部","2011");
        dataset.addValue(30,"销售部","2012");
        dataset.addValue(6,"销售部","2013");
        dataset.addValue(16,"销售部","2014");

        dataset.addValue(10,"产品部","2011");
        dataset.addValue(20,"产品部","2012");
        dataset.addValue(30,"产品部","2013");
        dataset.addValue(15,"产品部","2014");
        StandardChartTheme standardChartTheme=new StandardChartTheme("CN");
        //设置标题字体
        standardChartTheme.setExtraLargeFont(new Font("华文宋体",Font.BOLD,20));
        //设置图例的字体
        standardChartTheme.setRegularFont(new Font("华文宋体", Font.PLAIN,15));
        //设置轴向的字体
        standardChartTheme.setLargeFont(new Font("华文宋体",Font.PLAIN,15));
        //应用主题样式
        ChartFactory.setChartTheme(standardChartTheme);
//参数1  title 标题
//参数2 x轴的说明
//参数3   Y轴的说明
//参数4   数据集
        JFreeChart chart= ChartFactory.createLineChart("入职人数", "年度", "人数", dataset);
//生成一张图表的图片文件
        ChartUtils.saveChartAsPNG(new File("d:\\chart2.png"), chart, 400, 300);
    }
}


---------------柱状图(条形图)-------------
public class JfreeChartsDemo3 {

    public static void main(String[] args) throws Exception {
//构建饼图的数据集
        DefaultCategoryDataset dataset=new DefaultCategoryDataset();
        dataset.addValue(15,"技术部","2011");
        dataset.addValue(11,"技术部","2012");
        dataset.addValue(10,"技术部","2013");
        dataset.addValue(16,"技术部","2014");

        dataset.addValue(10,"销售部","2011");
        dataset.addValue(30,"销售部","2012");
        dataset.addValue(6,"销售部","2013");
        dataset.addValue(16,"销售部","2014");

        dataset.addValue(10,"产品部","2011");
        dataset.addValue(20,"产品部","2012");
        dataset.addValue(30,"产品部","2013");
        dataset.addValue(15,"产品部","2014");

        StandardChartTheme standardChartTheme=new StandardChartTheme("CN");
        //设置标题字体
        standardChartTheme.setExtraLargeFont(new Font("华文宋体",Font.BOLD,20));
        //设置图例的字体
        standardChartTheme.setRegularFont(new Font("华文宋体", Font.PLAIN,15));
        //设置轴向的字体
        standardChartTheme.setLargeFont(new Font("华文宋体",Font.PLAIN,15));
        //应用主题样式
        ChartFactory.setChartTheme(standardChartTheme);
//参数1  title 标题
//参数2 x轴的说明
//参数3   Y轴的说明
//参数4   数据集
        JFreeChart chart= ChartFactory.createBarChart("入职人数", "年度", "人数", dataset);
//生成一张图表的图片文件
        ChartUtils.saveChartAsPNG(new File("d:\\chart3.png"), chart, 400, 300);
    }
}

Highcharts(前端生成):

  • 简介:Highcharts 是一个用纯JavaScript编写的一个图表库, 能够很简单便捷的在web网站或是web应用程序添加有交互性的图表,并且免费提供给个人学习、个人网站和非商业用途使用。HighCharts支持的图表类型有曲线图、区域图、柱状图、饼状图、散状点图和综合图表。
  • 链接:官网下载
  • 步骤:
    ①下载
    ②解压
    ③把js放入到项目中
  • 流程:
    ①创建一个html demo.html
    ②页面中引入js文件
    ③准备一个dom
    ④js代码

Echarts(前端生成):

  • 简介:
    ①ECharts是由百度前端团队开发的一款开源的基于js图形报表组件,一个使用 JavaScript 实现的开源可视化库,可以流畅的运行在 PC 和移动设备上,兼容当前绝大部分浏览器(IE8/9/10/11,Chrome,Firefox,Safari等),底层依赖轻量级的矢量图形库 ZRender,提供直观,交互丰富,可高度个性化定制的数据可视化图表。
    ②ECharts 特性:
    <1>丰富的可视化类型
    <2>多种数据格式无需转换直接使用
    <3>千万数据的前端展现
    <4>移动端优化
    <5>多渲染方案,跨平台使用!
    <6>深度的交互式数据探索
    <7>多维数据的支持以及丰富的视觉编码手段
    <8>动态数据
    <9>绚丽的特效
  • 链接:官网下载
  • 步骤:
    ①下载
    ②解压
    ③把js放入到项目中
  • 流程:
    ①创建一个html demo.html
    ②页面中引入js文件
    ③准备一个dom
    ④js代码

你可能感兴趣的:(JavaSE,报表,Java)