这篇文章给大家介绍Python中怎么利用Altair实现数据制图,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。绘图流程我通过绘制同一个多柱状图比较了多个 Python 绘图库的差异。正式开始之前,你需要将你的 Python 环境调整到能运行下面代码的状态。具体就是:安装最新版的 Python( Linux、Mac 和 Windows 系统下的安装方法)确认该版本 Python 可以运行本教程所使用的库演示用数据可从网络下载,并且可以用 pandas 直接导入:import pandas as pddf = pd.read_csv('https://anvil.works/blog/img/plotting-in-python/uk-election-results.csv')准备开始吧。为了做个比较,先看下面这个用 Matplotlib 做的图:Matplotlib UK election results使用 Matplotlib 需要 16 行代码,图柱的位置需要自己计算。使用 Altair 绘制相似的图,代码如下: import altair as alt chart = alt.Chart(df).mark_bar().encode( x='party', y='seats', column='year', color='party', ) chart.save('altair-elections.html')真是简洁多了!与 Seaborn 类似,Altair 所用数据的组织形式是每个变量一列(即 数据列 )。这种方式下可以将每个变量映射到图的一个属性上 —— Altair 称之为“通道”。在上例中,我们期望每个 “党派” 在 x 轴上显示为一组图柱, 其 “席位” 显示在 y 轴,且将图柱按照 “年份” 分开为 “列”。我们还想根据 “党派” 给图柱使用不同的 “颜色”。用语言表述需求的话就是上面这个样子,而这也正是代码所要表述的!现在把图画出来:Altair plot with default styling调整样式这和我们期待的效果有点接近了。与 Matplotlib 方案相比,主要区别在于 Altair 方案中,每个 year 组显示的时候,内部之间都有个小空白 —— 这不是问题,这只是 Altair 多柱状图显示的一个特性。所以说呢,还需要对显示样式再做一些改进。非整形数据两个不是整数的年份名称(Feb 1974 和 Oct 1974)显示为 NaN 了。这可以通过将年份数值 year 转换为字符串来解决: df['year'] = df['year'].astype(str)指定数据排序方法还需要让 Altair 知道如何对数据进行排序。Altair 允许通过传给它一个 Column 对象,来设定 Column 通道的更多细节。现在让 Altair 按照数据在数据集中出现的顺序排列: chart = alt.Chart(df).mark_bar().encode( # ... column=alt.Column('year', sort=list(df['year']), title=None), # ... )移除坐标轴标签我们通过设置 title=None 移除了图顶的 "year" 标签。下面再一处每列数据的 "party" 标签: chart = alt.Chart(df).mark_bar().encode( x=alt.X('party', title=None), # ... )指定颜色图最后,我们还想自己指定图柱的颜色。Altair 允许建立 domain 中数值与 range 中颜色的映射来实现所需功能,太贴心了: cmap = { 'Conservative': '#0343df', 'Labour': '#e50000', 'Liberal': '#ffff14', 'Others': '#929591', } chart = alt.Chart(df).mark_bar().encode( # ... color=alt.Color('party', scale=alt.Scale(domain=list(cmap.keys()), range=list(cmap.values()))) )样式调整后的最终代码应用上述样式调整之后,代码看起来不那么悦目了,但我们仍然是用声明的方式实现的,这正是 Altair 如此有弹性的原因所在。实现过程中,仍然是使用的异于显示数据的独立变量来分离图中不同属性的,而不是像在 Matplotlib 中那样直接对显示数据做复杂的操作。唯一的不同是,我们的变量名字封装在类似 alt.X() 的对象中,从而实现对显示效果的控制: import altair as alt from votes import long as df cmap = { 'Conservative': '#0343df', 'Labour': '#e50000', 'Liberal': '#ffff14', 'Others': '#929591', } df['year'] = df['year'].astype(str) # We're still assigning, e.g. 'party' to x, but now we've wrapped it # in alt.X in order to specify its styling chart = alt.Chart(df).mark_bar().encode( x=alt.X('party', title=None), y='seats', column=alt.Column('year', sort=list(df['year']), title=None), color=alt.Color('party', scale=alt.Scale(domain=list(cmap.keys()), range=list(cmap.values()))) ) chart.save('altair-elections.html')现在与 Matplotlib 方案扯平了,代码数量达到了 16 行!下图是使用我们的样式调整方案之后的 Altair 效果图:关于Python中怎么利用Altair实现数据制图就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。...
本篇内容主要讲解“linux下怎么读取使用iso镜像文件的方法”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“linux下怎么读取使用iso镜像文件的方法”吧!如果拷贝到本地,可以使用mount mount fileName mountPoint -o loop,fileName是镜像文件名(*.iso,*.img), 用例:如我有一个/home/rhel5.2.iso光盘镜像文件, mkdir /mnt/b mount /home/rhel5.2.iso /mnt/b -o loop,这样进入目录/mnt/b 你就能浏览rhel5.2.iso的内容了,*.img文件的用法一样。 其它一些可能对你有用,供参考 linux是一个优秀的开放源码的操作系统,可以运行在大到巨型小到掌上型各类计算机系统上,随着linux系统的日渐成熟和稳定以及它开放源代码特有的优越性,linux在全世界得到了越来越广泛的应用。现在许多企业的计算机系统都是由UNIX系统、Linux系统和Windows系统组成的混合系统,不同系统之间经常需要进行数据交换。下面我根据自己的实际工作经验介绍一下如何在linux系统下挂接(mount)光盘镜像文件、移动硬盘、U盘以及Windows网络共享和UNIX NFS网络共享。 挂接命令(mount) 首先,介绍一下挂接(mount)命令的使用方法,mount命令参数非常多,这里主要讲一下今天我们要用到的。 命令格式: mount [-t vfstype] [-o options] device dir 其中: 1.-t vfstype 指定文件系统的类型,通常不必指定。mount 会自动选择正确的类型。常用类型有: 光盘或光盘镜像:iso9660 DOS fat16文件系统:msdos Windows 9x fat32文件系统:vfat Windows NT ntfs文件系统:ntfs Mount Windows文件网络共享:smbfs UNIX(LINUX) 文件网络共享:nfs 2.-o options 主要用来描述设备或档案的挂接方式。常用的参数有: loop:用来把一个文件当成硬盘分区挂接上系统 ro:采用只读方式挂接设备 rw:采用读写方式挂接设备 iocharset:指定访问文件系统所用字符集 3.device 要挂接(mount)的设备。 4.dir设备在系统上的挂接点(mount point)。 挂接光盘镜像文件 由于近年来磁盘技术的巨大进步,新的电脑系统都配备了大容量的磁盘系统,在Windows下许多人都习惯把软件和资料做成光盘镜像文件通过虚拟光驱来使用。这样做有许多好处:一、减轻了光驱的磨损;二、现在硬盘容量巨大存放几十个光盘镜像文件不成问题,随用随调十分方便;三、硬盘的读取速度要远远高于光盘的读取速度,CPU占用率大大降低。其实linux系统下制作和使用光盘镜像比Windows系统更方便,不必借用任何第三方软件包。 1、从光盘制作光盘镜像文件。将光盘放入光驱,执行下面的命令。 #cp /dev/cdrom /home/sunky/mydisk.iso 或 #dd if=/dev/cdrom of=/home/sunky/mydisk.iso 注:执行上面的任何一条命令都可将当前光驱里的光盘制作成光盘镜像文件/home/sunky/mydisk.iso 2、将文件和目录制作成光盘镜像文件,执行下面的命令。 #mkisofs -r -J -V mydisk -o /home/sunky/mydisk.iso /home/sunky/ mydir 注:这条命令将/home/sunky/mydir目录下所有的目录和文件制作成光盘镜像文件/home/sunky/mydisk.iso,光盘卷标为:mydisk 3、光盘镜像文件的挂接(mount) #mkdir /mnt/vcdrom 注:建立一个目录用来作挂接点(mount point) #mount -o loop -t iso9660 /home/sunky/mydisk.iso /mnt/vcdrom 注:使用/mnt/vcdrom就可以访问盘镜像文件mydisk.iso里的所有文件了。 挂接移动硬盘 对linux系统而言,USB接口的移动硬盘是当作SCSI设备对待的。插入移动硬盘之前,应先用fdisk –l 或 more /proc/partitions查看系统的硬盘和硬盘分区情况。 [root at pldyrouter /]# fdisk -l Disk /dev/sda: 73 dot 4 GB, 73407820800 bytes 255 heads, 63 sectors/track, 8924 cylinders Units = cylinders of 16065 * 512 = 8225280 bytes Device Boot Start End Blocks Id System /dev/sda1 1 4 32098+ de Dell Utility /dev/sda2 * 5 2554 20482875 7 HPFS/NTFS /dev/sda3 2555 7904 42973875 83 Linux /dev/sda4 7905 8924 8193150 f Win95 Ext'd (LBA) /dev/sda5 7905 8924 8193118+ 82 Linux swap 在这里可以清楚地看到系统有一块SCSI硬盘/dev/sda和它的四个磁盘分区/dev/sda1 -- /dev/sda4, /dev/sda5是分区/dev/sda4的逻辑分区。接好移动硬盘后,再用fdisk –l 或 more /proc/partitions查看系统的硬盘和硬盘分区情况 [root at pldyrouter /]# fdisk -l Disk /dev/sda: 73 dot 4 GB, 73407820800 bytes 255 heads, 63 sectors/track, 8924 cylinders Units = cylinders of 16065 * 512 = 8225280 bytes Device Boot Start End Blocks Id System /dev/sda1 1 4 32098+ de Dell Utility /dev/sda2 * 5 2554 20482875 7 HPFS/NTFS /dev/sda3 2555 7904 42973875 83 Linux /dev/sda4 7905 8924 8193150 f Win95 Ext'd (LBA) /dev/sda5 7905 8924 8193118+ 82 Linux swap Disk /dev/sdc: 40.0 GB, 40007761920 bytes 255 heads, 63 sectors/track, 4864 cylinders Units = cylinders of 16065 * 512 = 8225280 bytes Device Boot Start End Blocks Id System /dev/sdc1 1 510 4096543+ 7 HPFS/NTFS /dev/sdc2 511 4864 34973505 f Win95 Ext'd (LBA) /dev/sdc5 511 4864 34973473+ b Win95 FAT32 大家应该可以发现多了一个SCSI硬盘/dev/sdc和它的两个磁盘分区/dev/sdc1?、/dev/sdc2,其中/dev/sdc5是/dev/sdc2分区的逻辑分区。我们可以使用下面的命令挂接/dev/sdc1和/dev/sdc5。 #mkdir -p /mnt/usbhd1 #mkdir -p /mnt/usbhd2 注:建立目录用来作挂接点(mount point) #mount -t ntfs /dev/sdc1 /mnt/usbhd1 #mount -t vfat /dev/sdc5 /mnt/usbhd2 注:对ntfs格式的磁盘分区应使用-t ntfs 参数,对fat32格式的磁盘分区应使用-t vfat参数。若汉字文件名显示为乱码或不显示,可以使用下面的命令格式。 #mount -t ntfs -o iocharset=cp936 /dev/sdc1 /mnt/usbhd1 #mount -t vfat -o iocharset=cp936 /dev/sdc5 /mnt/usbhd2 到此,相信大家对“linux下怎么读取使用iso镜像文件的方法”有了更深的了解,不妨来实际操作一番吧!这里是辰讯云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!...
RPC服务与HTTP服务的区别是什么,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。1、什么是RPCRPC(Remote Procedure Call)—远程过程调用,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层和应用层。RPC使得开发包括网络分布式多程序在内的应用程序更加容易。RPC采用客户机/服务器(c/s)模式。请求程序就是一个客户机,而服务提供程序就是一个服务器。首先,客户机调用进程发送一个有进程参数的调用信息到服务进程,然后等待应答信息。在服务器端,进程保持睡眠状态直到调用信息到达为止。当一个调用信息到达,服务器获得进程参数,计算结果,发送答复信息,然后等待下一个调用信息,最后,客户端调用进程接收答复信息,获得进程结果,然后调用执行继续进行。2、OSI网络七层模型在说RPC和HTTP的区别之前,我觉的有必要了解一下OSI的七层网络结构模型,它可以分为以下几层(自下而上):第一层:物理层。这一层主要就是传输这些二进制数据。第二层:链路层。将上面的网络层的数据包封装成数据帧,便于物理层传输;第三层:网络层。定义网络设备间如何传输数据;第四层:传输层。管理着网络中的端到端的数据传输;第五层:会话层。管理用户的会话,控制用户间逻辑连接的建立和中断;第六层:表示层。定义不同的系统中数据的传输格式,编码和解码规范等;第七层:应用层。定义了用于在网络中进行通信和传输数据的接口;3、RPC调用流程简单地说一下,一个完整的RPC架构里面包含了四个核心的组件,分别是Client ,Server,Client Stub以及Server Stub1、 客户端(RPC Client):服务调用方2、 客户端存根(Client Stub):存放服务端地址信息,将客户端的请求参数打包成网络消息,再通过网络发送给服务方3、 服务端存根(Server Stub):接受客户端发送过来的消息并解包,再调用本地服务4、 服务端(RPC Server):真正的服务提供者。RPC采用C/S模式,请求程序就是一个客户端应用,而服务提供者就是一个服务器。首先,服务消费者(RPC客户端应用)调用进程发送一个有进程参数的调用信息到服务进程,然后等待应答信息。在服务提供方(RPC服务器端),进程保持睡眠状态直到调用信息到达为止。当一个调用信息到达,服务器获得进程参数,调用服务端方法对调用请求进行计算而得到计算结果,并发送答复信息,然后等待下一个调用信息;最后,客户端调用进程接收答复信息,获得进程结果,然后调用执行继续进行。4、RPC架构的作用RPC 的主要目标是让构建分布式计算(应用)更容易、透明,在提供强大的远程调用能力时不损失本地调用的语义简洁性。为实现该目标,RPC 框架需提供一种透明调用机制让使用者不必显式的区分本地调用和远程调用。RPC框架负责屏蔽底层的传输方式(TCP或者UDP)、序列化方式(XML/JSON/二进制)和通信细节。开发人员在使用的时候只需要了解谁在什么位置提供了什么样的远程服务接口即可,并不需要关心底层通信细节和调用过程。5、常见RPC技术和框架(1)、应用级的服务框架:阿里的Dubbo/Dubbox、Google GRPC、Spring Boot/Spring Cloud。(2)、远程通信协议:RMI、Socket、SOAP(HTTP XML)、REST(HTTP JSON)。(3)、通信框架:MINA和Netty6、HTTP服务 VS RPC服务传输协议RPC,可以基于TCP协议,也可以基于HTTP协议HTTP,基于HTTP协议传输效率RPC,使用自定义的TCP协议,可以让请求报文体积更小,或者使用HTTP2协议,也可以很好的减少报文的体积,提高传输效率HTTP,如果是基于HTTP1.1的协议,请求中会包含很多无用的内容,如果是基于HTTP2.0,那么简单的封装以下是可以作为一个RPC来使用的,这时标准RPC框架更多的是服务治理性能消耗,主要在于序列化和反序列化的耗时RPC,可以基于thrift实现高效的二进制传输HTTP,大部分是通过json来实现的,字节大小和序列化耗时都比thrift要更消耗性能负载均衡RPC,基本都自带了负载均衡策略HTTP,需要配置Nginx,HAProxy来实现服务治理(下游服务新增,重启,下线时如何不影响上游调用者)RPC,能做到自动通知,不影响上游HTTP,需要事先通知,修改Nginx/HAProxy配置看完上述内容是否对您有帮助呢?如果还想对相关知识有进一步的了解或阅读更多相关文章,请关注辰讯云资讯频道,感谢您对辰讯云的支持。...
HashMap和Hashtable有什么不同,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。线程安全两者最主要的区别在于Hashtable是线程安全,而HashMap则非线程安全。Hashtable的实现方法里面都添加了synchronized关键字来确保线程同步,因此相对而言HashMap性能会高一些,我们平时使用时若无特殊需求建议使用HashMap,在多线程环境下若使用HashMap需要使用Collections.synchronizedMap()方法来获取一个线程安全的集合(Collections.synchronizedMap()实现原理是Collections定义了一个SynchronizedMap的内部类,这个类实现了Map接口,在调用方法时使用synchronized来保证线程同步,当然了实际上操作的还是我们传入的HashMap实例,简单的说就是Collections.synchronizedMap()方法帮我们在操作HashMap时自动添加了synchronized来实现线程同步,类似的其它Collections.synchronizedXX方法也是类似原理。NULL值HashMap可以使用null作为key,不过建议还是尽量避免这样使用。HashMap以null作为key时,总是存储在table数组的第一个节点上。当get()方法返回null 值时,既可以表示HashMap 中没有该键,也可以表示该键所对应的值为null。因此,在HashMap 中不能用get()方法来判断HashMap 中是否存在某个键,而应该用containsKey()方法来判断。而Hashtable则不允许null作为key。继承关系HashMap继承了AbstractMap,HashTable继承Dictionary抽象类,两者均实现Map接口。容量初始值HashMap的初始容量为16,Hashtable初始容量为11,两者的填充因子默认都是0.75。扩容方式HashMap扩容时是当前容量翻倍即:capacity*2,Hashtable扩容时是容量翻倍+1即:capacity*2+1。底层结构HashMap和Hashtable的底层实现都是数组+链表结构实现。哈希算法Hashtable计算hash是直接使用key的hashcode对table数组的长度直接进行取模: int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; HashMap计算hash对key的hashcode进行了二次hash,以获得更好的散列值,然后对table数组长度取摸: static int hash(int h) { h ^= (h >>> 20) ^ (h >>> 12); return h ^ (h >>> 7) ^ (h >>> 4); } static int indexFor(int h, int length) { return h & (length-1); }看完上述内容是否对您有帮助呢?如果还想对相关知识有进一步的了解或阅读更多相关文章,请关注辰讯云资讯频道,感谢您对辰讯云的支持。...
这期内容当中小编将会给大家带来有关mybatis中怎么利用注解对对象进行批量更改,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。mybatis注解对象批量更改一、介绍当有多个对象需要进行更改时,批量修改对象集合List二、代码@Update("<script>"+ "<foreach collection='listUserAnswerRecord' item='item' open='' close='' separator=';'> "+ " update t_qb_record_201910"+ " set answered = 0, progress = 1, answer_sheet = null, gmt_update = #{item.gmtUpdate}"+ " <where>"+ "<choose>"+ "<when test='item.unionid !=null'> unionid=#{item.unionid}</when>"+ "<otherwise> openid= #{item.openid} </otherwise>"+ "</choose>"+ " and goods_id = #{item.goodsId} and charpter_id = #{item.charpterId} and type = #{item.type}"+ "</where>"+ "</foreach>"+ "</script>") Integer deleteUserAnswerSheet(@Param("listUserAnswerRecord") List<UserAnswerRecordNew> listUserAnswerRecord);mybatis 注解批量更新、插入//批量插入 @Insert({ "<script>", "insert into table(column1, column2) values ", "<foreach collection='userLists' item='item' index='index' separator=','>", "(#{item.column1}, #{item.column2} )", "</foreach>", "</script>" }) public int insertUsers(@Param(value="userLists") List<User> userLists);//批量更新@Update({ "<script>", "<foreach collection='userLists' item='item' index='index' separator=';'>", "update table b", "set b.column1= #{item.column1},b.column2= #{item.column2} where b.column3= #{item.column3}", "</foreach>", "</script>" }) public int updateUser(@Param(value="userLists") List<User> userLists);collection:你传来的集合item:里面的类index:就是for循环的iseparator:间隔符上述就是小编为大家分享的mybatis中怎么利用注解对对象进行批量更改了,如果刚好有类似的疑惑,不妨参照上述分析进行理解。如果想知道更多相关知识,欢迎关注辰讯云资讯频道。...
这期内容当中小编将会给大家带来有关Java中怎么处理异常类型,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。一、异常的描述程序运行时,发生的不被期望的事件,它阻止了程序按照程序员的预期正常执行,这就是异常。异常发生时,是任程序自生自灭,立刻退出终止。在Java中即,Java在编译或运行或者运行过程中出现的错误。Java提供了更加优秀的解决办法:异常处理机制。异常处理机制能让程序在异常发生时,按照代码的预先设定的异常处理逻辑,针对性地处理异常,让程序尽最大可能恢复正常并继续执行,且保持代码的清晰。Java中的异常可以是函数中的语句执行时引发的,也可以是程序员通过throw 语句手动抛出的,只要在Java程序中产生了异常,就会用一个对应类型的异常对象来封装异常,JRE就会试图寻找异常处理程序来处理异常。异常指在运行时期发生的不正常情况。在java中用类的形式对不正常情况进行了描述和封装对象。描述不正常情况的类,就成为异常类。将正常代码和问题处理代码分离,提高阅读性。其实异常就是java通过面向对象的思想将问题封装成了对象,用异常类对其进行描述。二、异常的体系两大类:hrowable:可抛出的异常,无论是error还是exception,问题发生就应该可以抛出,让调用者知道并且处理。该体系的特点就是在于Throwable及其所有的子类都具有可抛性。可抛性到底指的是什么?怎么体现可抛性呢?通过两个关键字来体现的。throws throw 凡是可以被这两个关键字所操作的类和对象都具有可抛性。子类1 一般不可处理的。————Error特点:是由jvm抛出的严重性问题,这种问题发生一般不针对性处理,直接修改程序。子类2)可以处理的。————Exception,问题抛给调用者,谁用抛给谁。特点:子类后缀名都是用其父类名作为后缀名,阅读性很强!范例:比如自定义一个负数角标的异常,使用面向对象思想封装成对象。注意:如果让一个类称为异常类,必须要继承异常类。因为只有异常体系的子类才具有可抛性。class FuShuIndex extends Exception{ //构造函数 和类名一样 FuShuIndex(){ } //定义一个带参数的构造函数 FuShuIndex(String msg){ //调用Exception中的带参数异常函数 super(msg); } } 主函数 throws FuShuIndex:{ int[] arr = new int[3]; method(arr,-7); } public static int method(int[] arr,int index) throws arrIndexexception { if (index<0){ throw new arrIndexexception("数组的角标不能为负数"); } return arr[index]; }三、异常的分类:编译时被检测异常还要是Exception和其子类都是,除了特殊子类RuntimeException体系未处理即编译失败!这种问题一旦出现,希望在编译时就进行检测,让这种问题有相应的处理方式,这样的问题都可以针对性处理。编译时不被检测异常(运行时异常):RuntimeException和其子类可处理可不处理,编译都可以通过,运行时会检测!这种问题的发生,无法让功能继续,运算无法运行,更多因为调用的原因导致,或者引发了内部状态的改变导致的。这种问题一般不处理,直接编译通过,在运行时,让调用者时程序强制停止,让调用者对代码进行修正。throws和throw的区别:throws使用在函数上 ————申明throw使用在函数内,可以抛出多个,用逗号隔开。 ————抛出throws抛出的是异常类,可以抛出多个。throw抛出的是异常对象。四、异常处理的捕捉形式这是可以对异常进行针对性处理的方式。格式:try{ //需要被检测异常的代码 } catch(异常类 变量)//该变量用于接收发生的异常对象{ //处理异常代码 } finally{ //一定会被执行的代码 }范例class FuShuIndex extends Exception{ //构造函数 和类名一样 FuShuIndex(){ } //定义一个带参数的构造函数 FuShuIndex(String msg){ //调用Exception中的带参数异常函数 super(msg); } }主函数:无需throws抛出,下面我们自己捕获异常{ int[] arr = new int[3]; try{ method(arr,-7); }catch(arrIndexexception a){ a.printStackTrace();//jvm默认的异常处理机制就是调用异常对象的这个方法。 System.out.println("数组的角标异常!!!");//自定义捕获后打印的信息 System.out.println(a.toString());//打印该异常对象的信息 System.out.println(a.getMessage());//获取我们自定义抛出所定义的信息 } }public static int method(int[] arr,int index) throws arrIndexexception { if (index<0){ throw new arrIndexexception("数组的角标不能为负数"); } return arr[index]; }一个try对应多个catch:多catch情况下,父类的catch要放在最下面,否则编译为空。五、异常处理的原则函数内部如果抛出了需要检测的异常,那么函数上必须申明,或者必须在函数内用try catch捕捉,否则编译失败。如果调用到了申明异常的函数,要么try catch 或者 throws ,否则编译失败。什么时候catch?什么时候throws?功能内容可以解决,用catch。解决不了,用throws告诉调用者,由调用者解决。一个功能如果抛出了多个异常,那么调用时,必须有对应的多个catch来进行针对性处理。内部有几个需要检测的异常,就抛几个异常,抛出几个就catch几个异常。六、finally通常用于关闭(释放)资源。必须要执行。除非jvm虚拟机挂了。范例:出门玩,必须关门,所以将关门这个动作放在finally里面,必须执行。凡是涉及到关闭连接等操作,要用finally代码块来释放资源。try catch finally 代码块组合特点:try catch finally:当有资源需要释放时,可以定义finallytry catch(多个):当没有资源需要释放时,可以不定义finallytry finally:异常处理不处理我不管,但是我得关闭资源,因为资源是我开的,得在内部关掉资源。范例:try{ //连接数据库 } //没有catch意思不处理异常,只单纯的捕获异常 finally{ //关闭连接 }七、异常的应用老师用电脑讲课范例:电脑类:public class Computer { private int state = 2; public void run() throws lanpingExcption,maoyanExcption{ if (state == 1){ throw new lanpingExcption("电脑蓝屏啦~"); }else if (state == 2){ throw new maoyanExcption("电脑冒烟啦~"); } System.out.println("电脑启动"); } public void chongqi(){ state = 0; System.out.println("重启电脑!"); } }老师类:public class Teacher { private String name; private Computer computer; Teacher(String name){ this.name = name; computer = new Computer(); } void teach() throws maoyanExcption{ try { computer.run(); System.out.println(this.name + "开始用电脑讲课了"); } catch (lanpingExcption l) { l.printStackTrace(); computer.chongqi(); teach();//重启后再次讲课 } catch (maoyanExcption m) { m.printStackTrace(); test(); throw m; } } public void test(){ System.out.println("大家自己练习去~"); } }蓝屏异常类:public class lanpingExcption extends Exception{ lanpingExcption (String msg){ super(msg); } }冒烟异常类:public class maoyanExcption extends Exception { maoyanExcption (String msg){ super(msg); } }主函数:public class Testmain { public static void main (String[] args){ Teacher teacher = new Teacher("丁老师"); try { teacher.teach(); } catch (maoyanExcption m) { //m.printStackTrace(); System.out.println("。。。。。"); } } }八、异常的注意事项:子类在覆盖父类方法时,父类的方法如果抛出了异常,那么子类的方法只能抛出父类的异常或者该异常的子类。如果父类抛出多个异常,那么子类只能抛出父类异常的子集。子类覆盖父类,只能抛出父类的异常或者子类。如果父类的方法没有抛出异常,子类覆盖时绝对不能抛。上述就是小编为大家分享的Java中怎么处理异常类型了,如果刚好有类似的疑惑,不妨参照上述分析进行理解。如果想知道更多相关知识,欢迎关注辰讯云资讯频道。...
这篇文章主要介绍“怎么在 Linux 上创建一个加密文件保险库”,在日常操作中,相信很多人在怎么在 Linux 上创建一个加密文件保险库问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”怎么在 Linux 上创建一个加密文件保险库”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!1、建立一个空文件首先,你必须创建一个预定大小的空文件。就像是一种保险库或保险箱,你可以在其中存储其他文件。你使用的命令是 util-linux 软件包中的 fallocate:$ fallocate --length 512M vaultfile.img这个例子创建了一个 512MB 的文件,但你可以把你的文件做成任何你想要的大小。2、创建一个 LUKS 卷接下来,在空文件中创建一个 LUKS 卷:$ cryptsetup --verify-passphrase \ luksFormat vaultfile.img3、打开 LUKS 卷要想创建一个可以存储文件的文件系统,必须先打开 LUKS 卷,并将其挂载到电脑上:$ sudo cryptsetup open \ --type luks vaultfile.img myvault$ ls /dev/mappermyvault4、建立一个文件系统在你打开的保险库中建立一个文件系统:$ sudo mkfs.ext4 -L myvault /dev/mapper/myvault如果你现在不需要它做什么,你可以关闭它:$ sudo cryptsetup close myvault5、开始使用你的加密保险库现在一切都设置好了,你可以在任何需要存储或访问私人数据的时候使用你的加密文件库。要访问你的保险库,必须将其挂载为一个可用的文件系统:$ sudo cryptsetup open \ --type luks vaultfile.img myvault$ ls /dev/mappermyvault$ sudo mkdir /myvault$ sudo mount /dev/mapper/myvault /myvault这个例子用 cryptsetup 打开保险库,然后把保险库从 /dev/mapper 下挂载到一个叫 /myvault 的新目录。和 Linux 上的任何卷一样,你可以把 LUKS 卷挂载到任何你想挂载的地方,所以除了 /myvault,你可以用 /mnt 或 ~/myvault 或任何你喜欢的位置。当它被挂载后,你的 LUKS 卷就会被解密。你可以像读取和写入文件一样读取和写入它,就像它是一个物理驱动器一样。当使用完你的加密保险库时,请卸载并关闭它:$ sudo umount /myvault$ sudo cryptsetup close myvault加密的文件保险库你用 LUKS 加密的镜像文件和其他文件一样,都是可移动的,因此你可以将你的保险库存储在硬盘、外置硬盘,甚至是互联网上。只要你可以使用 LUKS,就可以解密、挂载和使用它来保证你的数据安全。轻松加密,提高数据安全性,不妨一试。到此,关于“怎么在 Linux 上创建一个加密文件保险库”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注辰讯云网站,小编会继续努力为大家带来更多实用的文章!...
小编给大家分享一下IOS如何实现手机震动的提示功能,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!IOS开发实现手机震动的提示实例代码我们都知道手机有震动功能,其实呢,这个功能实现起来特别的简单,我们只需要用到几个函数就可以了: - (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event- (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event还有就是通过canBecomeFirstResponder:设置一个第一响应者为label,然后摇动手机两下,看看效果如下:代码如下:HHLAppDelegate.h#import <UIKit/UIKit.h> @class HHLViewController; @interface HHLAppDelegate : UIResponder <UIApplicationDelegate> @property (strong, nonatomic) UIWindow *window; @property (strong, nonatomic) HHLViewController *viewController; @endHHLAppDelegate.m#import "HHLAppDelegate.h" #import "HHLViewController.h" @implementation HHLAppDelegate - (void)dealloc { [_window release]; [_viewController release]; [super dealloc]; } - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease]; // Override point for customization after application launch. self.viewController = [[[HHLViewController alloc] initWithNibName:@"HHLViewController" bundle:nil] autorelease]; self.window.rootViewController = self.viewController; [self.window makeKeyAndVisible]; return YES; } - (void)applicationWillResignActive:(UIApplication *)application { // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. } - (void)applicationDidEnterBackground:(UIApplication *)application { // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. } - (void)applicationWillEnterForeground:(UIApplication *)application { // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. } - (void)applicationDidBecomeActive:(UIApplication *)application { // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. } - (void)applicationWillTerminate:(UIApplication *)application { // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. } @endHHLViewController.h#import <UIKit/UIKit.h> @interface HHLViewController : UIViewController @end @interface LabelForMotion : UILabel @endHHLViewController.m#import "HHLViewController.h" @interface HHLViewController () @end @implementation LabelForMotion - (BOOL)canBecomeFirstResponder { return YES; } @end @implementation HHLViewController - (void)viewDidLoad { [super viewDidLoad]; LabelForMotion *label = [[[LabelForMotion alloc]init]autorelease]; label.frame = self.view.bounds; label.autoresizingMask =UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight; label.textAlignment = NSTextAlignmentCenter; label.text = @"Shake me"; [self.view addSubview:label]; //将标签设置为第一响应者 [label becomeFirstResponder]; [label release]; } - (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event { NSLog(@"motionBegan"); } //震动结束时调用的方法 - (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event { NSLog(@"motionEnded"); UIAlertView *alert = [[UIAlertView alloc]initWithTitle:nil message:@"地震了" delegate:nil cancelButtonTitle:nil otherButtonTitles:@"OK", nil nil]; [alert show]; [alert release]; } - (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event { NSLog(@"motionCancelled"); } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } @end其实更简单的没有必要搞一个类继承自UIlabel,可以直接定义一个UIlabel的对象就行了。以上是“IOS如何实现手机震动的提示功能”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注辰讯云资讯频道!...
这篇文章给大家分享的是有关iOS中如何仿QQ实现侧滑菜单功能的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。UITabBarController做QQ侧滑菜单效果:首先要了解UITabBarController的层级结构:UITabBarController加载的其它UIViewController的View都是被添加在UITransitionView上(这是一个私有API),UITransitionView在self.view的0层,UITabBar在的第一层。所以我的思路是这样的:UITransitionView与UITabBar转移到一个新的View1上去,作为滑动的部分;在View1与self.view之间再添加一个View2,作为菜单的容器;给View1添加相应的手势响应;代码:#import <UIKit/UIKit.h>@protocol SlideTab_VC_TCVDelegate <NSObject>@optional-(void)didOpenMenu:(UIView*)menu; -(void)didCloseMenu:(UIView*)menu;@end@interface SlideTab_VC : UITabBarController@property(strong, nonatomic)UIView *mMenuV;@property(weak, nonatomic)id <SlideTab_VC_TCVDelegate> mDelegate; -(void)openMenu; -(void)closeMenu;@end#import "SlideTab_VC.h"#define DEVICE_W [UIScreen mainScreen].bounds.size.width@interface SlideTab_VC ()<UITabBarDelegate>{ CGFloat _centerMaxX; }@property(strong, nonatomic)UIView *mTransitionView;@property(strong, nonatomic)UITapGestureRecognizer *mTapGester;@property(assign, nonatomic)BOOL mMenuIsOpen;@property(strong, nonatomic)UITabBar *mTabBar;@end@implementation SlideTab_VC- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. self.view.backgroundColor = [UIColor purpleColor]; _mMenuIsOpen = NO; _centerMaxX = DEVICE_W*3/2-80.0f; [self initMTransitionView]; [self addGestureForMTransitionView]; }#pragma mark 菜单懒加载-(void)setMMenuV:(UIView *)mMenuV{ if (mMenuV!=nil) { _mMenuV = mMenuV; [self.view insertSubview:_mMenuV atIndex:0]; } }#pragma mark 打开菜单-(void)openMenu{ CGPoint center = self.mTransitionView.center; center.x = _centerMaxX; [UIView animateWithDuration:0.15f animations:^{ self.mTransitionView.center = center; if (_mDelegate != nil&& [_mDelegate respondsToSelector:@selector(didOpenMenu:)]) { [_mDelegate didOpenMenu:_mMenuV]; } }]; [self mTransitionSubViewsEnable:NO]; }#pragma mark 关闭菜单-(void)closeMenu{ CGPoint center = self.mTransitionView.center; center.x = DEVICE_W/2; [UIView animateWithDuration:0.15f animations:^{ self.mTransitionView.center = center; } completion:^(BOOL finished) { [self mTransitionSubViewsEnable:YES]; if (_mDelegate != nil&& [_mDelegate respondsToSelector:@selector(didCloseMenu:)]) { [_mDelegate didCloseMenu:_mMenuV]; } }]; }#pragma mark Transition用户交互使能-(void)mTransitionSubViewsEnable:(BOOL)enable{ for (UIView *tmp in self.mTransitionView.subviews) { tmp.userInteractionEnabled = enable; } if (enable) { [self.mTransitionView removeGestureRecognizer:_mTapGester]; }else{ [self.mTransitionView addGestureRecognizer:_mTapGester]; } }#pragma mark 配置mTransitionView-(void)initMTransitionView{ for (UIView *tmp in self.view.subviews) { [tmp removeFromSuperview]; [self.mTransitionView addSubview:tmp]; } [self.view addSubview:self.mTransitionView]; }#pragma mark 拖动手势动作-(void)panAction:(UIPanGestureRecognizer*)pan{ CGPoint location = [pan translationInView:pan.view.superview]; CGPoint center = self.mTransitionView.center; if (pan.state==UIGestureRecognizerStateEnded) { if (center.x<_centerMaxX*0.5+DEVICE_W*0.25){ [self closeMenu]; }else{ [self openMenu]; } }else if(pan.state==UIGestureRecognizerStateChanged){ if (location.x<0) {//向左滑 center.x = center.x+location.x<=DEVICE_W/2? DEVICE_W/2 : center.x+location.x; }else{ center.x = center.x+location.x>=_centerMaxX? _centerMaxX : center.x+location.x; } self.mTransitionView.center = center; [pan setTranslation:CGPointMake(0, 0) inView:pan.view.superview]; } }#pragma mark 添加手势-(void)addGestureForMTransitionView{ UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(panAction:)]; [_mTransitionView addGestureRecognizer:pan]; _mTapGester = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tapAction)]; }#pragma mark--懒加载-(UIView *)mTransitionView{ if (_mTransitionView==nil) { _mTransitionView = [[UIView alloc]initWithFrame:self.view.bounds]; } return _mTransitionView; } -(void)tapAction{ CGFloat x = _mTransitionView.center.x; if (x>=_centerMaxX) { [self closeMenu]; } }@end感谢各位的阅读!关于“iOS中如何仿QQ实现侧滑菜单功能”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!...
这篇文章主要介绍了iOS中标签Tag列表怎么用,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。前言1、之前项目中会有一些标签列表来显示某些特性或要求,如下图(代码实现后的效果):2、期间也是浏览了好多其他的第三方,但是可能是没找到好的方法去寻找吧,没有找到一个合适的,况且又不是特别复杂的东西,所以就自己写了一套,但是注意因为我们项目中使用的是RAC+Mansory,所以想要使用的话需要引入这两个库=_=。3、自己写的时候考虑的不是太多,中心思想是ViewModel做定制需求,View通过ViewModel来实现定制化UI,其他更多的是逻辑上的排版,所以不做更多赘述,自己体会Y^o^Y 。View布局LSLabelTextView.h的实现//// LSLabelTextView.h// RenCheRen//// Created by 王隆帅 on 15/12/30.// Copyright © 2015年 王隆帅. All rights reserved.//#import "YCView.h"@interface LSLabelTextView : YCView@endLSLabelTextView.m的实现//// LSLabelTextView.m// RenCheRen//// Created by 王隆帅 on 15/12/30.// Copyright © 2015年 王隆帅. All rights reserved.//#import "LSLabelTextView.h"#import "LSLabelTextViewModel.h"@interface LSLabelTextView ()@property (nonatomic, strong) LSLabelTextViewModel *viewModel;@end@implementation LSLabelTextView { MASConstraint *_toLeftBtnMasConstraint; MASConstraint *_toTopBtnMasonstraint; MASConstraint *_toLeftSelfMasConstraint; MASConstraint *_toTopSelfMasonstraint; } - (instancetype)initWithViewModel:(id<YCViewModelProtocol>)viewModel { self.viewModel = (LSLabelTextViewModel *)viewModel; return [super initWithViewModel:viewModel]; } - (void)yc_bindViewModel { @weakify(self); [[RACObserve(self, viewModel.dataArray) distinctUntilChanged] subscribeNext:^(id x) { @strongify(self); [self.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)]; if (self.viewModel.dataArray.count <= 0) { __weak UIView *weakNullView; UIView *nullView = [[UIView alloc] init]; weakNullView = nullView; [self addSubview:weakNullView]; WS(weakSelf) [weakNullView mas_makeConstraints:^(MASConstraintMaker *make) { make.top.right.left.bottom.equalTo(weakSelf); make.height.equalTo(weakSelf.viewModel.nullHeight); }]; return; } NSInteger lineNum = 1; CGFloat allWidth = 0; __weak UIButton *lastBtn; for (int i = 0; i < self.viewModel.dataArray.count; i++) { NSString *string = [self.viewModel.dataArray stringWithIndex:i]; __weak UIButton *weakBtn = [self ls_getBtnWithString:string]; [self addSubview:weakBtn]; CGSize size = [string widthWithHeight:20 andFont:self.viewModel.textFontNum]; CGFloat needFloat = size.width < self.viewModel.miniWidth ? self.viewModel.miniWidth : size.width; if (lastBtn) { WS(weakSelf) [weakBtn mas_makeConstraints:^(MASConstraintMaker *make) { _toLeftBtnMasConstraint = make.left.equalTo(lastBtn.mas_right).offset(weakSelf.viewModel.labelHorizontalSpace); [_toLeftBtnMasConstraint activate]; _toTopBtnMasonstraint = make.top.equalTo(lastBtn.mas_bottom).offset(weakSelf.viewModel.labelVerticalSpace); [_toTopBtnMasonstraint deactivate]; _toLeftSelfMasConstraint = make.left.equalTo(weakSelf.viewModel.leftToViewEdge); _toTopSelfMasonstraint = make.top.equalTo(lastBtn); make.size.equalTo(CGSizeMake(needFloat + 20, weakSelf.viewModel.labelHeight)); }]; if (allWidth + self.viewModel.labelHorizontalSpace + needFloat + 20 + self.viewModel.rightToViewEdge > self.viewModel.allWidth) { [_toLeftSelfMasConstraint activate]; [_toLeftBtnMasConstraint deactivate]; [_toTopBtnMasonstraint activate]; [_toTopSelfMasonstraint deactivate]; lineNum ++; allWidth = self.viewModel.leftToViewEdge + needFloat + 20; } else { [_toLeftSelfMasConstraint deactivate]; [_toLeftBtnMasConstraint activate]; [_toTopBtnMasonstraint deactivate]; [_toTopSelfMasonstraint activate]; allWidth = allWidth + self.viewModel.labelHorizontalSpace + needFloat + 20; } } else { WS(weakSelf) [weakBtn mas_makeConstraints:^(MASConstraintMaker *make) { make.left.equalTo(weakSelf.viewModel.leftToViewEdge); make.size.equalTo(CGSizeMake(needFloat + 20, weakSelf.viewModel.labelHeight)); make.top.equalTo(weakSelf.viewModel.topToViewEdge); }]; allWidth = allWidth + self.viewModel.leftToViewEdge + needFloat + 20; } lastBtn = weakBtn; } WS(weakSlef) [lastBtn mas_updateConstraints:^(MASConstraintMaker *make) { make.bottom.equalTo(weakSlef.viewModel.bottomToViewEdge); }]; }]; } - (UIButton *)ls_getBtnWithString:(NSString *)string { UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom]; btn.layer.borderWidth = 0.5; btn.layer.borderColor = self.viewModel.borderColor.CGColor; [btn setTitleColor:self.viewModel.titleColor forState:UIControlStateNormal]; btn.backgroundColor = self.viewModel.backgroundColor; btn.layer.masksToBounds = YES; btn.layer.cornerRadius = self.viewModel.cornerRadius; btn.titleLabel.font = YC_YAHEI_FONT(self.viewModel.textFontNum); [btn setTitle:string forState:UIControlStateNormal]; btn.ls_typeString = string; return btn; }@endViewModel适配LSLabelTextViewModel.h的实现//// LSLabelTextViewModel.h// RenCheRen//// Created by 王隆帅 on 15/12/30.// Copyright © 2015年 王隆帅. All rights reserved.//#import "YCViewModel.h"@interface LSLabelTextViewModel : YCViewModel/** * 标签数组 */@property (nonatomic, strong) NSMutableArray *dataArray;/** * 总的宽度 */@property (nonatomic, assign) CGFloat allWidth;/** * 没有标签时的高度 */@property (nonatomic, assign) CGFloat nullHeight;/** * 文字字体大小 */@property (nonatomic, assign) CGFloat textFontNum;/** * 取得标签为空的时候,标签最小长度 */@property (nonatomic, assign) CGFloat miniWidth;/** * 标签高度 */@property (nonatomic, assign) CGFloat labelHeight;/** * 最左侧标签距离View的边缘的宽度 */@property (nonatomic, assign) CGFloat leftToViewEdge;/** * 最右侧标签距离View的边缘的宽度 */@property (nonatomic, assign) CGFloat rightToViewEdge;/** * 最上侧标签距离View的边缘的宽度 */@property (nonatomic, assign) CGFloat topToViewEdge;/** * 最下侧标签距离View的边缘的宽度 */@property (nonatomic, assign) CGFloat bottomToViewEdge;/** * 横向标签之间的宽度 */@property (nonatomic, assign) CGFloat labelHorizontalSpace;/** * 纵向标签之间的宽度 */@property (nonatomic, assign) CGFloat labelVerticalSpace;/** * label(btn) 的相关属性 */@property (nonatomic, assign) CGFloat borderWidth;@property (nonatomic, strong) UIColor *borderColor;@property (nonatomic, strong) UIColor *titleColor;@property (nonatomic, strong) UIColor *backgroundColor;@property (nonatomic, assign) CGFloat cornerRadius;@endLSLabelTextViewModel.m的实现//// LSLabelTextViewModel.m// RenCheRen//// Created by 王隆帅 on 15/12/30.// Copyright © 2015年 王隆帅. All rights reserved.//#import "LSLabelTextViewModel.h"@implementation LSLabelTextViewModel- (NSMutableArray *)dataArray { if (!_dataArray) { _dataArray = [[NSMutableArray alloc] init]; } return _dataArray; }@end感谢你能够认真阅读完这篇文章,希望小编分享的“iOS中标签Tag列表怎么用”这篇文章对大家有帮助,同时也希望大家多多支持辰讯云,关注辰讯云资讯频道,更多相关知识等着你来学习!...