收藏 分享(赏)

Freemaker_入门+深入+开发指南+学习笔记.doc

上传人:暖洋洋 文档编号:1605356 上传时间:2018-08-10 格式:DOC 页数:76 大小:590KB
下载 相关 举报
Freemaker_入门+深入+开发指南+学习笔记.doc_第1页
第1页 / 共76页
Freemaker_入门+深入+开发指南+学习笔记.doc_第2页
第2页 / 共76页
Freemaker_入门+深入+开发指南+学习笔记.doc_第3页
第3页 / 共76页
Freemaker_入门+深入+开发指南+学习笔记.doc_第4页
第4页 / 共76页
Freemaker_入门+深入+开发指南+学习笔记.doc_第5页
第5页 / 共76页
点击查看更多>>
资源描述

1、1Freemaker 入门 +深入+开发指南+学习笔记freemaker 的基本语法freemaker 的基本语法:中存放所有 freemaker 的内容,之外的内容全部原样输出。是函数调用两个定界符内的内容中,第一个符号表示指令或者函数名,其后的跟随参数。freemaker 提供的控制包括如下: 条件判断遍历 hash 表或者collection(freemaker 称作 sequence)的成员 宏,无返回参数函数,有返回参数var?member_function(.) 用函数对 var 进行转换,freemaker 称为build-ins。实际内部实现类似 member_function

2、(var, .)stringAM N 取子字符串,类似 substring(stringA, M, N)key:value, key2:value2 . 直接定义一个 hash 表item0, item1, item2 . 直接定义一个序列hash0key0 存取 hash 表中 key 对应的元素seq05 存取序列指定下标的元素 调用函数 function1nest_body 调用宏,并处理宏的嵌套定义变量并初始化在 macro 或者 function 中定义局部变量并初始化 定义全局变量并初始化$var 输出并替换为表达式的值调用 macro 匹配 xmlnode 本身及其子节点调用 m

3、acro 匹配 xmlnode 的子节点FreeMaker 一篇通 【转】FreeMaker 一篇通【转】2007-08-09 19:382FreeMaker 一篇通前言Freemaker 是一个强大的模板引擎,相比 velocity 而言,其强大的过程调用、递归和闭包回调功能让 freemaker 可以完成几乎所有我们所想的功能。从个人看法而言,freemaker 完全有能力作为 MDA 的代码辅助生成工具。 本文试图越过传统的概念性介绍,通过一组例子直接把读者带入到 Freemaker应用的较高层阶。正文大家看文章标题就应该知道,我想用一篇文章,把大家从对 freemaker 的陌生直接带

4、入到比较深入的境界,所以不想说一些基础性的东西,如果大家不习惯我的表达方法,大可通过 google 去找习惯于自己阅读方式的相关文章。我用过 velocity,最近才用 freemaker,才知道我以前的选择是错了,因为velocity 不支持过程的调用,所以我为 velocity 增加了很多的东西,写了很多代码,而且脚本也累赘得要命。freemaker 首先吸引我的是它强大的过程调用和递归处理能力,其次则是 xml 风格的语法结构有着明显的边界,不象 velocity要注意段落之间要留空格。所以我建议大家直接使用 Freemaker,虽然freemaker 没有.net 版本,我想不嵌入程序

5、中使用的话,freemaker 是绝对的首选。(题外话,谁有兴趣移植一个 NFreeMaker?)在使用之前我们先要设置运行环境,在使用 Freemaker 的时候,我们需要下载相关的程序:freemaker: http:/ http:/ 其中 fmpp 是一个 freemaker 的辅助工具,有了它,我们可以实现更多的功能。以下例子必须 fmpp 辅助。这里我们首先提出问题。大家看如下的一个 xml 文件,虽然 freemaker 的能力不仅在于处理 xml 文件,但是用 xml 作为例子更直观一些:10代码 1我们的任务是把这个文件转化为相应的 C#代码。大家先看转换模板的代码:1 23

6、45 67 8 91011 12 class $.node.name 1113 14 15 16171819 public $.node.type $.node.name;202122 232425代码 2我们使用的配置文件设置如下:sourceRoot: srcoutputRoot: outlogFile: log.fmppmodes: copy(common/*/*.*, resource/*.*)execute(*.ftl)ignore(templates/*.*, .project, */*.xml, xml/*.*, *.js)removeExtensions: ftlsourceE

7、ncoding: gb2312data: doc: xml(freemaker.xml)代码 3然后我们在 dos 模式下运行指令:E:workblogsfreemakerf:downloadfreemakerfmppbinfmpp最后的输出结果是这样的,存放在文件 outfreemaker.中:class Type1 public Float Field11;public String Field12;public Integer Field13;public Type2 Field14;public Float Field15;12class Type3 public Type1 Fiel

8、d31;代码 4先来解释一下 freemaker 的基本语法了,中存放所有 freemaker 的内容,之外的内容全部原样输出。是函数调用两个定界符内的内容中,第一个符号表示指令或者函数名,其后的跟随参数。freemaker 提供的控制包括如下:条件判断遍历 hash 表或者collection(freemaker 称作 sequence)的成员宏,无返回参数函数,有返回参数var?member_function(.) 用函数对 var 进行转换,freemaker 称为 build-ins。实际内部实现类似 member_function(var, .)stringAM N 取子字符串,类似

9、 substring(stringA, M, N)key:value, key2:value2 . 直接定义一个 hash 表item0, item1, item2 . 直接定义一个序列hash0key0 存取 hash 表中 key 对应的元素seq05 存取序列指定下标的元素调用函数 function1nest_body 调用宏,并处理宏的嵌套定义变量并初始化在 macro 或者 function 中定义局部变量并初始化定义全局变量并初始化$var 输出并替换为表达式的值调用 macro 匹配 xmlnode 本身及其子节点调用 macro 匹配 xmlnode 的子节点表 1大家仔细对比

10、 xml 文件,发现少了什么吗?对了,少了一个 Type2 定义,我们把代码 2 中的 ns:type 匹配(第 11 行)修改一下:13public $.node.type $.node.name;代码 5结果输出文件中的内容就变为如下:class Type1 public Float Field11;public String Field12;public Integer Field13;public Type2 Field14;class Type2 public String Field21;public Integer Field22;public Float Field15;cla

11、ss Type3 public Type1 Field31;代码 6如果各位有意向把 Type2 提到跟 Type1 和 Type3 同一级别的位置,那么我们要继续修改代码了。把代码 2 的 行(第 5 行)修改成如下:代码 714同时把 macro ns:field(第 18 行)修改成如下:public $.node.type $.node.name;代码 8运行得到输出文件类似这样:class Type1 public Float Field11;public String Field12;public Integer Field13;public Type2 Field14;publi

12、c Float Field15;class Type3 public Type1 Field31;class Type2 public String Field21;public Integer Field22;代码 9大家比较一下,看看我们修改的地方出现了哪些效果?然后记得大家要做另外2 件事情,1。把第一行修改成为 ,然后把所有的 修改成,把所有的.node“ns:type“修改成 .node.type,看看能不能运行?是不是觉得简单方便些了?记住,第一行的那个 D 表示是 default namespace 的意思哦。2。在第二行插入,在最后一行添加。再运行一下看15看结果有什么不同?一

13、个例子下来,大家基本对 freemaker 有了一些感觉了,为了纠正大家认为freemaker 就是一个 xml 处理工具的误解,我们再来做一个简单的实验。这次我们要做的是一个正常的编程题目,做一个 100 以内的 Fibonacci 数列的程序。程序如下:迭代次数:$n = $fibo(n)代码 10这个例子里边有一些问题需要注意,大家看我的 #if n lte 1 这一行,为什么我这么写?因为常规的大于小于号和 xml 的节点有冲突,为了避免问题,所以用 gt() gte(=) lt($str(mid - cnt) (mid + cnt)?left_pad(mid*2)代码 11最后,说一

14、下非常有用的 macro 的 nested 指令,没有它,也许 freemaker 会失去大部分的魅力。我个人认为这也是 freemaker 全面超越 velocity 的地方。大16家先看一下代码:$msg $index代码 12这段代码的作用就是一个闭包(closure)。我们用 java 的匿名类实现相同的功能就是这样:interface ICallbackpublic void call(int index);void Main()String msg = “hello“;macro0(new ICallback()public void call(int index)System.o

15、ut.println(msg + index.toString(););void macro0(ICallback callback)for(int i = 0; i 中存放所有 freemaker 的内容,之外的内容全部原样输出。是函数调用两个定界符内的内容中,第一个符号表示指令或者函数名,其后的跟随参数。freemaker 提供的控制包括如下:条件判断遍历 hash 表或者collection(freemaker 称作 sequence)的成员宏,无返回参数函数,有返回参数var?member_function(.) 用函数对 var 进行转换,freemaker 称为build-ins。

16、实际内部实现类似 member_function(var, .)stringAM N 取子字符串,类似 substring(stringA, M, N)key:value, key2:value2 . 直接定义一个 hash 表item0, item1, item2 . 直接定义一个序列hash0key0 存取 hash 表中 key 对应的元素seq05 存取序列指定下标的元素调用函数 function1nest_body 调用宏,并处理宏的嵌套定义变量并初始化在 macro 或者 function 中定义局部变量并初始化定义全局变量并初始化$var 输出并替换为表达式的值调用 macro

17、匹配 xmlnode 本身及其子节点调用 macro 匹配 xmlnode 的子节点 repeatThis 一个 ftl 标记不能放在另外一个 ftl 标记里面,但是注释标记能够放在 ftl标记里面。系统预定义指令采用用户自定义指令采用18hash 片段可以采用: products1019 or products5 的格式。序列也可以做加法计算:passwords + “joe“:“secret42“缺省值: name!“unknown“ 或者 (user.name)!“unknown“ 或者 name! 或者 (user.name)!null 值检查: name? or (user.name

18、)?转义列表:Escape sequence Meaning“ Quotation mark (u0022) Apostrophe (a.k.a. apostrophe-quote) (u0027) Back slash (u005C)n Line feed (u000A)r Carriage return (u000D)t Horizontal tabulation (a.k.a. tab) (u0009)b Backspace (u0008)f Form feed (u000C)l Less-than sign: a Ampersand: and 数字变量插入方式: #expression

19、 or #expression; format:过期。变量只能用于文本区或者是字符串里面,比如:Hello $name!以及 数字值的插入:根据缺省的 number_format 输出,以及可以通过 setting 来达到设置数字格式的目的,也可以通过内置函数 string 来改变输出格式。日期类型的格式设置:date_format, time_format 和 datetime_format定义宏:不带参数:.,引用带参数:.,引用,带有参数的宏,调用是参数的值必须和参数的个数相同。当然也可以在宏定义时给参数一些默认值。比如:宏里面的嵌套内容:在宏的定义 body 中加入指令。嵌套的内容可以

20、是任何正确的 ftl 块。宏的本地变量在嵌套内容中是不可见的。21宏定义时,指令相当于调用定义的内容,而使用宏时,nest body 相当于定义。$c. $halfc Last! 定义变量:在模板中定义的变量将会隐藏(不是更改)数据模型根下面的同名的变量。模板中的 3 种类型变量:1:plain variables,能够在模板中的任何地方访问,一个模板 include 另外一个模板,也可以访问被包含模板的变量。可以通过 assign 或者 macro 指令产生或替换变量。如果要访问数据模型中的变量,则可以通过.global 来访问:$user $.globals.user 2:Local va

21、riables,宏定义 body 中用 local 指令创建或者替换。3:Loop variables:由 list 指令产生。namespaces:$my.mail 设置命名空间里面的变量:命名空间与数据模型:命名空间的 ftl 可以访问数据模型的变量。同样命名空间的变量也会隐藏数据模型中同名的变量。空白问题:1:White-space stripping,默认为 enabled,清除 ftl 标记带来的空白以及缩进。处理模板的空白。2:t, rt, lt 指令。3:ftl 的参数 strip_text.用 compress directive 或者 transform 来处理输出。.:消除

22、空白行。./compress 将输出压缩为一行。可替换语法:22freemarker 可用“代替“模板 test.html 可以稍做修改,加入 Freemarker 内置的格式化功能来定制 Date 类型的输出格式。Spring_FreemarkerHello, $name, it is $time?string(“yyyy-MM-dd HH:mm:ss“)添加 freemarker.jar 到 web/WEB-INF/lib 目录后,启动 Resin,可以看到由Freemarker 渲染的页面23FreeMarker 入门文章引用自: 1、快速入门 (1)模板 + 数据模型 = 输出 l F

23、reeMarker 基于设计者和程序员是具有不同专业技能的不同个体的观念 l 他们是分工劳动的:设计者专注于表示创建 HTML 文件、图片、Web 页面的其它可视化方面;程序员创建系统,生成设计页面要显示的数据 l 经常会遇到的问题是:在 Web 页面(或其它类型的文档)中显示的信息在设计页面时是无效的,是基于动态数据的 l 在这里,你可以在 HTML(或其它要输出的文本)中加入一些特定指令,FreeMarker会在输出页面给最终用户时,用适当的数据替代这些代码 l 下面是一个例子: Welcome! Welcome $user! Our latest product: $latestProd

24、uct.name! l 这个例子是在简单的 HTML 中加入了一些由$包围的特定代码,这些特定代码是FreeMarker 的指令,而包含 FreeMarker 的指令的文件就称为模板(Template) l 至于 user、latestProduct.url 和 latestProduct.name 来自于数据模型(data model) l 数据模型由程序员编程来创建,向模板提供变化的信息,这些信息来自于数据库、文件,甚至于在程序中直接生成 l 模板设计者不关心数据从那儿来,只知道使用已经建立的数据模型 l 下面是一个可能的数据模型: (root) | +- user = “Big Joe“

25、 | +- latestProduct | +- url = “products/greenmouse.html“ | +- name = “green mouse“ l 数据模型类似于计算机的文件系统,latestProduct 可以看作是目录,而 user、url24和 name 看作是文件,url 和 name 文件位于 latestProduct 目录中(这只是一个比喻,实际并不存在) l 当 FreeMarker 将上面的数据模型合并到模板中,就创建了下面的输出: Welcome! Welcome Big Joe! Our latest product: green mouse! (

26、2)数据模型 l 典型的数据模型是树型结构,可以任意复杂和深层次,如下面的例子: (root) | +- animals | | | +- mouse | | | | | +- size = “small“ | | | | | +- price = 50 | | | +- elephant | | | | | +- size = “large“ | | | | | +- price = 5000 | | | +- python | | | +- size = “medium“ | | | +- price = 4999 | +- test = “It is a test“ | +- whatn

27、ot | +- because = “dont know“ l 类似于目录的变量称为 hashes,包含保存下级变量的唯一的查询名字 l 类似于文件的变量称为 scalars,保存单值 25l scalars 保存的值有两种类型:字符串(用引号括起,可以是单引号或双引号)和数字(不要用引号将数字括起,这会作为字符串处理) l 对 scalars 的访问从 root 开始,各部分用“.”分隔,如 animals.mouse.price l 另外一种变量是 sequences,和 hashes 类似,只是不使用变量名字,而使用数字索引,如下面的例子: (root) | +- animals | |

28、 | +- (1st) | | | | | +- name = “mouse“ | | | | | +- size = “small“ | | | | | +- price = 50 | | | +- (2nd) | | | | | +- name = “elephant“ | | | | | +- size = “large“ | | | | | +- price = 5000 | | | +- (3rd) | | | +- name = “python“ | | | +- size = “medium“ | | | +- price = 4999 | +- whatnot | +- fru

29、its | +- (1st) = “orange“ | +- (2nd) = “banana“ l 这种对 scalars 的访问使用索引,如 animals0.name (3)模板 l 在 FreeMarker 模板中可以包括下面三种特定部分: ? $:称为 interpolations,FreeMarker 会在输出时用实际值进行替代 26? FTL 标记(FreeMarker 模板语言标记):类似于 HTML 标记,为了与 HTML 标记区分,用#开始(有些以开始,在后面叙述) ? 注释:包含在(而不是)之间 l 下面是一些使用指令的例子: ? if 指令 Pythons are che

30、aper than elephants today. Pythons are not cheaper than elephants today. ? list 指令 We have these animals: NamePrice $being.name$being.price Euros 输出为: We have these animals: NamePrice mouse50 Euros elephant5000 Euros python4999 Euros ? include 指令 Test page Test page Blah blah. ? 一起使用指令 We have these

31、 animals: NamePrice 27$being.name $being.price Euros FreeMarker 设计指南快速入门 (1)模板 + 数据模型 = 输出 FreeMarker 基于设计者和程序员是具有不同专业技能的不同个体的观念他们是分工劳动的:设计者专注于表示创建 HTML 文件、图片、Web 页面的其它可视化方面;程序员创建系统,生成设计页面要显示的数据。经常会遇到的问题是:在 Web 页面(或其它类型的文档)中显示的信息在设计页面时是无效的,是基于动态数据的。在这里,你可以在 HTML(或其它要输出的文本)中加入一些特定指令,FreeMarker 会在输出页面

32、给最终用户时,用适当的数据替代这些代码。先来解释一下 freemaker 的基本语法了,中存放所有 freemaker 的内容,之外的内容全部原样输出。是函数调用两个定界符内的内容中,第一个符号表示指令或者函数名,其后的跟随参数。freemaker 提供的控制包括如下:条件判断遍历 hash 表或者 collection(freemaker 称作sequence)的成员宏,无返回参数函数,有返回参数var?member_function(.) 用函数对 var 进行转换,freemaker 称为 build-ins。实际内部实现类似 member_function(var, .)stringA

33、M N 取子字符串,类似 substring(stringA, M, N)key:value, key2:value2 . 直接定义一个 hash 表item0, item1, item2 . 直接定义一个序列hash0key0 存取 hash 表中 key 对应的元素seq05 存取序列指定下标的元素调用函数 function1nest_body 调用宏,并处理宏的嵌套定义变量并初始化28在 macro 或者 function 中定义局部变量并初始化定义全局变量并初始化$var 输出并替换为表达式的值调用 macro 匹配 xmlnode 本身及其子节点调用 macro 匹配 xmlnode

34、 的子节点下面是一个例子: Welcome!Welcome $user!Our latest product:$latestProduct.name!这个例子是在简单的 HTML 中加入了一些由$包围的特定代码,这些特定代码是 FreeMarker 的指令,而包含 FreeMarker 的指令的文件就称为模板(Template)。至于 user、latestProduct.url 和 latestProduct.name 来自于数据模型(data model)。数据模型由程序员编程来创建,向模板提供变化的信息,这些信息来自于数据库、文件,甚至于在程序中直接生成。模板设计者不关心数据从那儿来,只

35、知道使用已经建立的数据模型。下面是一个可能的数据模型: (root)|+- user = “Big Joe“|+- latestProduct|+- url = “products/greenmouse.html“|+- name = “green mouse“数据模型类似于计算机的文件系统,latestProduct 可以看作是目录。 2、数据模型 (1)基础 在快速入门中介绍了在模板中使用的三种基本对象类型:scalars 、hashes 和 sequences,其实还可以有其它更多的能力: scalars:存储单值 hashes:充当其它对象的容器,每个都关联一个唯一的查询名字 sequ

36、ences:充当其它对象的容器,按次序访问 方法:通过传递的参数进行计算,以新对象返回结果 29用户自定义 FTL 标记:宏和变换器 通常每个变量只具有上述的一种能力,但一个变量可以具有多个上述能力,如下面的例子: (root)|+- mouse = “Yerri“|+- age = 12|+- color = “brown“ mouse 既是 scalars 又是 hashes,将上面的数据模型合并到下面的模板: $mouse $mouse.age $mouse.color 输出结果是: Yerri12brown (2)Scalar 变量 Scalar 变量存储单值,可以是: 字符串:简单文

37、本,在模板中使用引号(单引号或双引号)括起 数字:在模板中直接使用数字值 日期:存储日期/时间相关的数据,可以是日期、时间或日期-时间(Timestamp);通常情况,日期值由程序员加到数据模型中,设计者只需要显示它们 布尔值:true 或 false,通常在标记中使用 (3)hashes 、sequences 和集合 有些变量不包含任何可显示的内容,而是作为容器包含其它变量,者有两种类型: hashes:具有一个唯一的查询名字和它包含的每个变量相关联 sequences:使用数字和它包含的每个变量相关联,索引值从 0 开始 集合变量通常类似 sequences,除非无法访问它的大小和不能使用

38、索引来获得它的子变量;集合可以看作只能由指令使用的受限 sequences (4)方法 方法变量通常是基于给出的参数计算值。 下面的例子假设程序员已经将方法变量 avg 放到数据模型中,用来计算数字平均值: The average of 3 and 5 is: $avg(3, 5)The average of 6 and 10 and 20 is: $avg(6, 10, 20)The average of the price of python and elephant is: $avg(animals.python.price, animals.elephant.price)(5)宏和变换

39、器 宏和变换器变量是用户自定义指令(自定义 FTL 标记),会在后面讲述这些高级特性 30(6)节点 节点变量表示为树型结构中的一个节点,通常在 XML 处理中使用,会在后面的专门章节中讲 3、模板 (1)整体结构 模板使用 FTL(FreeMarker 模板语言)编写,是下面各部分的一个组合: 文本:直接输出 Interpolation:由$ 和,或#和 来限定,计算值替代输出 FTL 标记:FreeMarker 指令,和 HTML 标记类似,名字前加 #予以区分,不会输出 注释:由限定,不会输出 下面是以一个具体模板例子: Welcome!Welcome $user!We have the

40、se animals:$being.name for $being.price Euros注意事项: FTL 区分大小写,所以 list 是正确的 FTL 指令,而 List 不是;$name和$NAME是不同的 Interpolation 只能在文本中使用 FTL 标记不能位于另一个 FTL 标记内部,例如: =bar.注释可以位于 FTL 标记和 Interpolation 内部,如下面的例子: Welcome $user !We have these animals:animals as being. 余的空白字符会在模板输出时移除 (2)指令 在 FreeMarker 中,使用 FTL

41、 标记引用指令。有三种 FTL 标记,这和 HTML标记是类似的: 31开始标记: 结束标记: 空内容指令标记: 有两种类型的指令:预定义指令和用户定义指令。 用户定义指令要使用替换#,如.(会在后面讲述)。 FTL 标记不能够交叉,而应该正确的嵌套,如下面的代码是错误的: $being.name for $being.price Euros(except for you)如果使用不存在的指令,FreeMarker 不会使用模板输出,而是产生一个错误消息。 FreeMarker 会忽略 FTL 标记中的空白字符,如下面的例子: $being.name for $being.price Euro

42、s但是, a JerryTOM JERRY 操作符优先顺序 操作符组 操作符 后缀 subvarName subStringRange . (methodParams) 一元 +expr、-expr、! 内建 ? 乘法 *、 / 、% 加法 +、- 关系 、=(lt、lte、gt、gte) 相等 =(=)、!= 逻辑 and format 注意:Interpolation 只能用于文本部分 通用 Interpolation 插入字符串值:直接输出表达式结果 插入数字值:根据缺省格式(由#setting 指令设置)将表达式结果转换成文本输出;可以使用内建函数 string 格式化单个 Inter

43、polation,下面是一个例子: 37$answer$answer?string $answer?string.number$answer?string.currency$answer?string.percent 输出结果是: $42.00$42.0042$42.004,200%插入日期值:根据缺省格式(由#setting 指令设置)将表达式结果转换成文本输出;可以使用内建函数 string 格式化单个 Interpolation,下面是一个使用格式模式的例子: $lastUpdated?string(“yyyy-MM-dd HH:mm:ss zzzz“)$lastUpdated?stri

44、ng(“EEE, MMM d, yy“)$lastUpdated?string(“EEEE, MMMM dd, yyyy, hh:mm:ss a (zzz)“) 输出的结果类似下面的格式: 2003-04-08 21:24:44 Pacific Daylight TimeTue, Apr 8, 03Tuesday, April 08, 2003, 09:24:44 PM (PDT)插入布尔值:根据缺省格式(由#setting 指令设置)将表达式结果转换成文本输出;可以使用内建函数 string 格式化单个 Interpolation,下面是一个例子: $foo?string(“yes“, “no“)输出结果是: yes数字 Interpolation 的#expr; format形式可以用来格式化数字,format 可以是: mX:小数部分最小 X 位 MX:小数部分最大 X 位 例子: #x; M2 #y; M2 #x; m1 #y; m1 #x; m1M2 #y; m1M2 4、杂项 (1)用户定义指令 宏和变换器变量是两种不同类型的用户定义指令,它们之间的区别是宏是在模板中使用 macro指令定义,而变换器是在模板外由程序定义,这里只介绍宏 基本用法

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 专业基础教材

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报