2026/5/21 16:09:10
网站建设
项目流程
做网站 如何 挣钱,办公室设计公司,seo伪原创工具,wordpress 代码质量一、前言我们已经将黑马商城的前置知识学完#xff08;mp、docker#xff09;#xff0c;接下来就是要开始黑马商城项目了#xff0c;这个项目本身是一个已经做好的项目#xff0c;但是是单体架构#xff0c;和苍穹外卖是一样的#xff0c;现在我们将利用黑马商城来学习…一、前言我们已经将黑马商城的前置知识学完mp、docker接下来就是要开始黑马商城项目了这个项目本身是一个已经做好的项目但是是单体架构和苍穹外卖是一样的现在我们将利用黑马商城来学习微服务所以首先就需要拆分项目了。在这之前记得一定要创建一个git仓库并且虚拟机要定期保存快照本项目经多人实测中途可能会出现问题比如无法访问nacos网站等问题而本人也经历了虚拟机崩溃的问题所以在将来可能需要使用git回溯如果虚拟机出问题了也需要恢复快照。二、项目结构和拆分原则黑马商城的项目结构是比较简单的每一个板块都是分得比较清楚的比如有商品模块、购物车模块、订单模块、支付模块等等......这里我们选择将这些较为独立集中的模块拆分成项目结构中的模块也可以直接拆成一个独立的项目但是在学习期间不易管理如下图所示部分拆分同时需要导入不同模块所需要的表我们的拆分原则是拆分出功能相对独立的模块每一个拆分后的模块需要有自己单独的表。三、远程调用在拆分时我们会发现一些问题比如购物车模块需要依赖商品模块但是跨模块是不允许直接调用的而且也不能直接调用因为我们拆分项目的初衷是解耦合使项目更好管理如果模块之间相互依赖调用这样和单体架构就没什么两样了所以也就完全体现不出微服务的优势了。所以这里我们绝对不能直接调用这个时候就可以联想到之前苍穹外卖使使用过的HttpClient了当时我们是使用这个工具来让客户端获取店铺信息本质上是通过向管理端发起了一个请求然后获取管理端传回来的响应解析后拿到店铺状态。这里我们暂时就不使用httpclient了我们使用restTemplate首先需要注册到Bean中去所以要一个配置类但是由于这个配置很简单所以我们直接写在启动类中MapperScan(com.hmall.cart.mapper) SpringBootApplication public class CartApplication { public static void main(String[] args) { SpringApplication.run(CartApplication.class, args); } Bean public RestTemplate restTemplate(){ return new RestTemplate(); } }使用restTemplate主要也就分为两步1.发送请求并接收响应2.解析响应private void handleCartItems(ListCartVO vos) { // TODO 1.获取商品id SetLong 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.解析响应 if(!response.getStatusCode().is2xxSuccessful()){ // 查询失败直接结束 return; } ListItemDTO items response.getBody(); if (CollUtils.isEmpty(items)) { return; } // 3.转为 id 到 item的map 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.setStatus(item.getStatus()); v.setStock(item.getStock()); } }虽然逻辑简单但是代码确实不少太繁琐了所以后期我们会使用一个新技术来高度封装这些步骤这里学习RestTemplate有助于了解封装的底层原理所以还是需要看看的。四、Nacos注册中心1.简介首先我们要知道目前我们拆分了项目但是其实是没有进行统一管理的尤其是一个模块如果出现多个实例我们根本无法达到负载均衡。先前我们在nginx中提到了负载均衡的大致意思就是如果一个模块是一个服务器集群那么当多个请求访问这个服务器时可以将请求压力分摊到每个服务器上也就是不会一直只访问一个服务器这就是负载均衡。为了实现这个目的我们要引入一个管理中心——Nacos我们可以将每个模块注册进这个管理中心由Nacos管理有远程调用的需求时Nacos会自动将请求分配给目标服务器告诉请求发起者应该请求给哪个服务器。2.具体实现步骤1创建并启动容器首先我们要在虚拟机的Docker中用Nacos的镜像创建一个Nacos的容器2在目标模块导入依赖!--nacos 服务注册发现-- dependency groupIdcom.alibaba.cloud/groupId artifactIdspring-cloud-starter-alibaba-nacos-discovery/artifactId /dependency3写入配置文件cloud: nacos: server-addr: 192.168.xxx.xxx:8848这里就是指定Nacos容器所在的IP地址和Nacos的端口号这样就能让SpringCloud将项目注册到Nacos中了导入依赖的目的就是为了让这个配置生效。4测试这里我将启动三个模块其中有两个实例是源于一个模块相当于模拟一个服务器集群集群中有两台服务器这是就可以访问nacos的网站了在这里就可以统一管理服务器了这里我们发送五次请求看看是否实现了负载均衡从结果来看是实现了的8081和8083都是被请求到了的。五、OpenFeign刚刚在远程调用的时候就提到了使用restTemplate是及其不方便的也预告了后面会封装这个组件就是OpenFeign它通过和SpringBoot相似的语法减少了学习成本让远程调用更加规范耦合度更低最重要的是代码量大幅减少。OpenFeign的底层是可以选择的比如刚刚提到的httpclient除此之外还要okhttp等等。接下来讲解如何使用OpenFeign1.启动类首先启动类需要开启OpenFeignEnableFeignClients MapperScan(com.hmall.cart.mapper) SpringBootApplication public class CartApplication { public static void main(String[] args) { SpringApplication.run(CartApplication.class, args); } }2.导入依赖!--openFeign-- dependency groupIdorg.springframework.cloud/groupId artifactIdspring-cloud-starter-openfeign/artifactId /dependency /dependency !--OK http 的依赖 -- dependency groupIdio.github.openfeign/groupId artifactIdfeign-okhttp/artifactId /dependency3.配置feign: okhttp: enabled: true # 开启OKHttp功能4.创建接口这里注意这个接口是不需要被实现的和Mapper接口一样Spring会通过动态代理自动实现。FeignClient(item-service) public interface ItemClient { GetMapping(/items) ListItemDTO queryItemByIds(RequestParam(ids) CollectionLong ids); }可以看到这个接口的写法和SpringBoot的语法几乎一样所以也不再赘述就是需要注意要在注解写明远程调用的项目名5.远程调用修改代码一行代码就可以获取到item-service响应回来的数据了。private void handleCartItems(ListCartVO vos) { //1.获取商品id SetLong itemIds vos.stream().map(CartVO::getItemId).collect(Collectors.toSet()); //openfeign ListItemDTO items itemClient.queryItemByIds(itemIds); if (CollUtils.isEmpty(items)) { //如果查询失败 return; } // 3.转为 id 到 item的map 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.setStatus(item.getStatus()); v.setStock(item.getStock()); } }