承接上篇

第二章主要介绍了目录页的一些预览技巧,包括字体库注入到软件中,最后的目录页顺利的生成了,中间有几个小坑也给小伙伴们说了一下,报表在于要细心和耐心,不要急于求成,慢慢入手,终有成效!
本章准备讲一下交叉表,这个章节我觉得算是核心,因为交叉表的制作会涉及到后面的柱形图和饼图,因为柱形图和饼图的最终生成是靠着交叉表来实现的,没有交叉表就没有柱形图和饼图。交叉表的最大好处在于可以动态的增加或者减少你的列头,不像固定的表格,无法扩展固定写死的表头,所以本章对于后面的内容尤为重要,有坑的地方我也会时刻提醒,考虑不周的地方欢迎评论区留言,及时补充,争取将报表技术做到尽善尽美!
还是提醒一下小伙伴们,简单的部分我选择直接讲解不会花太多时间,因为百度都有,基本看到教程的你已经是属性jasperreport的一些基本元素再来学习,否则会有点吃力!切记!!!切记!!!切记!!!

何为交叉表

交叉报表是报表当中常见的类型,属于基本的报表,是行、列方向都有分组的报表;简单来说就是可以实现动态分组的表格。举个例子:
清华大学—计算机科学与技术系—三个班级(一班、二班、三班),每个班级人数分别为40,50,60人,再细分一点—一班男生女生分别为20,20;二班男生女生分别为20,30;三班男生女生分别为30,30;表格如图:

正常我们的数据模型应该是如图中箭头男生-一班 20,二班 20,三班 30;女生-一班 20,二班 30, 三班30这样,很明显是一个固定表格的数据模型。
这种模型下我们使用模板做出来的列头必须是固定的,无法实现动态扩展列头的方式,比如这时候多了个四班,五班等等。
所以交叉表展示的数据模型和普通表格不同,如图:

交叉表的数据模型存在交叉:一班男生-20,二班男生-20,三班男生-30,一班女生-20,二班女生30,三班女生30;
这样的交叉数据正是交叉表的意义所在,同样我们在模板文件中创建的交叉表也会去根据这三个值(班级,性别,人数)进行动态生成列头和纵向列头的生成,所以无论我们创建多个班级都会横向进行扩展!

交叉表数据准备

着手数据构造,模型就用我们刚才的数据进行模拟测试。开发工具使用idea,实体类QHComputerStudent,属性有三个性别(gender)String,班级 (grade)String,人数(personNumber)Integer;

public class QHComputerStudent {/*** 性别*/String gender;/*** 班级*/String grade;/*** 人数*/Integer personNumber;public String getGender() {return gender;}public void setGender(String gender) {this.gender = gender;}public String getGrade() {return grade;}public void setGrade(String grade) {this.grade = grade;}public Integer getPersonNumber() {return personNumber;}public void setPersonNumber(Integer personNumber) {this.personNumber = personNumber;}
}

实体类有了,再写一个构造数据的类就叫StudentFactory:

public class StudentFactory {public static List<QHComputerStudent> getQHComputerStudent(){List<QHComputerStudent> infoList = new ArrayList<>();QHComputerStudent student1 = new QHComputerStudent();student1.setGender("男");student1.setGrade("一班");student1.setPersonNumber(20);QHComputerStudent student2 = new QHComputerStudent();student2.setGender("男");student2.setGrade("二班");student2.setPersonNumber(20);QHComputerStudent student3 = new QHComputerStudent();student3.setGender("男");student3.setGrade("三班");student3.setPersonNumber(30);QHComputerStudent student4 = new QHComputerStudent();student4.setGender("女");student4.setGrade("一班");student4.setPersonNumber(20);QHComputerStudent student5 = new QHComputerStudent();student5.setGender("女");student5.setGrade("二班");student5.setPersonNumber(30);QHComputerStudent student6 = new QHComputerStudent();student6.setGender("女");student6.setGrade("三班");student6.setPersonNumber(30);infoList.add(student1);infoList.add(student2);infoList.add(student3);infoList.add(student4);infoList.add(student5);infoList.add(student6);return infoList;}}

可以看到我写了静态类,构造了一些测试数据,用于测试一会交叉表的导出。数据准备的差不多了,可以开始说一下交叉表模板制作了,为了防止和上一个目录模板冲突,我们重新建一个用于测试的模板,目录模板可以暂时移除,直接选中目录的模板右击delete即可!

重新建一个新的模板demo2.jrxml,直接选择finish即可,然后老样子拖动demo2.jrxml到content区域跳出弹框选项,表示选用什么数据源方式注入,我们这里选用的是bean方式,所以我们选择Use a JRDatasource expression ,基本上都是用外部bean的方式去注入数据源,所以后面基本上都是选择这个注入方式,然后点击finish即可!


这里可以点击一下 demo2.jrxml看一眼(不用双击点进去),查看一下data这里有个注入方式,看一眼就好,后面再说。
到这里我们准备工作差不多结束!!

交叉表模板制作

1. 创建DateSet数据集

双击打开demo.jrxml, 删除非必要的部分,只保留title和detail1两个部分

在创建交叉表之前我们首选要准备交叉表注入的一些元素,因为交叉表是依赖于属性类中的变量进行适配的,所以我们需要先创建制作交叉表需要的数据集DataSet,直接右击功能栏的demo2新建DataSet --> create a new empty dataset即可,点击finish,打开新建的dataset1,在field(这里的field类似于属性,之后我们从idea注入的外部类会注入到此属性中,所以属性名称必须和外部类的属性名称相同)中新建三个属性gender,grade和personNumber,和我们之前的属性类中名称一致。


需要注意的是每个属性的类型也必须要和你的外部类属性类型一致,不然无法找得到!



这样我们的数据集就有了,后面传递外部属性类的时候,这几个字段会和你外部属性类进行一一对应关联,试想你的名字不一样,类型不一样怎么能找得到呢???

2. 创建交叉表

第一步:将交叉表组件Crosstab直接拖动到detail中,提示你选择数据集,直接下拉选择我们刚才创建的,代表着这个交叉表会依赖于我们创建的数据集。

第二步:点击next,看右上角,表示你横向列头显示的内容,我们选择班级grade,双击grade即可,会发现grade移动到了后面的区域,默认Order表示升序方式;Total Position表示总计的位置,我们不需要总计所以选择none;然后点击next下一步:



第三步:这一次表示纵向的列头,显示的是性别,所以我们选择gender,双击即可,不需要总计,total position设置为none,同第二步;点击next下一步:


第四步:表示主体内容,选择人数personNumber,这里的calculation表示计算方式,我们只需要展示人数,所以我们不计算,选择No calculation,表示不计算只显示数据,点击next下一步:



第五步:这里主要是设置交叉表的颜色,我这个软件某些颜色显示不全,还是存在小bug的,可能分辨率的问题,我们暂时就先不设置颜色,大家可以自己参考设置!直接点击finish即可!

3. 完善交叉表的设置


可以看到交叉表已经出来了,但是显得比较小,看着不舒服,可以拉动边框放大,看着差不多就行了

3.1 设置交叉表字体

交叉表的数据会涉及到中文,所以我们统一处理字体
双击交叉表打开数据层,选中gender,grade和personNumber设置微软雅黑,居中显示

3.2 设置交叉表样式(此处有坑)

  1. 默认的框框可能会比较窄,看图可知,我们可以拉动边缘的框框使其变宽变高,对于多宽多高看自己需要,差不多就行
  2. (注意坑) 可能存在比如,框内数据很长,给的框框空间不够咋办? jasperreport提供了自适用高度,当长度不够的时候,会自动拉伸高度,达到换行的效果。选中gender,grade,value同时设置属性
    包括Stretch Type 自动拉伸;
    Detail Overflows 超过一页的时候会自动填写列头;
    Text Adjust 自适用行高;
    Blank when null 当你的交叉表中存在null值的时候,会自动以空白处理,当然有些时候,可能你的表格会用“–”表示,主动赋予值也是可以的,反正这个打钩没坏处,不然你的值会以null显示在表格中,很难看!

  3. (注意坑) 交叉表取消默认排序规则
    这个功能也很重要,比如你的数据在list中是一个顺序,但是交叉表默认给你的是按照某个字段的升序排列的,例如你的数据插入顺序是张三李四,但是交叉表默认升序给你变成了李四张三,所以我们就想要按照默认list的顺序进行展示,怎么办?可以设置取消交叉表的默认升序排序,改为默认不排序!
    在交叉表页面选择Crosstab展开,选中你的列头属性,右侧可以看到有个order,默认是升序Ascending,改成none就ok了,表示不排序。gender和grade可以都改动一下。
    **注意点:**你改完了之后,横向和纵向都会取消排序,如果你的横向是一些月份啥的,纵向比如是一些年份啥的,这种的就要求你在进行数据处理的时候需要按照月份或者年份顺序进行赋值,不然顺序肯定会混;所以需不需要取消排序效果也是根据实际情况判断的哦,这里我们都改一下默认不排序,给大家展示效果。
  4. (注意坑 这里是大坑) 交叉表默认会按照升序排列,也可以不设置排序规则,但是交叉表还有一个坑,那就是如果出现列头重复咋办,比如你的列头是那种同环比列头 ---- 电,上月环比;水,上月环比;燃气,上月环比;这时候出现了三个上月环比一模一样的列头,交叉表会怎么办,很简单,它会帮你合并成一个,可能你的交叉表画出来变成了电,水,燃气,上月环比;这个算是bug吗,算的。但是真实就是你需要显示所有的列头,不希望它合并,咋办?
    对于这个问题,我个人没有在设置方面发现解决办法,但是有个小技巧可以办的到:因为我们的列头是自己赋值的,它需要的就是我们每一个列头都不能重复,所以我们在赋值列头的时候,给每一个列头前面加上一个字符(char),占一个字符,在交叉表中,支持列头截取,从第一位开始截取,这样就避免了列头重复会被覆盖的问题。例如电,a上月环比;b水,c上月环比;d燃气,e上月环比;熟悉吗,然后对每一个列头进行字符串截取,String.subString(int);这样就完美的解决了这个问题。

如图,还是选中demo2模板,进入到交叉表设置中,分组的列头,右侧有个默认的列头表达式expression,意思就是默认你传啥它就显示啥,可以双击列头字段,如图,支持从grade下标截取,跟正常的字符串操作是一样的,我们这里先不做演示,后面在做演示!

** 保存保存别忘了!!!!!!!!!**

3.3 交叉表的数据源注入

  1. 先说一下数据源注入的过程:
    外部数据 —> 传到最外层模板student.jrxml —> demo2.jrxml —> 交叉表;

    第一步:demo2模板新建 field 变量 qhComputerStudentList — list类型(用于传递给交叉表的变量)打开demo2模板,新建field即可,类型选择java.util.List

    第二步:交叉表需要一个数据源用于展示(其实就是一个数据对象),交叉表的注入对象格式是固定的,将对象包装成模板可以识别的模型就可以了,这里注入的变量其实就需要用到它的父级demo模板中的qhComputerStudentList 变量了,达到传递的效果, 因为变量默认是list类型,所以我们需要转换成交叉表识别的格式:new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($F{qhComputerStudentList})
    点击detail中的交叉表,右侧选择dataset注入数据集,选择Use a JRDatasource expression

    点击圈中的部分添加注入格式,点击finish即可

这样注入交叉表的数据源就搞定了!!!

第三步:student主模板如何传递到它的子模板demo2中呢?其实同理,我们需要在student也添加变量传过来,只不过主模板我们就不是创建field,而是直接创建parameter参数用于传递变量。
打开student主模板,新建parameter --- > studentFactory 类型(如图)
其实studentFactory后面会为所有子模板传递所需要的数据源,它本身也作为主模板的数据源,所以它的类型:
net.sf.jasperreports.engine.data.JRBeanCollectionDataSource; 不用我多说了吧!!! **注意!!!**


第四步:如何将studentFactory数据源注入到demo2中?
实际原理是studentFactory中会存在demo中我们刚才创建的属性qhComputerStudentList,变量名字要求必须一模一样,少一个字母,demo2都找不到这个变量;主模板传递到子模板方式和交叉表类似(如图),点击主模板中的demo2.jasper,选择data,右侧圈圈点进去,选择parameter参数中的studentFactory, 点击finish完成即可。
这样也就实现了数据源从student主模板到子模板传递的过程。


** 保存保存别忘了!!!!!!!!!**

3.4 设置主模板中子模板的路径

大概说一下,因为设计到最后的导出pdf或者word,需要加载模板,主模板是直接通过加载模板的方式加载进去的,但是子模板不一样,是通过父模板找到子模板的位置,所以我们需要对每一个子模板都设置一个主模板所在的路径,这样在加载主模板的时候就能够加载到子模板!!!这一点很重要,不然你在导出的时候就一定会提示找不到子模板。
因为路径是根据你主模板的位置确定的,所以肯定是一个动态路径,也是从外部传入的参数,所以也需要创建路径参数 subPath(父模板的所在路径)
第一步:点击student主模板,创建parameter参数subPath(父级路径)--- String类型


第二步:给每一个模板名称都加上这个subPath前缀
点击cover --> 点击圈圈修改名称 —> 选择parameter —> 在原来的名称前面拼上subPath,点击finish即可。

其它几个模板同理,不要遗漏任何一个模板!!! 注意不要遗漏!!!!!




差不多子模板的路径也就这样了!!!如果在你的子模板中还嵌套着子模板,则也需要使用这样的方式去找到你的子模板的子模板(有点小饶!),方法一样的,只不过需要将你的路径subPath先传递到子模板中,再由子模板传递到子模板中!!!

3.5 设置背景图片路径

背景图片其实就类似于子模板中的子模板,现在的背景存在于封面和末尾,所以我们需要将subPath注入到这两个页面中去。
第一步:选中封面 —> 选择data --> edit Parameter --> add —> 输入参数名和选择注入的参数(subPath),点击ok finish即可!!!
如图:

末尾的页面同理设置参数subPath

第二步:第一步已经将路径subPath传递给了封面和尾页,其次还需要在封面和末尾的模板中添加接收subPath的参数,这里接收的参数名称必须和subPath一样;分别打开封面和尾页模板 — 新建subPath参数即可!!! 这样你的subPath就会顺利传到模板中;如图:
这里提醒一下:因为加了抽奖路径subPath所以可能你双击主模板中封面或者尾页会提示错误,很正常!!!我们直接点击对应的模板即可,不需要从主模板进入,这里可能会让有些人觉得是不是模板报错了!!!! 别在意!!!

首先是是封面添加参数subPath(和外面的参数一致)

其次是尾页添加参数subPath(和外面一致)

第三步:将背景图片的路径前面加上subPath,分别给封面页和尾页的背景图片加上路径前缀
首先是封面页,添加完点击finish别忘记保存了!!!


其次是尾页设置

这样差不多背景图片路径也设置好了

注意:模板制作需要细心和耐心,本来就枯燥无味,有的时候一步错步步错,所以细心,细节真的很重要!!!如果你没有耐心,但是为了生活,还是慢慢开始,不要放弃自己!!!

4. 数据准备

4.1 清华计算机学生类(数据源属性类)

public class QHComputerStudent {/*** 性别*/String gender;/*** 班级*/String grade;/*** 人数*/Integer personNumber;public String getGender() {return gender;}public void setGender(String gender) {this.gender = gender;}public String getGrade() {return grade;}public void setGrade(String grade) {this.grade = grade;}public Integer getPersonNumber() {return personNumber;}public void setPersonNumber(Integer personNumber) {this.personNumber = personNumber;}
}

4.2 主数据源类StudentInfo

public class StudentInfo {private List<QHComputerStudent> qhComputerStudentList;public List<QHComputerStudent> getQhComputerStudentList() {return qhComputerStudentList;}public void setQhComputerStudentList(List<QHComputerStudent> qhComputerStudentList) {this.qhComputerStudentList = qhComputerStudentList;}
}

4.3 用于封装测试数据的工厂类

public class StudentFactory {public static List<QHComputerStudent> getQHComputerStudent(){List<QHComputerStudent> infoList = new ArrayList<>();QHComputerStudent student1 = new QHComputerStudent();student1.setGender("男");student1.setGrade("一班");student1.setPersonNumber(20);QHComputerStudent student2 = new QHComputerStudent();student2.setGender("男");student2.setGrade("二班");student2.setPersonNumber(20);QHComputerStudent student3 = new QHComputerStudent();student3.setGender("男");student3.setGrade("三班");student3.setPersonNumber(30);QHComputerStudent student4 = new QHComputerStudent();student4.setGender("女");student4.setGrade("一班");student4.setPersonNumber(20);QHComputerStudent student5 = new QHComputerStudent();student5.setGender("女");student5.setGrade("二班");student5.setPersonNumber(30);QHComputerStudent student6 = new QHComputerStudent();student6.setGender("女");student6.setGrade("三班");student6.setPersonNumber(30);infoList.add(student1);infoList.add(student2);infoList.add(student3);infoList.add(student4);infoList.add(student5);infoList.add(student6);return infoList;}/*** 主数据源注入属性*/public static List<StudentInfo> getStudentInfo(){List<StudentInfo> studentInfoList = new ArrayList<>();StudentInfo studentInfo = new StudentInfo();studentInfo.setQhComputerStudentList(getQHComputerStudent());studentInfoList.add(studentInfo);return studentInfoList;}}

4.4 模板提取

删除所有的jasper文件,这里别删错了,把jrxml文件误删除了就不太好办了,然后选择文件夹demo_cover重新编译,所有模板会一起编译,重新生成新文件;


复制模板和背景图放到已经准备好的环境中,我用的是springboot环境,第一章节有说过,这里不做讲解了!!!
我这里放在了resource目录下:

4.5 导出pdf和word的代码

try {OutputStream os = response.getOutputStream();String reportName ="student.jasper";response.setContentType("application/pdf; charset=utf-8");response.setDateHeader("Expires", 0);// 加载主模板JasperReport jasperReport = (JasperReport)JRLoader.loadObject(resourceLoader.getResource("classpath:/jasper/student/"+reportName).getInputStream());// 获取主模板的路径String subPath = resourceLoader.getResource("classpath:/jasper/student/").getURL().toString();// 构造数据源JRBeanCollectionDataSource studentFactory = new JRBeanCollectionDataSource(StudentFactory.getStudentInfo());HashMap<String, Object> hashMap = new HashMap<>(16);// 这里map中的key就是你模板中变量的名称 一一对应hashMap.put("subPath", subPath);hashMap.put("studentFactory", studentFactory);JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, hashMap, new JREmptyDataSource());// 页面预览pdfJasperExportManager.exportReportToPdfStream(jasperPrint,os);// 导出pdfJasperExportManager.exportReportToPdfFile(jasperPrint,"D:/report/测试.pdf");System.out.println("导出pdf文件成功");// 导出wordList<JasperPrint> test1 = new ArrayList<>();test1.add(jasperPrint);JRDocxExporter exporter = new JRDocxExporter();exporter.setExporterInput(SimpleExporterInput.getInstance(test1));exporter.setExporterOutput(new SimpleOutputStreamExporterOutput(new File("D:/report/测试.doc")));exporter.exportReport();System.out.println("导出word文件成功");} catch (Exception e) {e.printStackTrace();}

5. 启动运行查看效果

启动项目:输入 localhost:8080/hkfire/reportStudent 这是我的测试路径,看一下能否成功导出pdf!!!
封面正常!!!

目录:当然现在没有目录,因为已经被我删掉了!!!

交叉表的数据也能正常显示

尾页也没问题

pdf和word也能正常导出

6. 优化导出的交叉表(防坑)


6.1 交叉表的默认排序解决(坑1)

对比一下我们导出的交叉表和注入的数据,我们会发现其实导出的数据是错乱分布的,这是因为我们之前说了,交叉表默认是按照它自己的排序规则排序的;修改交叉表的排序规则即可解决,前面内容提到过:
直接打开交叉表,找到列头字段,取消排序:

重新生成demo2模板,如果你只单独改动了某个模板,只需要重新生成当前模板即可,不需要重新编译其它的模板!!!
删除demo2.jasper,重新编译 —> 选中demo2.jrxml 重新编译

复制到项目中进行覆盖,然后重新编译一下项目文件夹,不然你的模板可能提示未找到,所以需要重新编译项目!!!
右击文件夹build一下即可,重启项目查看效果!!!


这下好了,列头是按照一班、二班、三班排列的!!!这样就解决了列头默认不排序的问题!!!
我们都知道默认排序规则是不太合理的,但是有些列头是数字列头,这种的升序或者降序都是合理的,因为数字大小排列不太会错乱,但是出于实际考虑,我们需要在数据处理的时候对数据按照合理的顺序进行封装,然后模板中选择不排序,其实也是极好的!!!

6.2 左上角缺失的方格补充(坑2)

其实这个不算问题,因为本来交叉表这里就是没有内容的,但是实际上看着交叉表不太美观,看着也很难受,所以需要补齐这个空缺。也很简单,直接选中交叉表模板中左上角的位置添加一个header,然后拖动一个动态变量到这个空白的单元格处,填写一些内容,顺便设置一下单元格文字样式,微软雅黑,10号字体居中,填写内容为性别;
保存!!!



因为新建的列头本身外围是没有边框的,故可能导出来的表格边框会是空白的,所以我们给所有的属性外面都加上边框设置
选中所有的单元格内容,设置边框如图,记得保存!!!

重新生成模板覆盖原有的项目模板,重新编译,然后启动测试!!!


好了 顺序和列头都没啥问题!!!

6.3 测试交叉表大长度列头(坑3)

修改一下列头长度测试导出的单元格效果:一班 —> 一班特别长长一班特别长长
太长的一行占不下,所以它会换行,我们之前已经说过了,需要设置自动拉伸高度!!!

6.4 测试多列头重复的效果(坑4)

我现在把一班,二班,三班都改成一班试试导出效果!!!


我们发现,重复的列头 一班会自动合并成一列了,所以之前我们提到的类似多个上月同环比就会出现合并的情况,这样的效果肯定是不合理的,我们想要让它不合并,所以需要保证每一个列头都不重复;
解决办法:在每一组列头前面加上一个字符,如图看我的处理:

这里需要保证肯定加的是一个字符不是多个字符(当然多个字符也可以,截取的时候你就需要看一下从哪个下标截取),所以我用的是char进行了强转,转化之后肯定一个字符,具体是啥字符不用管,只要保证每一组的列头不重复即可;另外还需要在模板中对每一个列头进行截取,因为我们不需要第一个字符的部分,所以我们列头都是从1号位置截取,如图:

找到模板中的列头字段双击设置,对列头进行表达式的重构,从1号位置开始截取,点击finish,这里和正常字符串操作是一样的!不多说了!!!
然后记得保存!!!!!!!
重新编译一下demo2模板,覆盖原有模板,编译目录,重新启动项目,再次测试!!!


这次发现就算都是一班(其实已经不全是一班了),也不会合并起来,这个算是投机取巧解决了列头重复的问题!!!

7. 总结Summary

花了点心思,平时上班抽空写,总算在拼拼凑凑下写完了单个交叉表的内容,内容较多,希望阅读的你耐得住寂寞,细心阅读,字字精华,句句真言!!!码字不易,需要边写边思考,喜欢的小伙伴欢迎阅读借鉴,走过的坑

Jasperreport_6.18的吐血记录三之简易交叉表 + 页面预览和导出相关推荐

  1. Jasperreport_6.18的吐血记录四之分组交叉表

    承接上篇 第三章主要说了交叉表的简单使用以及列出了在交叉表制作过程中可能会遇到的实际场景,还有就是实际场景中出现的一些坑,为了方便演示所以案例数据比较简单,希望小伙伴们认真阅读,细节很多,各位伙伴多注 ...

  2. Jasperreport_6.18的吐血记录二之目录页

    承接上篇 第一篇已经介绍了基本的安装方法和一些基本的配置,可能暂时还用不到,毕竟还没有做最后的导出,可能还不能看到效果,只能算是环境准备吧! 说一下编写思路,我的想法是分段编写,本章主要讲创建目录的案 ...

  3. Jasperreport_6.18的吐血记录一之安装软件

    开篇先说一说自己的心路历程,不想看的直接下拉 吐槽一下 软件以及jar包.字体配置下载链接 下载软件以及中文配置用法 总结 吐槽一下 2月份接到了来自公司的任务,使用报表技术编写一份月度报告,包括导出 ...

  4. Jasperreport_6.18的吐血记录五之柱形图

    承接上篇 第四章主要介绍了分组交叉表的展现的内容以及在实际过程中可能会遇到的问题,案例仅仅是案例,希望小伙伴们能在实际开发中举一反三,切合实际去做分组交叉表,遇到的问题不要着急欢迎私我,有问题一起解决 ...

  5. 【学习记录20】vue使用blob流预览word ,Excel,pdf,TXT,图片,视频

    TXT,PDF直接使用浏览器本身预览 excel使用插件 xlsx,这个插件需要用到arraybuffer的流格式,我是使用前端转换的详见js代码,也可以叫后台返回arraybuffer的数据流 wo ...

  6. 团队协作三、OnlyOffice 实现文件在线预览和编辑

    文档在线预览,最好都安装到本机,成功的机率大 对于大多数开源的网盘软件来说,文档(docx,doc,txt,pdf,xls等)不能在线预览,给网盘软件的使用带来了不变. 插件下载地址 https:// ...

  7. 记录一次微信小程序实现预览pdf

    微信小程序预览pdf需要注意的是,在安卓端和ios端是有差异的. 安卓端不能用web-view直接打开,需要先下载到本地,再打开文件进行预览. 网上说的ios端可以直接用web-view进行预览,但是 ...

  8. Jasperreport_6.18的回血终结篇之案例目录、封面

    承接上篇 上一章介绍了饼图,本章废话不多说了,准备给案例加个目录和封面,并且给案例排排版,做的好看一些!!! 案例回顾 - 以图为证 模板排版优化 1. 模板数据和列表展示更为合理 通过我们前面的讲解 ...

  9. Android 音视频开发(三) -- Camera2 实现预览、拍照功能

    音视频 系列文章 Android 音视频开发(一) – 使用AudioRecord 录制PCM(录音):AudioTrack播放音频 Android 音视频开发(二) – Camera1 实现预览.拍 ...

最新文章

  1. CodeGen编写自定义表达式标记
  2. 浅析 VO、DTO、DO、PO 的概念、区别和用处!
  3. 解决 Out of range value adjusted for column 'ID' at row 1
  4. Android中Activity总结
  5. Python-输入输出
  6. 确保字符串的每个单词首字母都大写,其余部分小写
  7. mysql 1418 存储过程_MySQL自定义函数 1418报错
  8. js学习总结:DOM节点一(选择器,节点类型)
  9. HDOJ 2639 Bone Collector II (背包)
  10. 一句话设置UITextField、UITextview的字数限制和placeholder
  11. POJ3461 HDU1686 Oulipo题解
  12. LeetCode 985 Sum of Even Numbers After Queries 解题报告
  13. dism命令使用教程_Dism命令教程修复Windows
  14. 华北水院c语言实验报告答案,C语言实验报告(三)
  15. 判断矩形是否重叠 Python
  16. 毕业三年,坚持学习两年,成功上岸字节跳动,背水一战
  17. 怎么删除日历每日重复提醒事项
  18. 彻底解决python关于各种文件(音乐、视屏等)读写的操作
  19. invalidate()和postInvalidate() 的区别及使用
  20. Linux Ext 文件系统

热门文章

  1. 量化金融模型ARCH模型官方例程(中文翻译版)
  2. Python基于OpenCV的人脸表情识别系统[源码&部署教程]
  3. Unirech腾讯云国际版代充-使用RDP文件登录到Windows云服务器实例教程
  4. 领存Xeon E5 6U VPX高性能计算刀片
  5. C6678信号处理板学习资料:基于6U VPX TMS320C6678+XC7K325T 的信号处理板
  6. vdi转vmdk VirtualBox与VMware硬盘格式转换及使用方法
  7. 计算机格式怎么调,怎么改电脑硬盘格式?
  8. 北大计算机研究生有多神仙,北大考研成绩公布,还上“热搜”,这都是些什么“神仙分数”?...
  9. webrtc QOS方法十二(接收端IDR帧请求)
  10. 通过 Dockerfile 搭建标注工具 brat 的镜像