HTML5的数据存储.ppt

上传人:工**** 文档编号:568202518 上传时间:2024-07-23 格式:PPT 页数:34 大小:1.42MB
返回 下载 相关 举报
HTML5的数据存储.ppt_第1页
第1页 / 共34页
HTML5的数据存储.ppt_第2页
第2页 / 共34页
HTML5的数据存储.ppt_第3页
第3页 / 共34页
HTML5的数据存储.ppt_第4页
第4页 / 共34页
HTML5的数据存储.ppt_第5页
第5页 / 共34页
点击查看更多>>
资源描述

《HTML5的数据存储.ppt》由会员分享,可在线阅读,更多相关《HTML5的数据存储.ppt(34页珍藏版)》请在金锄头文库上搜索。

1、本章要求本章要求:第第7 7章章 HTML5HTML5的数据存储的数据存储uWeb Storage的基本概念usessionStorage和localStorage两者之间的区别usessionStorage和localStorage的使用方法u使用sessionStorage和localStorage进行复杂数据的存储usessionStorage和localStorage进行JavaScript对象的存储u使用transactoin方法进行事务的处理主要内容主要内容1. Web Storage2. Web SQL数据库3. 跨文档消息通信4. 综合实例简单的Web留言本第第7 7章章 HT

2、ML5HTML5的数据存储的数据存储7.1 Web Storage7.1 Web Storage7.1.1 Web Storage简介7.1.2 WebStorage的API7.1.3 两种不同存储类型的实例计数器7.1.4 JSON对象的存数实例用户信息卡 在HTML5中,除了Canvas元素之外,另一个新增的非常重要的功能是可以在客户端本地保存数据的Web Storage功能。Web应用的发展,使得客户端存储使用得也越来越多,而实现客户端存储的方式则是多种多样。 最简单而且兼容性最佳的方案是Cookie,但是作为真正的客户端存储,cookie还是有些不足:p大小:cookies的大小被限制

3、在4KB。p带宽:cookies是随HTTP事物一起发送的,因此会浪费一部分发送cookies时使用的带宽。p复杂性:cookies操作起来比较麻烦;所有的信息要被拼到一个长字符串里面。p对cookies来说,在相同的站点与多事务处理保持联系不是很容易。在这种情况下,在HTML5中重新提供了一种在客户端本地保存数据的功能,它就是Web Storage功能。 Web Storage功能,顾名思义,就是在Web上存储数据的功能,而这里的存储,是针对客户端本地而言的。它包含两种不同的存储类型:Session Storage和Local Storage。不管是Session Storage还是Loca

4、l Storage,它们都能支持在同域下存储5MB数据,这相比cookies有着明显的优势。psessionStorage 将数据保存在session对象中。所谓session,是指用户在浏览某个网站时,从进入网站到浏览器关闭所经过的这段时间,也就是用户浏览这个网站所花费的时间。Session对象可以用来保存在这段时间内所要求保存在任何数据。plocalStorage 将数据保存在客户端本地的硬件设备中,即使浏览器被关闭了,该数据仍然存在,下次打开浏览器访问网站时仍然可以继续使用。这两种不同的存储类型区别在于,sessionStorage为临时保存,而localStorage为永久保存。7.1

5、.1 Web Storage7.1.1 Web Storage简介简介下面讲解如何使用WebStorage的API,目前WebStorage的API有如下这些:pLength:获得当前webstorage中的数目。pkey(n):返回webstorage中的第N个存储条目。pgetItem(key):返回指定key的存储内容,如果不存在则返回null。注意,返回的类型是String字符串类型。psetItem(key, value):设置指定key的内容的值为value。premoveItem(key):根据指定的key,删除键值为key的内容。pclear:清空webstorate的内容。

6、可以看到,webstorage API的操作机制实际上是对键值对进行的操作。下面是一些相关的应用:1数据的存储与获取在localStorage中设置键值对数据可以应用setItem(),代码如下:localStorage.setItem(key, value);获取数据可以应用getItem(),代码如下;var val = localStorage.getItem(key);当然也可以直接使用localStorage的key方法,而不使用setItem和getItem方法,如下:localStorage.key = value;var val = localStorage.key;7.1.2

7、 WebStorage7.1.2 WebStorage的的APIAPI HTML5存储是基于键值对(key/value)的形式存储的,每个键值对称为一个项(item)。 存储和检索数据都是通过指定的键名,键名的类型是字符串类型。值可以是包括字符串、布尔值、整数,或者浮点数在内的任意JavaScript支持的类型。但是,最终数据是以字符串类型存储的。 调用结果是将字符串value设置到sessionStorage中,这些数据随后可以通过键key获取。调用setItem()时,如果指定的键名已经存在,那么新传入的数据会覆盖原先的数据。调用getItem()时,如果传入的键名不存在,那么会返回nul

8、l,而不会抛出异常。2数据的删除和清空removeItem()用于从Storage列表删除数据代码如下:var val = sessionStorage.removeItem(key);也可以通过传入数据项的key从而删除对应的存储数据代码如下:var val = sessionStorage.removeItem(1);说明: 数字1会被转换为string,因为key的类型就是字符串。clear()方法用于清空整个列表的所有数据,代码如下:sessionStorage.clear();同时可以通过使用length属性获取Storage中存储的键值对的个数:var val = sessionS

9、torage.length;注意: removeItem可以清除给定的key所对应的项,如果key不存在则“什么都不做”;clear会清除所有的项,如果列表本来就是空的就“什么都不做”。【例例7-17-1】 本节通过一个实例来具体看一下sessionStorage和localStorage的区别。本例主要是通过sessionStorage和localStorage对页面的访问量进行计数。当在文本框内输入数据后,分别可以单击“session保存”按钮和“local保存”按钮对数据进行保存,还可以通过“session读取”按钮和“local读取”按钮对数据进行读取。但是两种方法对数据的处理方式不一

10、样,使用sessionStorage方法时,如果关闭了浏览器,这个数据就丢失了下一次打开浏览器,点击读取数据按钮时,读取不到任何数据。使用localStorage方法时,即使浏览器关闭了,下次打开浏览器时仍然能够读取保存的数据。但是,数据保存是按不同的浏览器分别进行的,也就是说,如果打开别的浏览器,是读取不到在这个浏览器中保存的数据的。实现本例的具体步骤如下:(1)首先,需要准备一个用来保存数据的网页。在本例网页中,在页面上放置的控件如表所示7-1所示。表7-1 Web Storage示例的页面中元素7.1.3 7.1.3 两种不同存储类型的实例两种不同存储类型的实例计数器计数器元素id用途i

11、nput type=texttext-1输入数据pmsg_1显示数据buttonbtn-1session保存buttonbtn-2session读取buttonbtn-3local保存buttonbtn-4local读取spansession_countsession计数spanlocal_countlocal计数该实例的HTML页面代码如下。 要保存的数据: session计数:   local计数: (2)在javascript脚本中分别使用了sessionStorage和localStorage两种方法。这两种方法都是当用户在input文本框中输入内容时“sessio

12、n保存”按钮和“local保存”按钮对数据进行保存,通过“session读取”按钮和“local读取”按钮对数据进行读取。实现的代码如下。function getE(ele) /自定义一个getE()函数/返回并调用document对象的getElementById方法输出变量 return document.getElementById(ele); var text_1 = getE(text-1), /声明变量并为其赋值 mag = getE(msg_1), btn_1 = getE(btn-1), btn_2 = getE(btn-2), btn_3 = getE(btn-3), btn

13、_4 = getE(btn-4); btn_1.onclick = saveSessionStorage; btn_2.onclick = loadSessionStorage; btn_3.onclick = saveLocalStorage; btn_4.onclick = loadLocalStorage; function saveSessionStorage() sessionStorage.setItem(msg,text_1.value + session); function loadSessionStorage() mag.innerHTML = sessionStorage

14、.getItem(msg); function saveLocalStorage() localStorage.setItem(msg,text_1.value + local); function loadLocalStorage() mag.innerHTML = localStorage.getItem(msg); (3)最后,通过三元运算符来定义记录页面的次数,然后通过setItem方法对数据进行保存,代码如下。var local_count = localStorage.getItem(a_count)?localStorage.getItem(a_count):0; getE(lo

15、cal_count).innerHTML = local_count; localStorage.setItem(a_count,+local_count+1); var session_count = sessionStorage.getItem(a_count)?sessionStorage.getItem(a_count):0; getE(session_count).innerHTML = session_count; sessionStorage.setItem(a_count,+session_count+1); 本例在Opera10浏览器中的运行结果如图7-1所示。图7-1 Op

16、era10浏览器中的WebStorage示例 虽然HTML5 Web Storage规范允许将任意类型的对象保存为键值对形式,实际情况却是一些浏览器将数据限定为文本字符串类型。不过,既然现代浏览器原生支持JSON,这就解决了这个问题。JSON格式是Javascript Object Notation的缩写,是将Javascript中的对象作为文本形式来保存时使用的一种格式。 JSON是一种将对象与字符串可以相互表示的数据转换标准。JSON一直是通过HTTP将对象从浏览器传送到服务器一种常用格式。现在,可以通过序列化复杂对象将JSON数据保存在Storage中,以实现复杂数据类型的持久化。7.1

17、.4 JSON7.1.4 JSON对象的存数实例对象的存数实例用户用户信息卡信息卡【例例7-27-2】 该实例中,将用户的信息使用JSON格式进行保存。使用JSON的格式作为文本保存来保存对象,获取该对象时再通过JSON格式来获取,可以保存和读取具有复杂结构的数据。本例实现的具体过程如下。(1)编写显示页面用的HTML代码部分。在该页面中,除了输入数据用的文本框与显示数据用的p元素之外,还放置了“保存”与“按姓名查询”按钮,点击“保存按钮”来保存数据,点击“按姓名查询”按钮来查询用户信息,实现的代码如下。 姓名: EMAIL: 电话号码: 备注: 查询::(2)在HTML页面中调用saveSt

18、orage函数来对数据实现保存,在这个函数中首先从各输入文本框中获取数据,然后创建对象,将获取的数据作为对象的属性进行保存。为了将数据保存在一个对象中,使用new Object语句创建了一个对象,将各种数据保存在该对象的各个属性中,为了将对象转换成JSON格式的文本数据,使用了JSON对象的stringify方法。该方法的使用方法如下。var str = JSON.stringify(data); 该方法接受一个参数data,该参数表示要转换成JSON格式文本数据的对象。这个方法的作用是将对象转换成JSON格式的文本数据,并将其返回。最后将文本数据保存在localStorage中,实现的代码如

19、下。function saveStorage() var data = new Object; data.name = document.getElementById(name).value; data.email = document.getElementById(email).value; data.tel = document.getElementById(tel).value; data.memo = document.getElementById(memo).value; var str = JSON.stringify(data); localStorage.setItem(dat

20、a.name,str); alert(数据已保存。);(3)在HTML页面中调用findStorage函数,对数据进行查询。在该函数中,首先从localStorage中,将查询用的姓名作为键值,获取对应的数据。将获取的数据转换成JSON对象。该函数的关键是使用JSON对象的parse方法,将从localStorage中获取的数据转换成JSON对象。该方法的使用方法如下。var data = JSON.parse(str); 该方法接受一个参数str,此参数表示从localStorage中取得的数据,该方法的作用是将传入的数据转换为JSON对象,并且将该对象返回。在取得JSON对象的各个属性值之

21、后,创建要输出的内容,最后将要输出的内容在页面上输出。实现的代码如下。function findStorage(id) var find = document.getElementById(find).value; var str = localStorage.getItem(find); var data = JSON.parse(str); var result = 姓名: + data.name + ; result += EMAIL: + data.email + ; result += 电话号码: + data.tel + ; result += 备注: + data.memo +

22、; var target = document.getElementById(id); target.innerHTML = result; 用户信息卡分为姓名、E-mail地址、电话号码、说明这几列,把它们保存在localStorage中。在查询中以用户的姓名进行检索,可以获取这个用户的所有联系信息。用户信息卡的运行效果如下7-2所示。图7-2 使用JSON对象实现的用户信息卡7.2 Web SQL7.2 Web SQL数据库数据库7.2.1 Web SQL数据库简介7.2.2 Web SQL Database API的使用 在HTML5中,大大丰富了客户端本地可以存储的内容,添加了很多功能

23、来将原本必须要保存在服务器上的数据转为保存在客户端本地,从而大大提高了Web应用程序的性能,减轻了服务器端的负担。在这其中,一项非常重要的功能就是数据库的本地存储功能。在HTML5中内置了一个可以通过SQL语言来访问数据库。在HTML4中,数据库只能放在服务器端,只能通过服务器来访问数据库,但是在HTML5中,可以就像访问本地文件那样轻松地对内置数据库进行直接访问了。 现在,像这种不需要存储在服务器上的,被称为“SQLite”的文件型SQL数据库已经得到了很广泛的利用,所以HTML5中也采用了这种数据库来作为本地数据库。因此,如果先掌握了SQLite数据库的基本知识的话,接着再学如何使用HTM

24、L5的数据库也就不是很难了。7.2.1 Web SQL7.2.1 Web SQL数据库简介数据库简介 典型的数据库API的用法,涉及打开数据库,然后执行一些SQL。但是需要注意的是如果使用服务器端的一个数据库的话,通常还要关闭数据库连接。1打开和创建数据库 通过初次打开一个数据库,就会创建数据库。在任何时间,在该域上只能拥有指定数据库的一个版本,因此如果你创建了版本1.0,那么应用程序在没有特定地改变数据库的版本时,将无法打开1.1。 打开和创建数据库必须使用openDatabase方法来创建一个访问数据库的对象。该方法的使用方法如下。var db=openDatabase( db, 1.0

25、, first database,2*1024*1024); 该方法使用四个参数,第一个参数为数据库名,第二个参数为版本号,第三个参数为数据库的描述,第四个参数为数据库的大小。该方法返回创建后的数据库访问对象,如果该数据库不存在,则创建该数据库。 为了确保应用程序有效,并且检测对Web SQL数据库API的支持,还应该测试浏览器对数据库的支持,所以要进行测试,测试代码如下。var db;if(window.openDatabase)db = openDatabase(mydb, 1.0 , My first database,2*1024*1024);7.2.2 Web SQL Databas

26、e API7.2.2 Web SQL Database API的使用的使用2创建数据表 实际访问数据库的时候,还需要使用transaction方法,用来执行事务处理。使用事务处理,可以防止在对数据库进行访问及执行有关操作的时候受到外界的打扰。因为在Web上,同时会有许多人都在对页面进行访问。如果在访问数据库的过程中,正在操作的数据被别的用户给修改掉得话,会引起很多意想不到的后果。因此,可以使用事务来达到在操作完了之前,阻止别的用户访问数据库的目的。transaction方法的使用方法如下。db.transaction(function(tx)tx.executeSql(CREATE TABLE

27、 tweets(id,date,tweet);); transaction方法使用一个回调函数为参数。在这个函数中,执行访问数据库的语句。要创建数据表(以及数据库上的任何其他事务),必须启动一个数据库“事务”,并且在回调中创建该表。事务回调接受一个参数,其中包含了事务对象,这就是允许运行SQL语句并且运行 executeSql方法(在下面的例子中,就是tx)的内容。这通过使用从openDatabase返回的数据库对象来完成,并且像下面这种调用事物的方法如下。var db;if(window.openDatabase)db = openDatabase(mydb, 1.0 , My first

28、database,2*1024*1024); db.transaction(function(tx)tx.executeSql(CREATE TABLE tweets(id,date,tweet););3插入和查询数据 接下来,我们来看一下在transaction的回调函数内,到底是怎样访问数据库的。这里,使用了作为参数传递给回调函数的transaction对象的executeSql方法。executeSql方法的完整定义如下。transaction.executeSql(sqlquery,dataHandler,errorHandler);该方法使用四个参数,第一个参数为需要执行的SQL语句

29、。第二个参数为SQL语句中所有使用到的参数的数组。在executeSql方法中,将SQL语句中所要使用到的参数先用“?”代替,然后依次将这些参数组成数组放在第二个参数中,如下。transaction.executeSql(UPDATE user set age=? where name=?;,age,name);第三个参数为执行sql语句成功时调用的回调函数。该回调函数的传递方法如下。function dataHandler(transaction,results)/执行SQL语句成功时的处理;该回调函数使用两个参数,第一个参数为transaction对象,第二个参数为执行查询操作时返回的查询

30、到的结果数据集对象。第四个参数为执行SQL语句出错时调用的回调函数。该回调函数的传递方法如下。function errorHandler(transaction,errmsg)/执行SQL语句出错时的处理;该回调函数使用两个参数,第一个参数为transaction对象,第二个参数为执行发生错误时的错误信息文字。 下面我们来看一下,当执行查询操作时,如何从查询到的结果数据集中,依次把数据取出到页面上来,最简单的方法是使用for语句循环。结果数据集对象有一个rows属性,其中保存了查询到的每条记录,记录的条数可以用rows.length来获取。可以用for循环,用rowindex或rows.Ite

31、m(index)的形式来依次取出每条数据。在JavaScript脚本中,一般采用rowindex的形式。这里需要注意的是在google Chrome5浏览器中,不支持rows.Item(index)的形式。7.3 7.3 跨文档消息通信跨文档消息通信7.3.1 postMessageAPI的使用7.3.2 跨文档消息传输 首先,要想接受从其他的窗口那里发过来的信息,就必须对窗口对象的message时间进行监视,代码如下。window.addEventListener(message,function().,false);使用window对象的postMessage方法向其他窗口发送信息,该方法

32、的定义如下。otherWindow.postMessage(message,targetOrigin); 该方法使用两个参数;第一个参数为所发送的消息文本,但也可以是任何javascript对象(通过JSON转换对象为文本);第二个参数为接收信息的对象窗口的URL地址(例如http:/localhost:8080/)。可以在URL地址字符串中使用通配符“*”指定全部地址,不过,建议使用准确的URL地址。otherWindow为要发送窗口对象的引用,可以通过window.open返回该对象,或通过对window.iframes数组指定序号(index)或名字的方式来返回单个iframe所属的窗口

33、对象。7.3.1 postMessageAPI7.3.1 postMessageAPI的使用的使用 【例例7-37-3】 为了让读者更好的理解跨文档消息传输,下面编写一个实例,实现主页面与子页面中框架之间的相互通信。其基本思路是:首先,创建主页面向iframe子页面发送消息,iframe子页面接受消息,显示在本页面中,然后向主页面返回消息。最后,主页面接受并输出消息注意: 要完成这个示例,必须先建立两个虚拟的网站,将主页面与子页面分别放置于不同的网站中,才能够达到跨域通信的效果。7.3.2 7.3.2 跨文档消息传输跨文档消息传输 这里介绍一种在Apache服务器下创建虚拟主机的方法,并且将主

34、页面和子页面分别存储于这两个虚拟主机下,以此完成跨域通信的示例。(1)安装配置Apache服务器(建议采用AppServ集成化安装包来搭建一个PHP的开发环境,通过其中的Apache服务器来测试我们的程序)。(2)定位到Apache2.2confhttpd.conf文件,打开该文件,并在其最后的位置,添加如下内容,完成虚拟主机的配置。其代码如下: ServerAdmin DocumentRoot F:wampwebpagecxkfzykhtml ServerName 192.168.1.59 ErrorLog logs/-error.log CustomLog logs/-access.lo

35、g common第一行,定义虚拟服务器的标签,指定端口号;第二行,指定一个邮箱地址,可以随意指定;第三行,定义要访问的项目在Apache服务器中的具体路径;第四行,指定服务器的访问名称,即与项目绑定的域名;第五、六行,定义Apache中日志文件的存储位置。第七行,定义虚拟服务器的结束标签。 上述七行代码即完成一个虚拟服务器的配置操作,如果存在多个域名,并且需要绑定Apache服务器下的多个项目,那么就以此类推,重复上述操作,为每个域名绑定不同的项目文件即可。即修改DocumentRoot和ServerName指定的值。(3)在完成虚拟主机的配置之后,需要保存httpd.conf文件,重新启动A

36、pache服务器。(4)然后,编写示例内容,首先创建一个index.html文件,其代码如下:跨域通信示例/ 监听message事件window.addEventListener(message, function(ev) /忽略指定URL地址之外的页面传过来的消息 if(ev.origin != http:/192.168.1.189) return;/显示消息 alert(从+ev.origin + 那里传过来的消息:n + ev.data + );, false);function hello()var iframe = window.frames0; /传递消息 iframe.post

37、Message(“您好!”, “http:/192.168.1.189”);跨域通信示例将其存储于服务器的访问名称为192.168.1.59的虚拟主机下,具体位置由DocumentRoot的值决定。(5)在IP为192.168.1.189的主机下,重新创建一个虚拟主机,设置其服务器访问地址为192.168.1.189,将子页面2.html存储于该服务器指定的位置。2.html的完整代码如下:window.addEventListener(message, function(ev)if(ev.origin != http:/192.168.1.59)return; document.body.i

38、nnerHTML = 从+ev.origin + 那里传来的消息。+ ev.data + ; /向主页面发送消息 ev.source.postMessage(明日科技欢迎您!这里是 + this.location, ev.origin);, false); 至此,已经完成虚拟主机的配置和跨域通信示例内容的创建,下面则可以通过指定的浏览器访问主页面(http:/192.168.1.59/),其运行效果如图7-3所示。图7-3 跨域通信实例7.4 7.4 综合实例综合实例简单的简单的WebWeb留言本留言本 本实例将使用HTML5存储技术实现一个简单的Web留言本,具体实现时,使用一个多行文本框输

39、入数据,单击按钮时,将文本框中的数据保存到localStorage中,然后在表单下部放置一个P元素来显示保存后的数据。程序在Opera 10浏览器中的运行结果如图7-4所示。图7-4 简单的Web留言本程序开发步骤如下:(1)首先,编写显示页面用的HTML代码部分。在该页面中,除了输入数据用的文本框与显示数据用的p元素之外,还放置了“添加按钮”与“全部清除”按钮,点击“添加按钮”来保存数据,点击“全部清除”按钮来消除全部数据,实现的代码如下。简单Web留言本(2)接下来在javascript脚本中,编写点击“添加”按钮时调用的saveStorage函数,在这个函数中使用“new Date().

40、getTime()”语句得到了当前的日期和时间戳,然后调用localStorage.setItem方法,将得到的时间戳作为键值,并将文本框中的数据作为键名进行保存。保存完毕后,重新调用脚本中的loadStorage函数在页面上重新显示保存后的数据。实现的代码如下。function saveStorage(id) var data = document.getElementById(id).value; var time = new Date().getTime(); localStorage.setItem(time,data); alert(数据已保存。); loadStorage(msg)

41、;(3)获取保存数据主要是先用loadStorage.length属性获取保存数据的条数,然后做一个循环,在循环内用一个变量,从0开始将该变量作为index参数传入loadStorage.key(index)属性,每次循环时该变量加1,以此取得保存在loadStorage中的所有数据。实现的代码如下。function loadStorage(id) var result = ; for(var i = 0;i localStorage.length;i+) var key = localStorage.key(i); var value = localStorage.getItem(key);

42、 var date = new Date(); date.setTime(key); var datestr = date.toGMTString(); result += + value + + datestr + ; result += ; var target = document.getElementById(id); target.innerHTML = result;(4)单击“全部清除”按钮时,调用clearStorage函数对数据进行全部清除,在这个函数中只有一句语句“localStorage.clear()”,调用localStorage的clear方法时,所有保存在loca

43、lStorage中的数据会全部被清除,实现代码如下。function clearStorage() localStorage.clear(); alert(全部数据被清除。); loadStorage(msg);(1)Web Storage功能,顾名思义,就是在Web上存储数据的功能,而这里的存储,是针对客户端本地而言的。它包含两种不同的存储类型:Session Storage和Local Storage。(2)所谓session,是指用户在浏览某个网站时,从进入网站到浏览器关闭所经过的这段时间,也就是用户浏览这个网站所花费的时间。(3)localStorage是将数据保存在客户端本地的硬件设

44、备中,即使浏览器被关闭了,该数据仍然存在,下次打开浏览器访问网站时仍然可以继续使用。(4)JSON格式是Javascript Object Notation的缩写,是将Javascript中的对象作为文本形式来保存时使用的一种格式,它是一种将对象与字符串可以相互表示的数据转换标(5)打开和创建数据库必须使用openDatabase方法来创建一个访问数据库的对象。(6)实际访问数据库的时候,还需要使用transaction方法,用来执行事务处理。知识点提炼7-1 Web Storage存储技术分为哪两种?7-2 Session Storage和Local Storage有什么区别?7-3 简单描述JSON的主要作用。7-4 Web SQL数据库技术中主要用到的是哪种数据库?7-5 如何在HTML5中实现跨文档消息通信?习题

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 高等教育 > 研究生课件

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号