iReport和JasperReport

一、介绍

1
)它可以PDFHTMLXML等多种形式产生报表或动态报表,在新版本还支持CSVXLSRTF等格式的报表;
2
)它按预定义的XML文档来组织数据,来源多(如:关系数据库,Java容器对象(collectionarrays)等);
报表的填充过程:
先产生报表设计对象->序列化该对象->存储在磁盘或网络->产生XML文件(表格数据)。
表单的设计过程就是用定义于XML文件中的Java表达式来实现报表的设计。
3
)它带数据一致性验证;
4
)报表引擎必须先接受数据(通过参数等多种形式)来产生报表,更多的是来自数据源,引擎直接接收用于填充表格的数据源对象,或者通过自身提供的JDBC连接对象来处理数据库的数据;
5
)报表最终要产生一个新的对象来进行填充操作,从而产生打印文档对象,这也是存储在磁盘或网络传输介质的序列化对象;
6
)内置浏览器能直接查看结果,以PDFHTMLXML导出;
7
)重要的类:
net.sf.jasperreports.engine.design.JasperDesign
其实例是用于报表产生的原始类;
net.sf.jasperreports.engine.design.JasperReport
表现了报表设计对象,是作为报表的编译过程的结果而被实例化,是向报表中填充数据的准备。


二、结构

JasperReports
XML文件来定义,约定用jrxml作为文件的后缀名。

1
)主要元素:
<jasperReport>
根元素
<title>
报表的标题
<pageHeader>
页眉
<detail>
正文
<pageFooter>
页脚
<band>
定义报表部件,以上所有元素都包含一个band元素作为其唯一子元素。
除了根元素,其余元素是可选的。

2
)其编辑工具iReportEclipse3.2下的安装过程
菜单帮助”->“软件更新”->“查找并安装”->“搜索要安装的新功能部件”--(下一步)-->“新建远程站点,输入以下内容:
名称:JasperForge
URL
http://www.jasperforge.org/update
--(
确定)-->“下一步”-->直至完成。

3
)以JasperReports1.3.0版本为例,一个JasperReports项目需要如下jar
包名                                    说明
jasperreports-1.3.0.jar                 JasperReports API
commons-beanutils-1.7.jar               JavaBeans Utility classes
commons-collections-2.1.jar             Collections framework extension classes
commons-digester-1.7.jar                classes for processing XML documents
commons-logging-1.0.2.jar               Logging classes
poi-2.0-final-20040126.jar              Jarkarta POI API to generate an Excel Document
itext-1.3.1.jar                         PDF library
xml-apis.jar                            XML parser API



三、iReport介绍

1
iReport是为JasperReports设计的强大的,直观的,易于使用的可视化报表设计器,为win32平台编写。允许用户可视化地编辑XML JasperDesign文件,可以和其它数据库进行JDBC通信。
再设计模板时可以以HTMLPDFXML方式预览,用它生成的文件有.jrxml.jasper两种文件。
.jrxml
:是可视化编辑的xml文件;
.jasper
:经编译后生成的类文件,即报表模板文件。

2
iReport的输出格式
其预览输出格式有:PDFHTMLCSVJAVA2DEXCEL,纯文本,JRView
注意:JRViewer是直接以C/S方式作为报表的输出格式,在JFrame框架下输出。

3
)报表的动态对象变量、参数、字段
字段Fields:是从数据库抽取出来的,在报表中出现的数据库内容。$F
参数Parameters:你写的应用需要提供给报表的入口。 $P
变量Variables:报表中一些逻辑运算的表现。 $V
每个对象的定义格式如下: $V{variablesName}

4
)运行时需要.jasper文件;编译:把.jrxml->.jasper文件。
静态运行:静态文本来运行,和数据源无关;
动态运行:带数据源运行。

5
)报表的结构
titlepageHeadercolumnHeaderdetailcolumnFooterpageFootersummarygroupHeadergroupfooter

6
)在iReport中创建数据库连接
1)菜单DourceSource -> Connections/DataSources -> ...new ->
2)菜单Build -> Set active connection -> 选择 -> ... -> OK

7
)在iReport中创建文件
iReport
工具是一个可视编辑器帮助创建JasperReports文件。JasperReports是一个基于Java报表的引擎。
当你在iReport中创建一个报表,你实际上是对配置文件进行操作,告诉JasperReports应该怎样建立Report
三种文件:
.jasper
文件:编译的二进制文件;
.jrxml
文件:报表的配置文件;
.pdf
文件:生成的pdf文件。

8
)报表格式化
iReport上选择报表的一个区域,将呈现蓝色高亮显示;
可用鼠标拖曳来改变区域的尺寸,当误操作时,用undo来恢复;
如选择框变红,则有错误,report将不能编译;
改变字体或调整尺寸,菜单“View”->“Element properties”->分三个选择:
1Common选择:尺寸,前景色/背景色,透明度,打印条件,位置属性等;
2Font选择:字体、大小、类型,PDF字体,加粗,斜体,下划线,水平位置,垂直位置,PDF编码。
注意:两种字体:
     Font Name
:将显示在iReport设计器和JasperReports运行中;
     PDF font Name
:将显示在编译后的PDF文件中。
3Static Text:静态文本。
想浏览元素时,看“View”->“Elements browser”
一次选择多个域,按“shift”键再用鼠标点击;
菜单“View”->“Report Properties”报表属性:
报表尺寸,单位,页边距,报表名,纵向Portrait/横向Landscape,列宽,Spacing,标题作为新页,Summary作为新页,XML编码(UTF-8)。

9
)使用Groups
菜单“View”->“Report query” 可以查询和修改SQL语句。

10
)为report增加参数
1)菜单“View”->“Report Query”,修改SQL语句,如:加上 WHERE LAST_NAME=$P{LAST_NAME}
注意:参数用$P{}来封装。
2)定义参数
菜单“View”->“Reports Parameters”
新建参数,如参数名为“LAST_NAME”,再指定参数的类型(如:String
还可设定缺省值和参数的描述
运行报表(缺省),还可以传递参数方式:http://server/showReport?LAST_NAME=smith
菜单“Build”->“Execute reportusing active conn.

11
)创建子报表
例子:一个报表包含另一个报表
1)建立两个报表;
2)扩展master报表,增加一个subreport元素;
3)双击subreport元素,设置其属性。在Subreportother)栏中,
Subreport Expression
填入“c:/test2.jasper”(第二个表即子表的文件名),点击“Add”,增加/修改:“Subreport parameter name”Default value expression值;(COUNTRY     $F{COUNTRY}
4)对子表“Report query”->添加'where COUNTRY=${COUNTRY}'
5)增加“Report parameters”,(COUNTRYjava.lang.String)
6)编译detail report
7)运行master report


iReport
支持Groovy脚本语言,可无需懂Java

1、配置XML文件
jasperreports
XML配置文件局域jasperreport.dtd文件而来。

1
)根元素jasperReport
其子元素有:报告的字体reportFont,参数parameter,查询字符串queryString,字段field,变量variable,组group,标题title,页眉pageHeader,列眉columnHeader,表明细detail,列脚columnFooter,页脚pageFooter
属性有:列宽columnWidth,列间距columnSpacing,左边距leftMargin,顶边距topMargin,底边距bottomMargin

2
)报表层字体含义reportFonts
无子元素;
属性有:名字name,是否缺省isFault,字体名fontName,字体大小size,是否粗体isBold,是否斜体isItalic,是否带下划线isUnderlineisStrikeThroughPDF字体名pdfFontNamePDF编码pdfEncoding,是否嵌入PDFisPdfEmbedded)。

3
)用于产生报表的对象参数parameter。引用P${name}
其子元素有:ParameterDescriptiondefaultValueExpression
属性有:nameclass

4
)从数据库检索数据的查询SQL语句 queryString

5
)包含于report中的数据库表列字段 field 引用F${name}
其子元素有:variableExpressioninitialValueExpression
属性有:nameclass

6
)用在XML文件中的变量 Variable   引用V${name}
其子元素有:variableExpressioninitialValueExpression
属性有:nameclass

7
)报表标题 title
其子元素有:band
无属性

8
)页眉 pageHeader
其子元素有:band
无属性

9
)报表的列名 columnHeader
其子元素有:band
无属性

10
)指定的列值detail
其子元素有:band
无属性

11
)列尾columnFooter
其子元素有:band
无属性

12
)页脚pageFooter
其子元素有:band
无属性
注:在report中,一个band表示一个report节点。一个band元素包括:staticText(静态文本)和textElement(文本元素)两个元素。
常见报表模型:列表、分组、主从、嵌套、交叉、图形、套打、分栏、填报。

2
、创建报表

1
)建立输入源
InputStream input = new FileInputStream(new File("c://JasperReports//catalog.xml"));
JasperDesign design=JRXmlLoader.load(Input);

2
)创建对象
JasperReport report = JasperCompileManager.compileReport(design);

3
)获得JDBC连接从数据库检索数据
InitialContext initialContext = new InitialContext();
DataSource ds = (DataSource)initialContext.lookup("java:comp/env/jdbc/OracleDBConnectionDS");
Connection conn = ds.getConnection();

4
)产生可预览、打印、输出为其它格式的JasperPrint文件
JasperPrint print = JasperFillManager.fillReport(report, parameters, conn);

5
)参数处理
Map parameters = new HashMap();
parameters.put("ReportTitle", "PDF JasperReport");

6
)输出成XMLPDFHTMLCSVXLSExcel)的任一种文件。
OutputStream output = new FileOutputStream(new File("c:/JasperReports/catalog.pdf"))
JasperExportManager.exportReportToPdfStream(print,output);

3
JasperReports的安装配置

1
JDK的安装,注意JAVA_HOME环境变量;
2
)要支持中文,需itext-1.3.1.jariTextAsian.jar包,加入CLASSPATH环境变量中;
3
)安装iReport,用iReport-1.3.0-windows-installer.exe安装;
4
JasperReport不需任何配置,将其jar包(jasperreports-1.3.0.jar)放入CLASSPATH
5
)数据库的JDBC驱动包,例如Sybase的驱动包为jconn6.jar,加入到CLASSPATH

4
iReport的安装配置

iReport如果不用其安装文件iReport-1.3.0-windows-installer.exe安装,则需要配置。
iReport
Sun公司的JDK下的tools.jar,需拷贝到iReportlib目录下。
iReport
初始化配置的组成:
1)建立报表;
2)选择语言;
3)加入到CLASSPATH


四、Report Structure 报告的结构

本章描述报告的结构,可用的report对象和它们的属性。这基本上是JasperReports的快速参考。

1
Expressions 表达式
表达式是JasperReports的核心特征。它是一个重要的机制,允许操纵和显示报告数据,执行各种计算,自定义报告的外观和报告对象的可视性。

1
)一个典型的表达式
$F{LastName} + " " + $F{LastName}
一个JasperReports的表达式是以Java表达式为基础的,再加上一些附加的语法,它允许引用参数、变量和字段等。
比如说要引用一个名叫DATA的参数时,语法应为$P{PARAM_NAME}
对变量和字段来说,其引用语法分别为$V{VAR_NAME}$F{FIELD_NAME}
注意:在JasperReportsgroovy脚本语言中,也同样可以用$F$P$V引用参数、变量和字段。

2
)表达式的语法
1$F{FIELD}   引用名为FIELD的字段;
2$V{VAR}     引用名为VAR的变量;
3$P{PARAM}   引用名为PARAM的参数;
4$P!{PARAM} 引用名为PARAM的参数;这个特殊的语法仅能用于report的查询中。它允许插入参数的内容到查询字符串中。例如,它能被用于创建一个带通过参数来指定WHERE条件的动态查询。
$R{keyName}     
resource bundle中检索带keyName关键字的字符串。
注意:表达式是用JavaGroovy写成的,这意外着可以用Java强大的功能,如调用方法,允许构建无限复杂的表达式。还要注意,表达式的结果总是一个对象。

3
)更多的表达式
1new Integer(Math.max($V{Price1},$V{Price2}))
2(new SimpleDateFormat("dd/MM/yyyy")).format($F{OrderDate})
3$F{SpecialOffer}.booleanValue()? $F{SpecialPrice} : $F{Price}

2
、内建的函数
JasperReports提供了一套内建的函数用于report表达式中。这些函数尽管是内建的工具,还是可以在普通操作中执行它。
注意:目前这套函数很有限,在未来会得到扩展。

1)
例:使用内建函数
msg("Total cost is {0}", $F{TOTAL})
msg("Matched {0} products out of {1}", $F{MATCHED}, $P{TOTAL})

2)
内建的函数
1String str(String key);
从和report相联系的resource bundle中得到给出的key的一个字符串。这个函数的功能和使用$R{key}语法等价。
2String msg(String pattern, Object arg0);
建立一个带给定的pattern和给定参数来指定其格式的java.util.MessageFormat对象。
3String msg(String pattern, Object arg0, Object arg1);
同上;
4String msg(String pattern, Object arg0, Object arg1, Object arg2);
同上。

3
Report 报告
Report
是表现为报告模板的根对象。在报告执行期间,report模板和数据组合成最终的文档。
报告的属性有:
1Report Name 报告名;
2Units 报告的单位;有:像素Pixels,毫米Millimeters,厘米Centimeters和英寸Inches
3Language 报告表达式使用的语言;目前有JavaGroovy两种。
4Orientation 页的方向;其可能值为水平Protrait和纵向Landscape
5Page Width 以报告单位指定的页宽;
6Page Height 以报告单位指定的页高;
7Page Size 报告的尺寸,即为page widthpage height
8Left Margin 以报告单位指定的左边页边距;
9Right Margin 以报告单位指定的右边页边距;
10Top Margin 以报告单位指定的顶部页边距;
11Bottom Margin 以报告单位指定的底部页边距;
12Column Count 报告中的列数;
13Column Spacing 以报告单位指定的列边距;
14Column Width 以报告单位指定的列宽;
15Print Order 填充列的顺序;有垂直Vertical和水平Horizontal两种。
16Float Column Footer 浮动列脚,指出是否在列底部或明细表最后或组脚进行打印;
17Default Font 缺省字体;
18Default Style 缺省风格;
19Scriptlet Class 脚本类,它必须是JRAbstractScriptlet类的子类。如果省略,将创建一个JRDefaultScriptlet的实例。
20Summary New Page 新页的概要;
21Title New Page 新页的标题;
22When No Data Print 无数据时的打印,有三个选择:No Pages 表示0页;Blank Page 空白页;All Sections No Detail 除了detail section,其它的都打印。
23Query 查询,用来检索数据到报告中。
24Query Language 查询语言,有五个值:SQL 用于JDBC数据源的查询语言;HBM Hibernate用于Hibernate数据源的查询语言;XPath 用于XML数据源的查询语言;EJBQL用于支持Java持久层(PersistenceAPI的数据源的查询语言;MDX 用于Mondrian数据源的查询语言。
25Imports java输入的列表,例如:java.util.*java.text.SimpleDateFormat格式。用于简化report的表达式。
26Resource Bundle report提供了本地的系列字符串。在报告中,本地字符串能用$R{key}引用。
27When Resource Missing Print 允许自定义引擎在resource bundle中处理丢失的resource。有4种选择:Null 丢失的resource不打印;Empty 丢失的resource为空;Key $R{key}指定的key来打印; Error 用错误来中断报告的执行。

4
Styles 风格
一个report可以定义大量的风格。一旦定义了,它们能和report对象联系起来,为了给各种可视视图提供基本的配置。report允许用模块化的方式来定义模块的风格。
风格有相关联的条件风格。条件风格允许当其表达式为真时改变风格。

1
)风格的属性有:
1Name 风格名;
2Parent Style 父风格;
3Foreground 前景色;
4Background 背景色;
5Mode 方式,决定是否带透明度;
6Pen 画笔 6种选择:None 无线;1 Point 正常宽度的线;2 Point 中等宽度的线;4 Point 粗线;Dotted 虚线;Thin 细线。
7Fill 填充;决定对对象进行填充的模式;
8Box 指定盒子的属性,如边框类型,边框颜色,是否填充。
9Horizontal Alignment 水平排列;有3种选择:Left 左;Center 中;Right 右。
10Vertical Alignment 垂直排列;有3种选择:Top 顶;Middle 中;Bottom 底。
11Scale 比例;指定图像的比例,有3种选择:Clip 尺寸不适合时,多余部分省略;Fill Frame 图像按比例填充进Image对象中;Retain Shape 保留原形状进行填充。
12Radius 指定矩形边框倒角的弧度;
13Pattern Text Field表达式的值来指定样式;其日期类型的值用java.text.SimpleDataFormat类来定义;其数值型的值用java.text.DecimalFormat来定义。
14Blank When Null Text Field表达式的值为null时显示空白;
15Line Spacing 线距;有3种选择:Single:单倍线距;1 and 1/21.5倍线距;Double:双倍线距。
16Rotation 旋转;有3种选择:None 不旋转;Left 左旋180度;Right 右旋180度。
17Styled Text 是一个标志位,用来指定是否text对象包含了已定义风格或规则的text
18Font Name 字体名;
19Font Size 字体的尺寸;
20Bold 粗体;
21Italic 斜体;
22Underline 下划线;
23Strike Through 通过标准位来取消;
24PDF Font NamePDF字体名;
25PDF EncodingPDF编码;
26PDF Embedded是一个标志位,指定是否PDF字体应该嵌入到文档中。

2
)条件风格的属性:
和上面仅有一点点的不同。其不同的属性为:
Condition Expression
条件表达式;是一个布尔型的表达式,用于判断是否应用条件表达式。

5
Section Properties 节属性
Section的种类前面已经讲了,这里只是补充讲述它的属性:
1Height 以报告的单位指定的section的高度;
2Print When Expression 是一个布尔表达式,决定是否打印本Section
3Split Allowed 一个标志位,指示当Section超过当前页面的尺寸时,是否允许分割它。如果为真,当前Section将迁移到下一页。注意:如果Section在下一页也不适合时,则不管标志位值如何,都会分割它。

6
Groups
一个report可以定义大量的组。组表示决定带相关数据的可视组的表达式名。一旦声明后,组能在报告任意地方使用。
一个数据组用一个表达式组来识别。
注意:组机制不能完成来自于数据源数据的任何排序。如果想要有序的数据,必须把数据源的数据进行先排序处理。
组属性:
1Name 组名;用于引用组。
2Expression 表达式;决定report数据的组;
3Min Height To Start New Page 开始新页的最小高度;
4Reprint Header On Each Page 一个标志位,指示在每一页的开始处是否重新打印组头;
5Reset Page Number 重设页数,一个标志位;在组头在新页开始处打印时,是否重新设置页数;
6Start New Column 一个标志位,是否在新列中总是打印组头;
7Start New Page 一个标志位,是否在新页中总是打印组头;

 


五、JasperReports作为一种开源的报表库为应用提供了强大的支持。其易用性和
灵活性为系统的开发提供了极大的便利。


在报表生成过程中,使用JDBC等传统数据源操作方法获取数据的过程会消耗大量的系统时间,这样就需要利用其它手段来简化数据源操作。
在这种情况下,适当的使用ORMObject/Relational Mapping)技术,能够很好的解决这个问题,对于系统性能的提升有很大的帮助。

1
JasperReports填充报表

要完成报表的填充,必须先完成用于报表的xml模板,其过程是先产生报表布局对象,再序列号该对象,存储在磁盘或者网络,用于产生特定应用的表格数据。
实际上,表单的设计过程就是用定义于xml文件中的java表达式来表现报表的布局。
编辑过程中会有各种保证数据一致性的验证,最终会产生相关数据的文档。
报表引擎必须先接受数据来产生报表,这些数据一般来源于各种数据源,报表引擎能直接接收用于填充表格的数据源对象,或者通过自身提供的JDBC连接对象来处理数据库的数据。
报表最终要产生一个新的对象来进行填充操作从而产生用于输出的文档对象,这也是一个存储在磁盘或者网络传输介质的序列化对象。
JasperReports
的内置浏览器能直接查看结果或者以PDF,HTML,XML形式将其导出。

2
、持久化技术和ORM

持久化(Persistence),即把数据保存到可永久保存的存储设备中(如磁盘)。
持久化的主要应用是将内存中的数据存储在关系型的数据库中,当然也可以存储在磁盘文件中、XML数据文件中等。
ORM
对象-关系型数据映射组件。对于O/R,即Object(对象)和Relational(关系型数据),表示必须同时使用面向对象和关系型数据进行开发。
MVC
Model View Control)中的Model包含了复杂的业务逻辑和数据逻辑,以及数据存取机制(如JDBC的连接、SQL生成和Statement创建、还要ResultSet结果集的读取等)。将这些复杂的业务逻辑和数据逻辑分离,以将系统的紧耦合关系转化为松耦合关系(即解耦合),是降低系统耦合度迫切要做的,也是持久化要做的工作。
MVC
模式实现了架构上将表现层和数据处理层分离的解耦合,而持久化设计则实现了数据处理层内部的业务逻辑和数据逻辑分离的解耦合。
关系型数据库中的数据基本都是以一行行的数据进行存取的,而程序运行却是一个个对象进行处理,而目前大部分数据库驱动技术(如ADO.NETJDBCODBC等)均是以行集的结果集一条条进行处理的。所以为解决这一困难,就出现ORM这一个对象和数据之间映射技术。

3
、在JasperReports中使用Hibernate

Hibernate是一个开发源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。
Hibernate
可以应用在任何使用JDBC的场合,既可以在Java的客户端程序使用,也可以在Servlet/JSPWeb应用中使用,最具革意义的是,Hibernate可以在应用EJBJ2EE架构中取代CMP,完成数据持久化的重任。

package src;

import java.util.HashMap;
import java.util.List;

import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JasperCompileManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
import net.sf.jasperreports.engine.design.JasperDesign;
import net.sf.jasperreports.engine.xml.JRXmlLoader;
import net.sf.jasperreports.engine.JasperExportManager;

import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class Simple1  {
public static void main(String args[]) {
   String sampleReportFile=
new String("reports/sampleReport.jrxml");
   
//Hibernate Result Set Holder.
   List bowlerInfo=null;
   
try {
    
//Configure the Hibernate session
    Configuration cfg=new Configuration();
    cfg.addResource("hibernate-mapping.xml");
    SessionFactory sessions=cfg.buildSessionFactory();
    
//Open the Hibernate Session
    Session session=sessions.openSession();
    
//Returns all SampleData records.
    //Simple POJO object.
    bowlerInfo=session.createQuery("from SampleData").list();
    
//Fill the parameters
    HashMap parameters=new HashMap();
    parameters.put("ReportTitle","Bowling Scores");
    parameters.put("NoOfGames", 
new Integer(3));
    
//Load the sample report file from the XML file
    //into the JasperDesign object.
    JasperDesign design=JRXmlLoader.load(sampleReportFile);
    
//Compile the Report in Memory storing it in a JasperReport object
    //no .jasper report file is created.
    JasperReport report=new JasperCompileManager().compileReport(design);
    
//Fill the report using the JRBeanCollectionDataSource passed
    //a Hibernate query result set.
    JasperPrint print=JasperFillManager.fillReport(report,parameters,new JRBeanCollectionDataSource(bowlerInfo));
    
//Export to PDF file.
    JasperExportManager.exportReportToPdfFile(print,"simpleHibernatExample.pdf");
    
//Close the Hibernate Session.
    session.close();   
   }
catch(JRException jre) {
    jre.printStackTrace();
   }
catch(MappingException me) {
    me.printStackTrace();
   }
catch(HibernateException he) {
    he.printStackTrace();
   }
}
}


 

Hibernate检索返回集合类型的对象时,使用JRBeanCollection接口可将数据通过HibernatePOJOPlain Old Java Object)实例映射到报表域中,使用JRXmlLoader.load(templateName)方法加载报表模板,最后通过JasperFillManager方法将数据填入模板中。
本例使用JasperExportManager.exportReportToPdfFile()方法将报表输出为PDF格式。JasperReports提供的net.sf.jasperreports.engine.JRExporter接口可以方便的将报表输出为PDFXLSCSVRTFHTML或者XML格式,目前以PDFEXCEL格式较为通用。

4
、总结

JasperReports中使用了Hibernate以后,如果随业务更换数据源的话,只需要更好Hibernate的映射文件,极大提高了代码的可重用性,同时由于Hibernate本身对于查询的优化,也能很好的提高整个应用的效率,尽可能的节省开发时间。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值