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

广州公司网站托管外贸网站建设大概多少钱

广州公司网站托管,外贸网站建设大概多少钱,国家企业信用信息公示系统官网四川,aspx php哪个做门户网站好微服务拆分 接下来#xff0c;我们就一起将黑马商城这个单体项目拆分为微服务项目#xff0c;并解决其中出现的各种问题。 熟悉黑马商城 首先#xff0c;我们需要熟悉黑马商城项目的基本结构#xff1a; 大家可以直接启动该项目#xff0c;测试效果。不过#xff0c…微服务拆分 接下来我们就一起将黑马商城这个单体项目拆分为微服务项目并解决其中出现的各种问题。 熟悉黑马商城 首先我们需要熟悉黑马商城项目的基本结构 大家可以直接启动该项目测试效果。不过需要修改数据库连接参数在application-local.yaml中 hm:db:host: 192.168.202.128 # 修改为你自己的虚拟机IP地址pw: 1234 # 修改为docker中的MySQL密码同时配置启动项激活的是local环境 登录 首先来看一下登录业务流程 登录入口在com.hmall.controller.UserController中的login方法 搜索商品 在首页搜索框输入关键字点击搜索即可进入搜索列表页面 该页面会调用接口/search/list对应的服务端入口在com.hmall.controller.SearchController中的search方法 这里目前是利用数据库实现了简单的分页查询。 购物车 在搜索到的商品列表中点击按钮加入购物车即可将商品加入购物车 加入成功后即可进入购物车列表页查看自己购物车商品列表 同时这里还可以对购物车实现修改、删除等操作。 相关功能全部在com.hmall.controller.CartController中 其中查询购物车列表时由于要判断商品最新的价格和状态所以还需要查询商品信息业务流程如下 下单 在购物车页面点击结算按钮会进入订单结算页面 点击提交订单会提交请求到服务端服务端做3件事情 创建一个新的订单扣减商品库存清理购物车中商品 业务入口在com.hmall.controller.OrderController中的createOrder方法 支付 下单完成后会跳转到支付页面目前只支持余额支付 在选择余额支付这种方式后会发起请求到服务端服务端会立刻创建一个支付流水单并返回支付流水单号到前端。 当用户输入用户密码然后点击确认支付时页面会发送请求到服务端而服务端会做几件事情 校验用户密码扣减余额修改支付流水状态修改交易订单状态 请求入口在com.hmall.controller.PayController中 服务拆分原则 服务拆分一定要考虑几个问题 什么时候拆如何拆 什么时候拆 一般情况下对于一个初创的项目首先要做的是验证项目的可行性。因此这一阶段的首要任务是敏捷开发快速产出生产可用的产品投入市场做验证。为了达成这一目的该阶段项目架构往往会比较简单很多情况下会直接采用单体架构这样开发成本比较低可以快速产出结果一旦发现项目不符合市场损失较小。如果这一阶段采用复杂的微服务架构投入大量的人力和时间成本用于架构设计最终发现产品不符合市场需求等于全部做了无用功。 所以对于大多数小型项目来说一般是先采用单体架构随着用户规模扩大、业务复杂后再逐渐拆分为微服务架构**。这样初期成本会比较低可以快速试错。但是这么做的问题就在于后期做服务拆分时可能会遇到很多代码耦合带来的问题拆分比较困难**前易后难。 而对于一些大型项目在立项之初目的就很明确为了长远考虑在架构设计时就直接选择微服务架构。虽然前期投入较多但后期就少了拆分服务的烦恼前难后易。 怎么拆 之前我们说过微服务拆分时粒度要小这其实是拆分的目标。具体可以从两个角度来分析 高内聚每个微服务的职责要尽量单一包含的业务相互关联度高、完整度高。低耦合每个微服务的功能要相对独立尽量减少对其它微服务的依赖或者依赖接口的稳定性要强。 高内聚首先是单一职责但不能说一个微服务就一个接口而是要保证微服务内部业务的完整性为前提。目标是当我们要修改某个业务时最好就只修改当前微服务这样变更的成本更低。一旦微服务做到了高内聚那么服务之间的耦合度自然就降低了。 当然微服务之间不可避免的会有或多或少的业务交互比如下单时需要查询商品数据。这个时候我们不能在订单服务直接查询商品数据库否则就导致了数据耦合。而应该由商品服务对应暴露接口并且一定要保证微服务对外接口的稳定性即尽量保证接口外观不变。虽然出现了服务间调用但此时无论你如何在商品服务做内部修改都不会影响到订单微服务服务间的耦合度就降低了。 明确了拆分目标接下来就是拆分方式了。我们在做服务拆分时一般有两种方式 纵向拆分横向拆分 所谓纵向拆分就是按照项目的功能模块来拆分。例如黑马商城中就有用户管理功能、订单管理功能、购物车功能、商品管理功能、支付功能等。那么按照功能模块将他们拆分为一个个服务就属于纵向拆分。这种拆分模式可以尽可能提高服务的内聚性。 而横向拆分是看各个功能模块之间有没有公共的业务部分如果有将其抽取出来作为通用服务。例如用户登录是需要发送消息通知记录风控数据下单时也要发送短信记录风控数据。因此消息发送、风控数据记录就是通用的业务功能因此可以将他们分别抽取为公共服务消息中心服务、风控管理服务。这样可以提高业务的复用性避免重复开发。同时通用业务一般接口稳定性较强也不会使服务之间过分耦合。 当然由于黑马商城并不是一个完整的项目其中的短信发送、风控管理并没有实现这里就不再考虑了。而其它的业务按照纵向拆分可以分为以下几个微服务 用户服务商品服务订单服务购物车服务支付服务 拆分购物车、商品服务 接下来我们先把商品管理功能、购物车功能抽取为两个独立服务。 一般微服务项目有两种不同的工程结构 完全解耦每一个微服务都创建为一个独立的工程甚至可以使用不同的开发语言来开发项目完全解耦。 优点服务之间耦合度低缺点每个项目都有自己的独立仓库管理起来比较麻烦 Maven聚合整个项目为一个Project然后每个微服务是其中的一个Module 优点项目代码集中管理和运维方便缺点服务之间耦合编译时间较长 注意 这里采用Maven聚合工程大家以后到了企业可以根据需求自由选择工程结构。在hmall父工程之中我已经提前定义了SpringBoot、SpringCloud的依赖版本所以为了方便期间我们直接在这个项目中创建微服务module. 商品服务 在hmall中创建module选择maven模块并设定JDK版本为11。商品模块我们起名为item-service 引入依赖 ?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/modelVersionartifactIditem-service/artifactIdpropertiesmaven.compiler.source11/maven.compiler.sourcemaven.compiler.target11/maven.compiler.target/propertiesdependencies!--common--dependencygroupIdcom.heima/groupIdartifactIdhm-common/artifactIdversion1.0.0/version/dependency!--web--dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependency!--数据库--dependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactId/dependency!--mybatis--dependencygroupIdcom.baomidou/groupIdartifactIdmybatis-plus-boot-starter/artifactId/dependency!--单元测试--dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactId/dependency/dependenciesbuildfinalName${project.artifactId}/finalNamepluginsplugingroupIdorg.springframework.boot/groupIdartifactIdspring-boot-maven-plugin/artifactId/plugin/plugins/build /project编写启动类 代码如下 package com.hmall.item;import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;MapperScan(com.hmall.item.mapper) SpringBootApplication public class ItemApplication {public static void main(String[] args) {SpringApplication.run(ItemApplication.class, args);} }接下来是配置文件可以从hm-service中拷贝 其中application.yaml内容如下 server:# port: 8080port: 8081spring:application:name: item-service# name: hm-serviceprofiles:active: devdatasource:url: jdbc:mysql://${hm.db.host}:3306/hmall?useUnicodetruecharacterEncodingUTF-8autoReconnecttrueserverTimezoneAsia/Shanghaidriver-class-name: com.mysql.cj.jdbc.Driverusername: rootpassword: ${hm.db.pw} mybatis-plus:configuration:default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandlerglobal-config:db-config:update-strategy: not_nullid-type: auto logging:level:com.hmall: debugpattern:dateformat: HH:mm:ss:SSSfile:path: logs/${spring.application.name} knife4j:enable: trueopenapi:title: 商品服务接口# title: 黑马商城接口文档description: 信息#description: 黑马商城接口文档email: zs0536stu.edu.cnconcat: Charlieurl: https://www.itcast.cnversion: v1.0.0group:default:group-name: defaultapi-rule: packageapi-rule-resources:- com.hmall.item.controller # - com.hmall.controller剩下的application-dev.yaml和application-local.yaml直接从hm-service拷贝即可。 然后拷贝hm-service中与商品管理有关的代码到item-service如图 这里有一个地方的代码需要改动就是ItemServiceImpl中的deductStock方法 改动前 改动后 这也是因为ItemMapper的所在包发生了变化因此这里代码必须修改包路径。 最后还要导入数据库表。默认的数据库连接的是虚拟机在你docker数据库执行网盘中提供的SQL文件 通过网盘分享的文件微服务独立数据库 链接: https://pan.baidu.com/s/1ep9hMO6m8st8nEHedW-R6w?pwdj6am 提取码: j6am –来自百度网盘超级会员v5的分享 最终会在数据库创建一个名为hm-item的database将来的每一个微服务都会有自己的一个database 注意在企业开发的生产环境中每一个微服务都应该有自己的独立数据库服务而不仅仅是database课堂我们用database来代替。 接下来就可以启动测试了在启动前我们要配置一下启动项让默认激活的配置为local而不是dev,在打开的编辑框填写active profiles: 接着启动item-service访问商品微服务的swagger接口文档http://localhost:8081/doc.html 然后测试其中的根据id批量查询商品这个接口测试参数100002672302,100002624500,100002533430结果如下 说明商品微服务抽取成功了。 购物车服务 与商品服务类似在hmall下创建一个新的module起名为cart-service: 然后是依赖 ?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/modelVersionartifactIdcart-service/artifactIdpropertiesmaven.compiler.source11/maven.compiler.sourcemaven.compiler.target11/maven.compiler.target/propertiesdependencies!--common--dependencygroupIdcom.heima/groupIdartifactIdhm-common/artifactIdversion1.0.0/version/dependency!--web--dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependency!--数据库--dependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactId/dependency!--mybatis--dependencygroupIdcom.baomidou/groupIdartifactIdmybatis-plus-boot-starter/artifactId/dependency!--单元测试--dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactId/dependency/dependenciesbuildfinalName${project.artifactId}/finalNamepluginsplugingroupIdorg.springframework.boot/groupIdartifactIdspring-boot-maven-plugin/artifactId/plugin/plugins/build /project然后是启动类 package com.hmall.cart;import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;MapperScan(com.hmall.cart.mapper) SpringBootApplication public class CartApplication {public static void main(String[] args) {SpringApplication.run(CartApplication.class, args);} }然后是配置文件同样可以拷贝自item-service不过其中的application.yaml需要修改 server:port: 8082 spring:application:name: cart-serviceprofiles:active: devdatasource:url: jdbc:mysql://${hm.db.host}:3306/hm-cart?useUnicodetruecharacterEncodingUTF-8autoReconnecttrueserverTimezoneAsia/Shanghaidriver-class-name: com.mysql.cj.jdbc.Driverusername: rootpassword: ${hm.db.pw} mybatis-plus:configuration:default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandlerglobal-config:db-config:update-strategy: not_nullid-type: auto logging:level:com.hmall: debugpattern:dateformat: HH:mm:ss:SSSfile:path: logs/${spring.application.name} knife4j:enable: trueopenapi:title: 购物车服务接口description: 信息email: zs0536stu.edu.cnconcat: Charlieurl: https://www.itcast.cnversion: v1.0.0group:default:group-name: defaultapi-rule: packageapi-rule-resources:- com.hmall.cart.controller最后把hm-service中的与购物车有关功能拷贝过来最终的项目结构如下 特别注意的是com.hmall.cart.service.impl.CartServiceImpl其中有两个地方需要处理 需要获取登录用户信息但登录校验功能目前没有复制过来先写死固定用户id查询购物车时需要查询商品信息而商品信息不在当前服务需要先将这部分代码注释 我们对这部分代码做如下修改 package com.hmall.cart.service.impl;import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.hmall.cart.domain.dto.CartFormDTO; import com.hmall.cart.domain.po.Cart; import com.hmall.cart.domain.vo.CartVO; import com.hmall.cart.mapper.CartMapper; import com.hmall.cart.service.ICartService; import com.hmall.common.exception.BizIllegalException; import com.hmall.common.utils.BeanUtils; import com.hmall.common.utils.CollUtils; import com.hmall.common.utils.UserContext; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service;import java.util.Collection; import java.util.List;/*** p* 订单详情表 服务实现类* /p** author 虎哥* since 2023-05-05*/ Service RequiredArgsConstructor public class CartServiceImpl extends ServiceImplCartMapper, Cart implements ICartService {// private final IItemService itemService;Overridepublic void addItem2Cart(CartFormDTO cartFormDTO) {// 1.获取登录用户Long userId UserContext.getUser();// 2.判断是否已经存在if (checkItemExists(cartFormDTO.getItemId(), userId)) {// 2.1.存在则更新数量baseMapper.updateNum(cartFormDTO.getItemId(), userId);return;}// 2.2.不存在判断是否超过购物车数量checkCartsFull(userId);// 3.新增购物车条目// 3.1.转换POCart cart BeanUtils.copyBean(cartFormDTO, Cart.class);// 3.2.保存当前用户cart.setUserId(userId);// 3.3.保存到数据库save(cart);}Overridepublic ListCartVO queryMyCarts() {// 1.查询我的购物车列表ListCart carts lambdaQuery().eq(Cart::getUserId, 1L /*TODO UserContext.getUser()*/).list();if (CollUtils.isEmpty(carts)) {return CollUtils.emptyList();}// 2.转换VOListCartVO vos BeanUtils.copyList(carts, CartVO.class);// 3.处理VO中的商品信息handleCartItems(vos);// 4.返回return vos;}private void handleCartItems(ListCartVO vos) {// 1.获取商品id TODO 处理商品信息/*SetLong itemIds vos.stream().map(CartVO::getItemId).collect(Collectors.toSet());// 2.查询商品ListItemDTO items itemService.queryItemByIds(itemIds);if (CollUtils.isEmpty(items)) {throw new BadRequestException(购物车中商品不存在);}// 3.转为 id 到 item的mapMapLong, ItemDTO itemMap items.stream().collect(Collectors.toMap(ItemDTO::getId, Function.identity()));// 4.写入vofor (CartVO v : vos) {ItemDTO item itemMap.get(v.getItemId());if (item null) {continue;}v.setNewPrice(item.getPrice());v.setStatus(item.getStatus());v.setStock(item.getStock());}*/}Overridepublic void removeByItemIds(CollectionLong itemIds) {// 1.构建删除条件userId和itemIdQueryWrapperCart queryWrapper new QueryWrapperCart();queryWrapper.lambda().eq(Cart::getUserId, UserContext.getUser()).in(Cart::getItemId, itemIds);// 2.删除remove(queryWrapper);}private void checkCartsFull(Long userId) {int count lambdaQuery().eq(Cart::getUserId, userId).count();if (count 10) {throw new BizIllegalException(StrUtil.format(用户购物车课程不能超过{}, 10));}}private boolean checkItemExists(Long itemId, Long userId) {int count lambdaQuery().eq(Cart::getUserId, userId).eq(Cart::getItemId, itemId).count();return count 0;} }最后还是要导入数据库表在资料对应的SQL文件 在数据库中会出现名为hm-cart的database以及其中的cart表代表购物车 接下来就可以测试了。不过在启动前同样要配置启动项的active profile为local 然后启动CartApplication访问swagger文档页面http://localhost:8082/doc.html 我们测试其中的查询我的购物车列表接口无需填写参数直接访问 我们注意到其中与商品有关的几个字段值都为空这就是因为刚才我们注释掉了查询购物车时查询商品信息的相关代码。 那么我们该如何在cart-service服务中实现对item-service服务的查询呢 服务调用 在拆分的时候我们发现一个问题就是购物车业务中需要查询商品信息但商品信息查询的逻辑全部迁移到了item-service服务导致我们无法查询。 最终结果就是查询到的购物车数据不完整因此要想解决这个问题我们就必须改造其中的代码把原本本地方法调用改造成跨微服务的远程调用RPC即Remote Produce Call。 因此现在查询购物车列表的流程变成了这样 代码中需要变化的就是这一步 那么问题来了我们该如何跨服务调用准确的说如何在cart-service中获取item-service服务中的提供的商品数据呢 大家思考一下我们以前有没有实现过类似的远程查询的功能呢 答案是肯定的我们前端向服务端查询数据其实就是从浏览器远程查询服务端数据。比如我们刚才通过Swagger测试商品查询接口就是向http://localhost:8081/items这个接口发起的请求 而这种查询就是通过http请求的方式来完成的不仅仅可以实现远程查询还可以实现新增、删除等各种远程请求。 假如我们在cart-service中能模拟浏览器发送http请求到item-service是不是就实现了跨微服务的远程调用了呢 那么我们该如何用Java代码发送Http的请求呢 RestTemplate Spring给我们提供了一个RestTemplate的API可以方便的实现Http请求的发送。 org.springframework.web.client public class RestTemplate extends InterceptingHttpAccessor implements RestOperations ---------------------------------------------------------------------------------------------------------------- 同步客户端执行HTTP请求在底层HTTP客户端库(如JDK HttpURLConnection、Apache HttpComponents等)上公开一个简单的模板方法API。RestTemplate通过HTTP方法为常见场景提供了模板此外还提供了支持不太常见情况的通用交换和执行方法。 RestTemplate通常用作共享组件。然而它的配置不支持并发修改因此它的配置通常是在启动时准备的。如果需要您可以在启动时创建多个不同配置的RestTemplate实例。如果这些实例需要共享HTTP客户端资源它们可以使用相同的底层ClientHttpRequestFactory。 注意:从5.0开始这个类处于维护模式只有对更改和错误的小请求才会被接受。请考虑使用org.springframework.web.react .client. webclient它有更现代的API支持同步、异步和流场景。 ---------------------------------------------------------------------------------------------------------------- 自: 3.0 参见: HttpMessageConverter, RequestCallback, ResponseExtractor, ResponseErrorHandler 其中提供了大量的方法方便我们发送Http请求例如 可以看到常见的Get、Post、Put、Delete请求都支持如果请求参数比较复杂还可以使用exchange方法来构造请求。 我们在cart-service服务中定义一个配置类 先将RestTemplate注册为一个Bean package com.hmall.cart.config;import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate;Configuration public class RemoteCallConfig {Beanpublic RestTemplate restTemplate() {return new RestTemplate();} }远程调用 接下来我们修改cart-service中的com.hmall.cart.service.impl.CartServiceImpl的handleCartItems方法发送http请求到item-service 可以看到利用RestTemplate发送http请求与前端ajax发送请求非常相似都包含四部分信息 ① 请求方式② 请求路径③ 请求参数④ 返回值类型 handleCartItems方法的完整代码如下 private void handleCartItems(ListCartVO vos) {// TODO 1.获取商品idSetLong itemIds vos.stream().map(CartVO::getItemId).collect(Collectors.toSet());// 2.查询商品// ListItemDTO items itemService.queryItemByIds(itemIds);// 2.1.利用RestTemplate发起http请求得到http的响应ResponseEntityListItemDTO response restTemplate.exchange(http://localhost:8081/items?ids{ids},HttpMethod.GET,null,new ParameterizedTypeReferenceListItemDTO() {},Map.of(ids, CollUtil.join(itemIds, ,)));// 2.2.解析响应检查HTTP响应的状态码是否在200-299范围内表示请求成功。if(!response.getStatusCode().is2xxSuccessful()){// 查询失败直接结束return;}// 获取响应体中的商品信息ListItemDTO items response.getBody();if (CollUtils.isEmpty(items)) {return;}// 3.转为 id 到 item的mapMapLong, ItemDTO itemMap items.stream().collect(Collectors.toMap(ItemDTO::getId, Function.identity()));// 4.写入vofor (CartVO v : vos) {ItemDTO item itemMap.get(v.getItemId());if (item null) {continue;}v.setNewPrice(item.getPrice());v.setStatus(item.getStatus());v.setStock(item.getStock());} }好了现在重启cart-service再次测试查询我的购物车列表接口 可以发现所有商品相关数据都已经查询到了。 在这个过程中item-service提供了查询接口cart-service利用Http请求调用该接口。因此item-service可以称为服务的提供者而cart-service则称为服务的消费者或服务调用者。 总结 什么时候需要拆分微服务 如果是创业型公司最好先用单体架构快速迭代开发验证市场运作模型快速试错。当业务跑通以后随着业务规模扩大、人员规模增加再考虑拆分微服务。如果是大型企业有充足的资源可以在项目开始之初就搭建微服务架构。 如何拆分 首先要做到高内聚、低耦合从拆分方式来说有横向拆分和纵向拆分两种。纵向就是按照业务功能模块横向则是拆分通用性业务提高复用性 服务拆分之后不可避免的会出现跨微服务的业务此时微服务之间就需要进行远程调用。微服务之间的远程调用被称为RPC即远程过程调用。RPC的实现方式有很多比如 基于Http协议基于Dubbo协议 我们课堂中使用的是Http方式这种方式不关心服务提供者的具体技术实现只要对外暴露Http接口即可更符合微服务的需要。 Java发送http请求可以使用Spring提供的RestTemplate使用的基本步骤如下 注册RestTemplate到Spring容器调用RestTemplate的API发送请求常见方法有 getForObject发送Get请求并返回指定类型对象PostForObject发送Post请求并返回指定类型对象put发送PUT请求delete发送Delete请求exchange发送任意类型请求返回ResponseEntity
http://www.w-s-a.com/news/204203/

相关文章:

  • 网站平台建设的作用电影宣传类网页界面设计
  • 户外网站模板国外优秀的平面设计网站
  • 家政网站怎么做网站机房建设方案
  • 学校网站建设运行情况2022年近期舆情热点话题
  • 做淘宝需要知道什么网站吗有没有做软件的网站
  • 安丘网站建设制作做网站和微信小程序
  • 京东网站的建设与发展前景黑龙江建设网官网登陆
  • soho的网站怎么做微网站平台建设方案
  • 网站开发下载阿里云oss做视频网站
  • 东莞营销网站制作做一个网站建设
  • 啥网站都能看的浏览器下载网站后台管理系统展望
  • 新建站点步骤汉中 wordpress联盟
  • 坪山网站设计的公司网站 seo 设置
  • 济南网站设计公司排名如何免费注册网站域名
  • 网站开发分工甜妹妹福利wordpress
  • 网站中英文要怎么做网站建设的策划文案
  • 合肥推广外包公司佛山seo
  • 成都网站品牌设计策划课堂网站开发
  • 做直播网站赚钱公司网站空间怎么续费
  • 企业网站制作公司有哪些太原网站建设 thinkphp3.2
  • 云集网站哪个公司做的百度竞价排名怎么做
  • 做网站公司赚钱吗网站建设英语翻译
  • 网络公司除了做网站产品设计作品
  • dede网站模板替换湘潭建设路街道网站
  • 东莞网站优化效果如何网络设计工作
  • 网站备案系统验证码出错的解决方案任丘建设银行网站
  • 个人博客建站wordpress叮当app制作
  • 网站式的公司记录怎么做二手书网站策划书
  • 营销型网站的建设重点是什么帝国程序和WordPress
  • 正能量网站推荐不需要下载巴中网站建设开发公司