当前位置: 首页 > news >正文

网站开发维护印花税移动互联网软件开发

网站开发维护印花税,移动互联网软件开发,北京移动端网站设计,网站建设用户画像例子zookeeper作为一个分布式协调框架#xff0c;它的创建就是为了方便或者简化分布式应用的开发。除了服务注册与发现之外#xff0c;它还能够提供更多的功能#xff0c;但是对于入门来说#xff0c;看这一篇就够了。后续会讲zookeeper的架构设计与原理#xff0c;比如zookee… zookeeper作为一个分布式协调框架它的创建就是为了方便或者简化分布式应用的开发。除了服务注册与发现之外它还能够提供更多的功能但是对于入门来说看这一篇就够了。后续会讲zookeeper的架构设计与原理比如zookeeper的原子协议leader选举算法等。欢迎关注 目录 zookeeper安装与启动 一、zookeeper下载 二、安装zookeeper 三、linux下启动zookeeper 四、windows下启动zookeeper zookeeper基本概念 一、zookeeper的存储结构 二、什么是znode 三、znode节点的四种类型 四、权限控制ACLAccess Control List 五、事件监听watcher zookeeper的基本操作 一、节点的增删改查 二、zookeeper的其他命令 2.1   ls path列出path下的文件 2.2  stat path查看节点状态 2.3  ls2 path列出path节点的子节点及状态 三、其他 在java客户端中操作zookeeper 用zookeeper实现服务注册与发现中心  zookeeper安装与启动 一、zookeeper下载 镜像站下载http://mirrors.hust.edu.cn/apache/zookeeper/ 记住选择带bin的。从版本3.5.5开始带有bin名称的包才是我们想要的下载可以直接使用的里面有编译后的二进制的包而之前的普通的tar.gz的包里面是只是源码的包无法直接使用。不然会爆 错误: 找不到或无法加载主类 org.apache.zookeeper.server.quorum.QuorumPeerMain 下载后解压到自己的电脑位置比如D:\apache-zookeeper-3.5.8-bin 若用wsl请将apache-zookeeper-3.5.8-bin.tar.gz拷贝到wsl下面后再解压可以参考WSL访问windows下的文件 解压后目录结构 bin目录 zk的可执行脚本目录包括zk服务进程zk客户端等脚本。其中.sh是Linux环境下的脚本.cmd是Windows环境下的脚本。conf目录 配置文件目录。zoo_sample.cfg为样例配置文件需要修改为自己的名称一般为zoo.cfg。log4j.properties为日志配置文件。lib zk依赖的包。contrib目录 一些用于操作zk的工具包。recipes目录 zk某些用法的代码示例 二、安装zookeeper ZooKeeper的安装包括单机模式安装以及集群模式安装。 开发情况下由于资源有限一般用单机模式我们先讲单机模式让zookeeper跑起来。后面实践案例再讲集群模式。 在启动zookeeper之前我们需要先修改zookeeper的配置信息我们先进入zookeeper-3.5.8-bin/conf目录修改zoo_sample.cfg文件为 # The number of milliseconds of each tick tickTime2000 # The number of ticks that the initial # synchronization phase can take initLimit10 # The number of ticks that can pass between # sending a request and getting an acknowledgement syncLimit5 # the directory where the snapshot is stored. # do not use /tmp for storage, /tmp here is just # example sakes.dataDir/tmp/zookeeper修改为自己的目录 dataLogDir/tmp/zookeeper修改为自己的目录 # the port at which the clients will connect clientPort2181 # the maximum number of client connections. # increase this if you need to handle more clients #maxClientCnxns60 # # Be sure to read the maintenance section of the # administrator guide before turning on autopurge. # # http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance # # The number of snapshots to retain in dataDir #autopurge.snapRetainCount3 # Purge task interval in hours # Set to 0 to disable auto purge feature #autopurge.purgeInterval1 主要修改项为dataDir和dataLogDirdataDir是zookeeper存放数据的地方dataLogDir是存放zookeeper日志的地方。 如果只配置dataDir则数据和日志都会创建在dataDir目录下。默认情况下zookeeper会占有8080端口如果你不想8080端口被占用增加一行admin.serverPort8082指定你自己的端口。 其他配置项的意思我们留到后面再说。   注意如果你是在windows下使用zookeeper需要将zoo_sample.cfg改名为zoo.cfg 三、linux下启动zookeeper 我们需要先启动zookeeper服务端再启动客户端。 首先进入 zookeeper-3.5.8-bin/bin目录 输入命令 ./zkServer.sh start  我之前安装的是zookeeper-3.4.13版本所以图里的版本和文章的版本不一致不影响 可以看到STARTEDzookeeper服务端启动成功了。 接下来启动客户端。输入命令 ./zkCli.sh -server 127.0.0.1:2181 -server参数就代表我们要连接哪个zookeeper服务端 连接成功出现 这样就算启动成功了。如果不放心可以输入下面两条命令创建节点和获取节点测试一下。 四、windows下启动zookeeper windows和linux大同小异。只不过执行文件从zkServer.sh替换成zkServer.cmdzkCli.sh替换成zkCli.cmd。 如果你前面没有改名的话需要将conf目录下的zoo_sample.cfg改名为zoo.cfg 用cmd进入我们zookeeper的bin目录。 输入zkServer.cmd 双击zkCli.cmd 出现 同样输入create /zk test 和get /zk测试一下 至此zookeeper安装与启动完成。 zookeeper基本概念 一、zookeeper的存储结构 zookeeper的存储结构极其类似于文件系统都是树形结构如下图所示。 与文件系统不同的是文件系统分为目录和文件目录是没有数据的。而zookeeper则全部称为节点znode每个节点既能保存数据又有孩子节点。 zookeeper的根节点都是“/。 每一个节点znode)的命名空间类似于java中的包名都由其路径组成。zookeeper称上面这种结构为分层命名空间Hierarchical Namespace。 例如根节点的命名空间为“/第二层左节点的命名空间为”/app1右节点的命名空间为“/app2”。 节点的命名空间我们又可以理解为是每个节点的标识符程序能够根据名称定位到具体是哪个节点。 二、什么是znode 上图中的每个节点在zookeeper中称为znode。在zookeeper推荐在znode中存储的数据不超过1M这是从性能和效率的角度出发。zookeeper作为协调分布式应用的服务中心一般是存储状态信息、配置信息和本地数据等等。从设计的初衷上看也不是为了存储大量数据准备的。如果真的要存储大数据应该把数据存储在别的地方比如数据库上然后在znode上存储他们的引用。 znode在每次更新数据时都是全量更新直接覆盖以前的值不存在追加或者修改其中某个地方的操作。读取数据也是全部读取。同时znode的读取和写入都是原子操作。 znode还存储了znode版本信息有三个版本号dataversion数据版本号、cversion子节点版本号、aclversion节点所拥有的ACL版本号。每个版本号其实是一个数字每次修改对应的版本号就会增加。 比如我们创建一个节点create /zk test后在linux下用get /zk后返回的信息如下 test  #znode的数据 cZxid 0x1e   #znode的创建事务id ctime Tue Sep 29 06:45:54 CST 2020 #znode的创建时间 mZxid 0x1e  #znode的修改事务id mtime Tue Sep 29 06:45:54 CST 2020  #修改时间 pZxid 0x1e  #该节点的子节点列表最后一次修改的版本号添加子节点或删除子节点就会影响子节点列表但是修改子节点的数据内容则不影响该值孙子节点的操作也不影响 cversion 0  #children节点的版本号每次子节点修改加1下同 dataVersion 0 #数据版本号 aclVersion 0  #ACL(权限控制列表版本号 ephemeralOwner 0x0  #如果节点为临时节点那么它的值为这个节点拥有者的session ID如果该节点不是ephemeral节点, ephemeralOwner值为0. dataLength 4 #数据长度 numChildren 0 #孩子节点的数量 版本号的作用 Zookeeper里面的版本号和我们理解的版本号不同它表示的是对数据节点的内容、子节点列表或者ACL信息的修改次数。节点创建时dataversion、aclversioncversion都为0每次修改响应内容其对应的版本号加1。 这个版本号的用途就和分布式场景的一个锁概念有关。比如演出售票中的一个座位显然每个场次中的每个座位都只有一个不可能卖出2次。如果A下单的时候显示可售他想买那么为了保证他可以下单成功此时别人就不能买。这时候就需要有一种机制来保证同一时刻只能有一个人去修改该座位的库存。这就用到了锁。锁有悲观锁和乐观锁。 悲观锁它会假定所有不同事务的处理一定会出现干扰数据库中最严格的并发控制策略如果一个事务A正在对数据处理那么在整个事务过程中其他事务都无法对这个数据进行更新操作直到A事务释放了这个锁。 乐观锁它假定所有不同事务的处理不一定会出现干扰所以在大部分操作里不许加锁但是既然是并发就有出现干扰的可能如何解决冲突就是一个问题。在乐观锁中当你在提交更新请求之前你要先去检查你读取这个数据之后该数据是否发生了变化如果有那么你此次的提交就要放弃如果没有就可以提交。 Zookeeper中的版本号就是乐观锁你修改节点数据之前会读取这个数据并记录该数据版本号当你需要更新时会携带这个版本号去提交如果你此时携带的版本号就是你上次读取出来的和当前节点的版本号相同则说明该数据没有被修改过那么你的提交就会成功如果提交失败说明该数据在你读取之后和提交之前这段时间内被修改了。 三、znode节点的四种类型 zookeeper有四种节点临时节点临时顺序节点持久节点和持久顺序节点。 3.1  临时节点 当zookeeper的客户端申请zookeeper服务端创建临时节点时节点的ephemeralOwner为此客户端与服务端的sessionId。当客户端与服务端断开连接时临时节点也会被删除。 3.2  临时顺序节点 当创建的是临时顺序节点时会在节点名称后面增加序号不断递增。 举个例子。比如申请创建的是/zk临时顺序节点如果此时服务端没有/zk的节点那么就会创建/zk-1节点。这时第二个请求过来了也是创建临时顺序节点/zk那么服务端就会创建/zk-2依次是/zk-3,/zk-4......不断递增下去一直到2^32。与临时节点一样的是当客户端断开链接时临时顺序节点也会被删除。 3.3 持久节点 顾名思义就是创建后除非主动删除否则会一直存在的节点。 3.4 持久顺序节点 当创建的是持久顺序节点时举个例子。比如申请创建的是/zk临时顺序节点如果此时服务端没有/zk的节点那么就会创建/zk-1节点。这是有第二个请求过来了也是创建临时顺序节点/zk那么服务端就会创建/zk-2不断递增下去一直到2^32。与持久节点一样的是创建后除非主动删除否则会一直存在。 四、权限控制ACLAccess Control List ZooKeeper的权限控制是基于每个znode节点的需要对每个节点设置权限。 zookeeper每个节点的权限类型有五种create、read、delete、write、admin CREATE创建子节点的权限 READ读节点数据的权限包括获取它的子节点列表的权限 DELETE有删除子节点的权限 WRITE写节点数据的权限 ADMIN可以设置节点访问控制列表权限 zookeeper的授权策略Scheme有5种world、auth、digest、ip、x509有一些博客写了Super即超级管理员模式这个类型可能是老版本从3.4开始官方文档介绍ACL的时候就没看到super了 world默认方式全部都能访问 auth认证用户可以使用(cli中可以通过addauth digest user:pwd 来添加当前上下文中的授权用户) digest即用户名:密码这种方式认证这也是业务系统中最常用的。用 username:password 字符串来产生一个MD5串然后该串被用来作为ACL ID。认证是通过明文发送username:password 来进行的当用在ACL时表达式为username:base64 base64是password的SHA1摘要的编码。 ip使用客户端的主机IP作为ACL ID 。这个ACL表达式的格式为addr/bits 此时addr中的有效位与客户端addr中的有效位进行比对。 x509 uses the client X500 Principal as an ACL ID identity. The ACL expression is the exact X500 Principal name of a client. When using the secure port, clients are automatically authenticated and their auth info for the x509 scheme is set. ACL 权限控制使用scheme:id:perm 来标识主要涵盖 3 个方面权限模式Scheme授权的策略   授权对象ID:授权的对象    权限类型Permission:授予的权限。权限模式和权限类型就是上文所讲授权对象ID很好理解就是权限赋予的用户或者一个实体例如IP 地址或者机器。 五、事件监听watcher zookeeper可以向节点注册一个watcher用来监听节点的变化。当节点状态发生变化时比如说被删除或者修改那么它就会发送通知到监听这个节点的客户端客户端因此而做出自己的操作。 每个注册仅使用一次也就是当发生一次节点改变通知完客户端之后如果你需要这个节点下次发生改变时也发送通知到这个客户端那么就需要再注册一次监听。 zookeeper的基本操作 在zookeeper的bin目录下输入./zkServer.sh start和./zkCli.sh启动服务端和客户端然后我们就可以进行zookeeper的基本操作了 一、节点的增删改查 zookeeper节点的增删改查命令很简单唯一需要注意的是create命令有两个参数-s代表顺序节点-e代表临时节点。 我们先用create /temp 123命令创建一个名为temp的znode节点123是这个节点保存的data值。 用get /temp命令查看 如果你输入的是get temp那么会出现Command failed: java.lang.IllegalArgumentException: Path must start with /character错误这是因为在zookeeper中没有相对路径的概念所有的节点都需要用绝对路径表示也即所有节点名称都会以“/”开头。 如果我们要创建临时节点则给create命令增加一个-e的参数。 修改temp节点的数据set /temp  456 再用get /temp查看 可以看到/temp节点的数据已经从123变成了456。在zookeeper中对于数据的修改都是全量修改没有只修改某一部分这种说法。这也是为什么zookeeper的修改命令是set而不是update的原因。 需要注意的是但我们修改了数据之后可以看到mZxid修改事务id已经从原来的0X26变成了0x27。 如果要删除某个节点则用delete path即可。 需要注意的是 set path data [version]命令如果我们多次修改会发现  dataVersion 也就是数据版本在不停得发生变化自增如果我们在set的时候手动去指定了版本号就必须和上一次查询出来的结果一致否则 就会报错。 这个可以用于我们在修改节点数据的时候保证我们修改前数据没被别人修改过。因为如果别人修改过了我们这次修改是不会成功的 delete path [version] 删除指定节点数据其version参数的作用于set指定一致 二、zookeeper的其他命令 2.1   ls path列出path下的文件 与linux命令类似ls命令用于列出给定路径下的zookeeper节点 2.2  stat path查看节点状态 我们查看持久节点temp和临时节点short的状态主要不同是画红线部分从ephemeralOwner的值可以判断这个节点是持久节点还是临时节点。0X0代表的是持久节点。如果节点为临时节点那么它的值为这个节点拥有者的session ID。 2.3  ls2 path列出path节点的子节点及状态 我们先给temp节点创建一个child1的子节点接着用ls2 /temp查看它的子节点和状态。 三、其他 我们可以输入-h获取zookeeper的所有命令 在java客户端中操作zookeeper 先启动zookeeper服务端。 在maven引入zookeeper依赖。 dependencygroupIdorg.apache.hadoop/groupIdartifactIdzookeeper/artifactIdversion3.3.1/version /dependency org.apache.zookeeper.Zookeeper是客户端入口主类负责建立与server的会话。它提供了以下 所示几类主要方法。  在java中启动客户端注册一个watcher监听链接的建立。 import org.apache.zookeeper.WatchedEvent; import org.apache.zookeeper.Watcher; import org.apache.zookeeper.ZooKeeper;public class ZookeeperClient {private static final String connectString 127.0.0.1:2181;private static final int sessionTimeout 2000;private static ZooKeeper zkClient null;public void init() throws Exception {zkClient new ZooKeeper(connectString, sessionTimeout, new Watcher() {Overridepublic void process(WatchedEvent event) {// 收到事件通知后的回调函数应该是我们自己的事件处理逻辑System.out.println(zookeeper链接建立);}});} }在main方法里测试我们的init方法用Thread.sleep方法等待zookeeper连接创建不然在zookeeper客户端建立连接之前主线程就已经退出。 public static void main(String[] args)throws Exception{new ZookeeperClient().init();Thread.sleep(5000);} 控制台输出 接下来我们创建一个名为“/java”的节点节点数据为“data”ZooDefs.Ids.OPEN_ACL_UNSAFE的意思是不节点能被所有人访问CreateMode.PERSISTENT节点的类型为持久节点。 public void createZnode()throws Exception{zkClient.create(/java, data.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);} 判断节点是否存在false代表不注册监听事件如果是true则注册我们在new zookeeper方法里面传递的watcher。 public void testExist() throws Exception{Stat stat zkClient.exists(/java, false);System.out.println(statnull?节点不存在:节点存在);} 测试一下我们的方法。 public static void main(String[] args)throws Exception{new ZookeeperClient().init();Thread.sleep(5000);new ZookeeperClient().createZnode();new ZookeeperClient().testExist();} 获取节点的数据。false和上面exists方法参数含义一样表示不注册连接建立时的watcher第三个stat对象则存储了除了节点数据之外的其他信息如czxid、mzxid等。如果为null则表示不保存节点的这些信息。 public void getNodeData()throws Exception{byte[] res zkClient.getData(/java,false,new Stat());System.out.println(new String(res));} 同样测试我们的方法。 public static void main(String[] args)throws Exception{new ZookeeperClient().init();Thread.sleep(3000);new ZookeeperClient().getNodeData();} 获取ACL控制列表 public void getACl()throws Exception{ListACL res zkClient.getACL(/java,new Stat());for(ACL acl : res){System.out.println(acl.getId().toString()acl.getPerms());}} 测试 public static void main(String[] args)throws Exception{new ZookeeperClient().init();Thread.sleep(3000);new ZookeeperClient().getACl();} 在/java下创建子节点获取子节点列表。 public void createChildZnode()throws Exception{zkClient.create(/java/child, child data.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);zkClient.create(/java/child2, child2 data.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);}public void getChildNode()throws Exception{ListString res zkClient.getChildren(/java,false);for(String s : res){System.out.println(s);}} 测试 public static void main(String[] args)throws Exception{new ZookeeperClient().init();Thread.sleep(3000);new ZookeeperClient().createChildZnode();new ZookeeperClient().getChildNode();} 全部代码如下 import org.apache.zookeeper.*; import org.apache.zookeeper.data.ACL; import org.apache.zookeeper.data.Stat;import java.util.List;public class ZookeeperClient {private static final String connectString 127.0.0.1:2181;private static final int sessionTimeout 2000;private static ZooKeeper zkClient null;public void init() throws Exception {zkClient new ZooKeeper(connectString, sessionTimeout, new Watcher() {Overridepublic void process(WatchedEvent event) {// 收到事件通知后的回调函数应该是我们自己的事件处理逻辑System.out.println(zookeeper链接建立);}});}public void createZnode()throws Exception{zkClient.create(/java, data.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);}public void createChildZnode()throws Exception{zkClient.create(/java/child, child data.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);zkClient.create(/java/child2, child2 data.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);}public void getChildNode()throws Exception{ListString res zkClient.getChildren(/java,false);for(String s : res){System.out.println(s);}}public void testExist() throws Exception{Stat stat zkClient.exists(/java, false);System.out.println(statnull?节点不存在:节点存在);}public void getNodeData()throws Exception{byte[] res zkClient.getData(/java,false,new Stat());System.out.println(new String(res));}public void getACl()throws Exception{ListACL res zkClient.getACL(/java,new Stat());for(ACL acl : res){System.out.println(acl.getId().toString()acl.getPerms());}}public static void main(String[] args)throws Exception{new ZookeeperClient().init();Thread.sleep(3000);new ZookeeperClient().createChildZnode();new ZookeeperClient().getChildNode();}} 用zookeeper实现服务注册与发现中心  经过前面的讲解我们已经对zookeeper建立起初步的概念这里就来做一个小小的实践用zookeeper实现一个简单版的服务注册与发现中心。 zookeeper的一个常见功能就是作为服务注册与发现中心。 我们先创建一个节点/services。 Stat stat zkClient.exists(/services,false);if (stat null ){zkClient.create(/services,.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);} 每当有一个服务上线时我们就向我们的服务注册与发现中心zookeeper注册我们的应用。 比如我们注册一个user服务服务地址是localhost:8080那么我们就在/services下面建立一个user子节点子节点数据为user服务的真实url地址比如localhost:8080子节点类型为临时节点。 public void registerService()throws Exception{zkClient.create(/services/user,localhost:8080.getBytes(),ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.EPHEMERAL);} 当我们向user请求服务时首先通过/services节点获取user服务判断user服务是否存在。进而获取它的地址发起真正的请求。同时我们注册一个监听事件监听节点的状态变化。当user服务出现故障或其他因素而下线时/services/user节点会被删除zookeeper server会通知到监听这个节点的客户端从而使客户端做出自己的响应同样的当user服务上线或地址修改客户端也能收到通知。 public void invokeUserService()throws Exception{Stat stat zkClient.exists(/services/user,false);if (stat null){System.out.println(未能找到user服务服务未注册或已下线);}byte[] url zkClient.getData(/services/user, new Watcher() {Overridepublic void process(WatchedEvent watchedEvent) {if (watchedEvent.getType() Event.EventType.NodeDeleted){System.out.println(服务下线); // 处理业务逻辑}if (watchedEvent.getType() Event.EventType.NodeCreated){System.out.println(服务上线); // 处理业务逻辑}if (watchedEvent.getType() Event.EventType.NodeDataChanged){System.out.println(服务地址修改了);}}}, null); // 处理业务逻辑System.out.println(向new String(url)发起请求);} 如果对前面有印象的话应该记得zookeeper的watcher只触发一次当节点状态改变一次之后节点状态的第二次改变就不能监听到了。为了能够持续监听我们需要修改一下我们的代码。 我们把判断服务上线的代码挪到上面来并且在下面的监听事件里回调invokeUserService方法实现持续监听的功能。 为了简单易懂这里代码写得并不够好如果是实际项目需要再做点拆分与封装。 public void invokeUserService()throws Exception{Stat stat zkClient.exists(/services/user,false);if (stat null){System.out.println(未能找到user服务服务未注册或已下线);zkClient.exists(/services/user, new Watcher() {Overridepublic void process(WatchedEvent watchedEvent) {if (watchedEvent.getType() Event.EventType.NodeCreated){System.out.println(服务上线); // 处理业务逻辑}}});}else{byte[] url zkClient.getData(/services/user, new Watcher() {Overridepublic void process(WatchedEvent watchedEvent) {if (watchedEvent.getType() Event.EventType.NodeDeleted){System.out.println(服务下线); // 处理业务逻辑}if (watchedEvent.getType() Event.EventType.NodeDataChanged){System.out.println(服务地址修改了);}try {invokeUserService();}catch (Exception e){}}}, null); // 处理业务逻辑System.out.println(向new String(url)发起请求);}}
http://www.tj-hxxt.cn/news/227164.html

相关文章:

  • 无锡做网站公司电话什么网站流量高
  • 最好的网站设濮阳网站建设熊掌网络
  • 中国e网网站建设深圳微信分销网站设计
  • 专业重庆房产网站建设企业网站页面图片
  • 黄石网站建设推荐狗和女人做的网站
  • 男生做男生网站在那看wordpress自动添加关键词和描述
  • 找做网站的公司好扬州市开发区建设局网站首页
  • 中国可信网站认证wordpress博客如何防止另存为
  • 共享办公室 设计网站优化价格
  • asp网站乱码中企动力做网站一次性付款
  • 网站制做工具百度权重查询入口
  • 个人网站怎么建三联网站建设
  • 网站开发学些什么软件如何给网站建设提意见
  • 网站注销重新备案网站后台怎么做alt标签
  • 福州培训网站建设wordpress如何设置用户中心
  • 站长域名查询工具风雨同舟 网站建设
  • 网站说服力 营销型网站策划网站建设专业团队图片
  • 做演讲和做演讲视频网站导航仪企业网站源码
  • 广州网站建设哪个公司做得好些广州vi设计公司
  • 网站建设微信开发网页模版之家
  • 怎么帮别人做网站崇安区网站建设价格
  • 网站建设国内公司个人网站制作
  • 兰溪城市建设规划网站郑州制作网页的公司
  • 宾馆网站模板多用户商城网站方案
  • 安康网站建设高端网站建设设计公司
  • 武安网站设计公司网站开发代码说明书
  • 网站做缓存企业网站如何优化排名
  • 我有一个网站怎么做外贸定制网站建设官网
  • 怎么用net123做网站昆明哪个公司做网站建设最好
  • 城市焦点商城网站建设案例建立什么网站