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

网站如何做关键词排名高端网站建设公

网站如何做关键词排名,高端网站建设公,网络平台建设公司,路桥区商用营销型网站建设目录 前言 一、纯 RestTemplate 方案存在的缺陷 二、注册中心模式介绍 三、注册中心技术#xff1a;Nacos 3.1 Docker部署Nacos 3.2 服务注册 3.3 服务发现 四、代码优化#xff1a;OpenFeign工具 4.1 OpenFeign快速入门 4.2 连接池的必要性 4.3 抽取服务、最佳实…目录 前言 一、纯 RestTemplate 方案存在的缺陷 二、注册中心模式介绍 三、注册中心技术Nacos 3.1 Docker部署Nacos 3.2 服务注册 3.3 服务发现  四、代码优化OpenFeign工具 4.1 OpenFeign快速入门 4.2 连接池的必要性 4.3 抽取服务、最佳实践 4.4 日志配置 五、服务注册与调用巩固 前言 前面通过微服务基础入门我们大致了解的微服务的拆分。并且发现了跨微服务的请求调用问题。当时我们使用RestTemplate进行请求发送。也发现了一个比较大的问题——请求的url需要开发者人为提供这种硬编码的方式无论是在什么项目里都应该被避免。更何况如果一个微服务分布在好几台服务器上我们又该如何做负载均衡呢因此本篇主要针对跨微服务的优化问题提出解决方案的学习。 一、纯 RestTemplate 方案存在的缺陷 item-service这么多实例cart-service如何知道每一个实例的地址 http请求要写url地址cart-service服务到底该调用哪个实例呢 如果在运行过程中某一个item-service实例宕机cart-service依然在调用该怎么办 如果并发太高item-service临时多部署了N台实例cart-service如何知道新实例的地址 因此对于新方案必须要有以下几个优势 1. 只需关注有无实例有该功能调用无需关注调用实例的地址 2. 拥有负载均衡策略可以在多实例间自动进行策略切换 3. 自动监控实例健康状态及时切断异常实例的连接 4. 允许实例动态变化何时注册何时即可投入使用。 二、注册中心模式介绍 所谓注册中心模式可以理解为 “中介模式”拿房屋中介来举例子吧 房东【服务提供者】只需要把自己的房屋信息告诉注册中介不需要自己去找租客。 租客【服务消费者】只需要到房屋中介处寻找调用自己需要的房屋不需要满大街找房东。 而中介负责整合房屋资源注册服务列表同时在租客寻找的时候提供对应的房源提供调用 注意到我上面举例的用词了吧在微服务中也是一样的。在微服务远程调用的过程中包括两个角色 服务提供者提供接口供其它微服务访问比如item-service 服务消费者调用其它微服务提供的接口比如cart-service 注册中心模式的整体流程如下 服务启动时就会注册自己的服务信息服务名、IP、端口到注册中心 调用者可以从注册中心订阅想要的服务获取服务对应的实例列表1个服务可能多实例部署 调用者自己对实例列表负载均衡挑选一个实例 调用者向该实例发起远程调用 如何实现宕机实例、异常实例的检测 引入心跳检测机制【类似Redis的哨兵机制】所有注册到中心的实例每隔一段时间必须向中心发送信号证实自己是健康状态 当注册中心长时间收不到提供者的心跳时会认为该实例宕机将其从服务的实例列表中剔除 如何实现宕机通知、新添实例通知 当服务有新实例启动时会发送注册服务请求其信息会被记录在注册中心的服务实例列表 当注册中心服务列表变更时会主动通知微服务更新本地服务列表。 如何实现负载均衡策略 成功获取到实例列表后调用者可以根据一定的策略随机、轮询等挑选任意一个实例发送请求 三、注册中心技术Nacos 目前开源的注册中心框架有很多国内比较常见的有 EurekaNetflix公司出品目前被集成在SpringCloud当中一般用于Java应用 NacosAlibaba公司出品目前被集成在SpringCloudAlibaba中一般用于Java应用 ConsulHashiCorp公司出品目前集成在SpringCloud中不限制微服务语言 其中Nacos上手快、配置简单、并且有详细的中文文档提供学习。因此本次实验采取Nacos进行。 Nacos 快速开始https://nacos.io/zh-cn/docs/quick-start.html 3.1 Docker部署Nacos 【部署步骤】 导入nacos数据库文件修改nacos配置文件并上传到服务器执行容器创建命令确保启动顺序必须先启动数据库再启动nacos  测试访问http://192.168.186.140:8848/nacos/ 账号密码均为 nacos 首先Nacos需要管理服务列表必然是依赖数据库的。本次实验采取先前Docker布置好的MySQL。 第一步: 导入nacos数据库文件 第二步修改nacos配置文件并上传到服务器 第三步 执行容器创建命令 8848 是用于客户端与服务通信的主要端口。 9848 是 gRPC 端口用于与 Nacos 的 gRPC 通信如果需要。 9849 是 Raft 端口用于 Nacos 集群中节点之间的通信如果运行集群模式。 docker run -d \ --name nacos \ --env-file ./nacos/custom.env \ -p 8848:8848 \ -p 9848:9848 \ -p 9849:9849 \ --restartalways \ nacos/nacos-server:v2.1.0-slim 第四步确保启动顺序必须先启动数据库再启动nacos 第五步测试访问http://192.168.186.140:8848/nacos/ 账号密码均为 nacos 3.2 服务注册 导入坐标依赖配置nacos的访问地址和服务名称使用nacos 3.2.1 导入坐标依赖 在需要注册服务的模块中导入nacos的坐标 3.2.2 配置nacos的访问地址和服务名称 3.2.3 使用nacos 将服务注册到nacos我们拿item-service为例启动多个实例模拟多服务器部署 启动后查看nacos网站--服务列表 测试服务宕机后nacos服务列表是否会更新 3.3 服务发现  导入坐标依赖配置nacos的访问地址和服务名称发现并调用服务 3.3.1 导入坐标依赖 我们在cart-service中的pom.xml中添加nacos的依赖 !--nacos 服务注册发现-- dependencygroupIdcom.alibaba.cloud/groupIdartifactIdspring-cloud-starter-alibaba-nacos-discovery/artifactId /dependency 可以发现这里Nacos的依赖于服务注册时一致这个依赖中同时包含了服务注册和发现的功能。因为任何一个微服务都可以调用别人也可以被别人调用即可以是调用者也可以是提供者。 因此等一会儿cart-service启动同样会注册到Nacos 3.3.2 配置nacos的访问地址和服务名称 在cart-service的application.yml中添加nacos地址配置 spring:application:name: cart-servicecloud:nacos:server-addr: 192.168.186.140:8848 3.3.3 发现并调用服务 到此为止我们还需要准备负载均衡策略。以最简单的随机策略为例。 为了能够发现服务获取实例列表这里还需要使用SpringCloud提供的服务发现工具DiscoveryClient 该工具被SpringCloud自动注入装配我们只需要注入就可以使用我们利用它修改我们原先的代码逻辑 RestTemplase实现代码 使用DiscoveryClient工具 Nacos后代码 3.3.4 发现服务测试 3.3.5 完整代码 // 注入服务发现工具Resourceprivate DiscoveryClient discoveryClient;/*** DiscoveryClient* param vos*/private void handleCartItems(ListCartVO vos) {// 1.获取商品idSetLong itemIds vos.stream().map(CartVO::getItemId).collect(Collectors.toSet());// 2.查询商品// 2.1 发现item-service服务的请求实例ListServiceInstance instances discoveryClient.getInstances(item-service);if(CollUtils.isEmpty(instances)) {throw new BizIllegalException(商品服务不可用);}//2.2 负载均衡选择一个实例ServiceInstance instance instances.get(RandomUtil.randomInt(instances.size()));//2.3 构建请求、发送请求ResponseEntityListItemDTO response restTemplate.exchange(instance.getUri() /items?ids{ids}, // 请求路径HttpMethod.GET,null,new ParameterizedTypeReferenceListItemDTO() {},Map.of(ids, CollUtil.join(itemIds, ,)));//2.4 解析响应对象if(!response.getStatusCode().is2xxSuccessful()) {// 查询失败return;}// 2.5 获取查询商品对象ListItemDTO items response.getBody();// 3.构建商品id与商品对象的映射MapLong,ItemDTO itemMap items.stream().collect(Collectors.toMap(ItemDTO::getId, Function.identity()));//4. 写入VO对象返回前端for(CartVO v : vos) {ItemDTO item itemMap.get(v.getItemId());if(item null) {continue;}v.setNewPrice(item.getPrice()); // 最新价格v.setStock(item.getStock()); // 库存v.setStatus(item.getStatus()); // 状态}} 四、代码优化OpenFeign工具 到这里我们已经解决了跨微服务请求的难题了是不是挺简单的。确实SpringCloud给我们提供了太多好用的工具了使用DiscoveryClient Nacos RestTemplate解决了这个问题。 但是回看我们写的完整代码。是不是感觉有些复杂啊想要构建一个简单的请求。我们先是去寻找服务接着手写负载均衡选择实例、然后才是利用RestTemplate构建请求...... 如何能够优化项目代码减少开发者的工作量呢这一节我们使用另一个工具——OpenFegin来解决这个问题。 4.1 OpenFeign快速入门 以cart-service中的查询我的购物车为例。因此下面的操作都是在cart-service中进行。 【使用步骤】 引入OpenFeign依赖 和 loadBalancer负载均衡依赖启动类下添加 EnableFeignClients 依赖 启动 OpenFeign服务编写client接口用于实现请求发送这一步就跟你编写业务controller很像很像实现类中注入client接口使用client接口中的方法发送请求 4.1.1 引入依赖 !--openFeign--dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-openfeign/artifactId/dependency!--负载均衡器--dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-loadbalancer/artifactId/dependency 4.1.2 添加启动注解 在cart-service启动类下添加EnableFeignClients 依赖 启动 OpenFeign服务 4.1.3 编写client接口 无需编写实现类SpringCloud帮我们动态生成 4.1.4 实现类注入client接口 4.1.5 使用client定义的接口方法 你看看现在的代码是不是简单暴了。完全不需要再手动找服务、手动完成负载均衡、手动编写restTemplate发送请求了。 /*** OpenFeign实现* param vos*/private void handleCartItems(ListCartVO vos) {// 1.获取商品idSetLong itemIds vos.stream().map(CartVO::getItemId).collect(Collectors.toSet());// 2.查询商品ListItemDTO items itemClient.queryItemByIds(itemIds); // openfeign调用// 3.构建商品id与商品对象的映射MapLong,ItemDTO itemMap items.stream().collect(Collectors.toMap(ItemDTO::getId, Function.identity()));//4. 写入VO对象返回前端for(CartVO v : vos) {ItemDTO item itemMap.get(v.getItemId());if(item null) {continue;}v.setNewPrice(item.getPrice()); // 最新价格v.setStock(item.getStock()); // 库存v.setStatus(item.getStatus()); // 状态}} 4.1.6 测试代码 4.2 连接池的必要性 4.2.1 HTTP连接 与 HTTP消息 目前我们已经将代码优化得非常好了。理论上日常开发做到这块就可以了。但如如何还要想优化的话接下来我们需要考虑的就是开销方面的问题了。我们回忆一下现在我们每次需要发送跨端请求时都需要先建立服务器之间的连接然后才会去发送http消息。但是 两台服务器建立HTTP连接的过程复杂且耗时特别是其中的3次握手和4次分手过程产生的开销对于传输大量较小的HTTP消息来说这种开销显得尤为显著。 于是乎为了减少建立HTTP连接的大开销我们需要建立HTTP连接池。 4.2.2 HTTP客户端技术选型 主要用到的HTTP客户端技术包括以下三种其中第一种是OpenFeign默认的底层实现 HttpURLConnection默认实现不支持连接池 Apache HttpClient 支持连接池 OKHttp支持连接池 由于HttpURLConnection不支持连接池所有我们得更改其他的HTTP客户端技术本次实验选取OKHttp。 【HTTP客户端技术补充说明】 HttpURLConnection 概述 HttpURLConnection是Java标准库中的一部分用于发送HTTP请求和接收HTTP响应。它提供了一组简单的方法来发送HTTP请求和处理响应使开发人员能够轻松地与服务器进行通信。 特点 简单易用HttpURLConnection提供了直观的API使得HTTP请求和响应的处理变得简单。线程安全HttpURLConnection是线程安全的可以在多线程环境下使用而无需额外的同步措施。支持多种HTTP方法如GET、POST、PUT、DELETE等可以根据需要选择合适的方法进行请求。支持HTTPS可以与HTTPS服务器建立安全连接通过SSL/TLS协议进行数据传输确保数据的安全性。跨平台作为Java标准库的一部分可以在各种Java平台上使用具有良好的跨平台性。 限制 HttpURLConnection的默认实现不支持连接池这意味着每次发送HTTP请求时都需要建立新的连接这可能会导致性能下降特别是在发送大量HTTP请求的情况下。 Apache HttpClient 概述 Apache HttpClient是Apache软件基金会的一个项目是Java标准库之外的一个广泛使用的HTTP客户端库。它提供了丰富的功能和配置选项可以满足各种复杂的HTTP请求场景。 特点 稳定可靠Apache HttpClient是一个成熟稳定的HTTP客户端库拥有长期的开发历史和广泛的用户基础。支持连接池通过连接池技术可以有效地复用已经建立的连接减少连接建立和关闭的开销提高性能。支持HTTP/2最新版本的Apache HttpClient支持HTTP/2协议可以提供更高的性能和效率。丰富的配置选项提供了多种配置选项以满足不同的HTTP请求需求。 应用 Apache HttpClient适用于需要处理复杂HTTP请求和响应的场景如需要设置自定义请求头、处理重定向、管理Cookies等。 OKHttp 概述 OKHttp是一个开源的Java HTTP客户端库由Square公司开发。它被广泛用于Android开发和Java后端开发。OKHttp提供了一个简洁的API用于发送HTTP请求和处理HTTP响应。 特点 高性能OKHttp的底层实现基于Java的Socket和线程池使用了连接池和请求重用机制可以高效地处理大量的并发请求并减少网络延迟。支持连接池与Apache HttpClient类似OKHttp也支持连接池技术可以复用已经建立的连接。支持同步和异步请求OKHttp支持发送同步和异步的HTTP请求可以根据需要选择合适的请求方式。拦截器机制提供了拦截器机制可以在发送请求和接收响应的过程中进行干预和操作如添加公共头部、记录日志等。支持HTTP/2和SPDY这些协议可以提高网络性能和效率OKHttp会自动选择支持的协议进行通信。 应用 OKHttp适用于需要高性能和灵活配置的HTTP客户端场景如需要处理大量并发请求、需要自定义请求和响应处理等。 4.2.3 连接池的使用 引入依赖开启线程池配置验证底层变化 第一步引入依赖 在cart-service的pom.xml中引入依赖 !--OK http 的依赖 -- dependencygroupIdio.github.openfeign/groupIdartifactIdfeign-okhttp/artifactId /dependency 第二步: 开启线程池配置 在cart-service的yml文件中引入 第三步验证底层 4.3 抽取服务、最佳实践 呼现在应该是最佳方案了吧.......是吧其实还是有优化的优化是无止境的哈哈。你观察一下。其实微服务与微服务之间往往是双向调用的假设有1000个微服务两两互相调用。按照我们这种写法需要给每个微服务提供 999 个 client接口。那1000个微服务就要提供 999000个接口。喔喔喔是不是特别吓人。而且这些接口文件大都是重复的呀。 所以我们能不能把接口抽取成一个顶层模块其他微服务模块只需要“继承”该模块就能获得其中的方法。哇是不是很可行那咱们马上行动。 4.3.1 抽取思路分析 思路1抽取到微服务之外的公共modul 第一种的就是将所有的需要Fegin的接口都放入这个hm-api中不同模块都可以调用这个hm-api中的接口 优点抽取更加简单工程结构也比较清晰不需要额外拷贝别的微服务的DTO。 缺点耦合度比较高每个模块都可能都需要调用hm-api。 思路2每个微服务自己抽取一个module 第二种是将需要调用的接口放在自己的module下耦合度没有那么高但是实现相对麻烦工程结构相对更复杂、而且要额外拷贝别的微服务的DTO。 4.3.2 .抽取Feign客户端实践 在hmall下定义一个新的module命名为hm-api 导入依赖、导入实体对象、导入client接口 在hmall下定义一个新的module命名为hm-api 导入依赖、导入实体对象、导入client接口 ?xml version1.0 encodingUTF-8? project xmlnshttp://maven.apache.org/POM/4.0.0xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsdparentartifactIdhmall/artifactIdgroupIdcom.heima/groupIdversion1.0.0/version/parentmodelVersion4.0.0/modelVersionartifactIdhm-api/artifactIdpropertiesmaven.compiler.source11/maven.compiler.sourcemaven.compiler.target11/maven.compiler.target/propertiesdependencies!--open feign--dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-openfeign/artifactId/dependency!-- load balancer--dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-loadbalancer/artifactId/dependency!-- swagger 注解依赖 --dependencygroupIdio.swagger/groupIdartifactIdswagger-annotations/artifactIdversion1.6.6/versionscopecompile/scope/dependency/dependencies /project 现在任何微服务要调用item-service中的接口只需要引入hm-api模块依赖即可无需自己编写Feign客户端了。 4.3.3 配置扫描包 为什么要配置扫描包 cart-service的启动类定义在com.hmall.cart包下扫描不到ItemClient我们必须配置扫描包不然会报错。 【使用步骤】 在cart-service的pom.xml中引入hm-api模块配置扫描包路径 在cart-service的pom.xml中引入hm-api模块(模块调用模块) !--feign模块--dependencygroupIdcom.heima/groupIdartifactIdhm-api/artifactIdversion1.0.0/version/dependency 配置扫描包路径方法一声明扫描包 在cart-service的启动类上添加扫描 hm-api的声明 注意哈由于删除了原本模块中的client、dto。导包部分要重新导 配置扫描包路径方法一声明要用的FeignClient 在cart-service的启动类上添加声明要用的FeignClient 4.4 日志配置 OpenFeign只会在FeignClient所在包的日志级别为DEBUG时才会输出日志。而且其日志级别有4级 NONE不记录任何日志信息这是默认值。 BASIC仅记录请求的方法URL以及响应状态码和执行时间 HEADERS在BASIC的基础上额外记录了请求和响应的头信息 FULL记录所有请求和响应的明细包括头信息、请求体、元数据。 Feign默认的日志级别就是NONE所以默认我们看不到请求日志。 4.4.1 定义日志级别 package com.hmall.api.config;import feign.Logger; import org.springframework.context.annotation.Bean;public class DefaultFeignConfig {Beanpublic Logger.Level feignLogLevel(){return Logger.Level.FULL;} } 4.4.2 日志配置生效 【局部生效】在某个FeignClient中配置只对当前FeignClient生效 FeignClient(value item-service, configuration DefaultFeignConfig.class) 【全局生效】在EnableFeignClients中配置针对所有FeignClient生效。 EnableFeignClients(defaultConfiguration DefaultFeignConfig.class) 【日志格式】 22:26:25:336 DEBUG 4716 --- [nio-8082-exec-1] com.hmall.api.client.ItemClient : [ItemClient#queryItemByIds] --- GET http://item-service/items?ids100000006163 HTTP/1.1 22:26:25:336 DEBUG 4716 --- [nio-8082-exec-1] com.hmall.api.client.ItemClient : [ItemClient#queryItemByIds] --- END HTTP (0-byte body) 22:26:25:518 DEBUG 4716 --- [nio-8082-exec-1] com.hmall.api.client.ItemClient : [ItemClient#queryItemByIds] --- HTTP/1.1 200 (182ms) 22:26:25:518 DEBUG 4716 --- [nio-8082-exec-1] com.hmall.api.client.ItemClient : [ItemClient#queryItemByIds] connection: keep-alive 22:26:25:519 DEBUG 4716 --- [nio-8082-exec-1] com.hmall.api.client.ItemClient : [ItemClient#queryItemByIds] content-type: application/json 22:26:25:519 DEBUG 4716 --- [nio-8082-exec-1] com.hmall.api.client.ItemClient : [ItemClient#queryItemByIds] date: Fri, 01 Nov 2024 14:26:25 GMT 22:26:25:519 DEBUG 4716 --- [nio-8082-exec-1] com.hmall.api.client.ItemClient : [ItemClient#queryItemByIds] keep-alive: timeout60 22:26:25:519 DEBUG 4716 --- [nio-8082-exec-1] com.hmall.api.client.ItemClient : [ItemClient#queryItemByIds] transfer-encoding: chunked 22:26:25:519 DEBUG 4716 --- [nio-8082-exec-1] com.hmall.api.client.ItemClient : [ItemClient#queryItemByIds] 22:26:25:520 DEBUG 4716 --- [nio-8082-exec-1] com.hmall.api.client.ItemClient : [ItemClient#queryItemByIds] [{id:100000006163,name:巴布豆(BOBDOG)柔薄悦动婴儿拉拉裤XXL码80片(15kg以上),price:67100,stock:10000,image:https://m.360buyimg.com/mobilecms/s720x720_jfs/t23998/350/2363990466/222391/a6e9581d/5b7cba5bN0c18fb4f.jpg!q70.jpg.webp,category:拉拉裤,brand:巴布豆,spec:{},sold:11,commentCount:33343434,isAD:false,status:2}] 22:26:25:520 DEBUG 4716 --- [nio-8082-exec-1] com.hmall.api.client.ItemClient : [ItemClient#queryItemByIds] --- END HTTP (371-byte body) 22:26:26:007 INFO 4716 --- [ent-executor-12] com.alibaba.nacos.common.remote.client : [64fa38f0-9dff-4673-8014-52dbf5095a2f] Receive server push request, request NotifySubscriberRequest, requestId 22 22:26:26:008 INFO 4716 --- [ent-executor-12] com.alibaba.nacos.common.remote.client : [64fa38f0-9dff-4673-8014-52dbf5095a2f] Ack server push request, request NotifySubscriberRequest, requestId 22五、服务注册与调用巩固 1. 注册中心模式的角色有哪些流程是什么 2. 注册中心模式是如何实现宕机实例、异常实例的检测的 3. 概述一下Nacos的使用流程 4. 微服务中的服务发现是如何实现的 5. 如何优化微服务远程调用的代码逻辑取代RestTemplate的工具 6. 谈谈OpenFeign工具的使用流程 7. OpenFeign底层的HTTP客户端技术是什么有什么特点 8. 除了HttpURLConnection还要哪些HTTP客户端技术有何特点 9. 如何提高client接口代码的复用性。你有什么实现思路 10. 跨模块调用client接口方法的配置步骤
http://www.zqtcl.cn/news/709833/

相关文章:

  • 三维网站是怎么做的商城网站 运营
  • 程序员网站开发框架无锡网络公司网站建设app微信公众号平
  • 中关村网站建设网络营销策划书范文
  • 电商网站建设与课程设计科技网站模版
  • 建设部网站资质漳州最专业的网站建设公司
  • 网站建设需求和页面需求怎么提一个静态网站怎么做
  • 宝塔wordpress广州网站营销seo
  • 甘肃城乡建设厅网站首页发布公司信息的网站
  • 工信部网站备案查询 手机凡科网微信小程序制作
  • 一站多通怎么做网站网站推广工具 刷链接
  • 学生做网站的工作室网络舆情监测与研判考试重点
  • 做网站去哪个公司好广告创意设计论文
  • 20m带宽做网站够用吗win7创建wordpress
  • qq音乐怎么做mp3下载网站发卡网站建设方案
  • 做cpc不做网站可以吗网站跳出率
  • 公司网站变更域名有了域名就可以做网站了吗
  • 网站建设推广营销策划做外贸网站需要注册公司吗
  • 可信赖的赣州网站建设做羽毛球网站
  • 如何找网站做推广wordpress登录及注册
  • 韩国美容网站 模板wordpress中英文
  • 为什么邮箱突然进不去了总提示正在进入不安全网站wordpress需注册访问
  • 建网站哪家最好山东泰安房价
  • wordpress4.9+多站点网络推广公司联系昔年下拉
  • 西安seo网站关键词优化罗田县建设局网站
  • 北京网站建设 shwllnmp新手 wordpress
  • 优化网站结构一般包括如何进行网络营销风险控制
  • 怎样查看网站是用什么做的郫都区规划建设局网站
  • 新乡营销型网站建设制作网站设计的总结
  • 做网站的免费空间微信crm管理系统
  • 网站开发方向 英语翻译护肤品网页设计图片