欢迎您访问365答案网,请分享给你的朋友!
生活常识 学习资料

SpringCloud.远程消费

时间:2023-06-09
一、SpringCloud搭建

SpringCloud的架构图:

 nacos :

1、建立maven的父项目

①、cloud_01父项目

②、删除项目中的src(因为父项目没有代码,只需给子类提供依赖即可)

③、修改pom.xml

添加:

pom

2.4.12020.0.02021.1

dependencyManagement里放依赖版本号 

org.springframework.boot spring-boot-dependencies ${spring-boot.version} pom import org.springframework.cloud spring-cloud-dependencies ${spring-cloud.version} pom import com.alibaba.cloud spring-cloud-alibaba-dependencies ${spring-cloud-alibaba.version} pom import

引入依赖

org.springframework.boot spring-boot-starter-test org.springframework.boot spring-boot-starter-web com.alibaba.cloud spring-cloud-starter-alibaba-nacos-discovery org.springframework.cloud spring-cloud-starter-openfeign org.projectlombok lombok

2、搭建子项目

①、新建生产者provider

(1)、修改pom.xml

子项目(provider)继承父项目(cloud_01)

cloud_01 org.example 1.0-SNAPSHOT

父项目(cloud_01)承认子项目(provider)

provider

(2)、application.yml文件

spring: cloud: nacos: discovery: server-addr: 127.0.0.1:8848 application: name: providerserver: port: 8081

(3)、启动类添加注解

开启服务发现

@EnableDiscoveryClient

nacos中产生服务

②、新建消费者consumer

(1)、修改pom.xml

子项目(consumer)继承父项目(cloud_01)

cloud_01 org.example 1.0-SNAPSHOT

父项目(cloud_01)承认子项目(consumer)

provider consumer

(2)、application.yml文件

spring: cloud: nacos: discovery: server-addr: 127.0.0.1:8848 application: name: consumerserver: port: 8082

(3)、启动类添加注解

开启服务发现

@EnableDiscoveryClient

增加服务成功

3、调用方法

①、provider生产者编写生产鸡腿方法·

新建controller软件包,新建ProviderController

package com.provider.code.controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;@RestControllerpublic class ProviderController { @RequestMapping("/run") public String run(){ return ""; }}

 运行结果:
 

②、消费者编写获得鸡腿方法 (跨服务器访问)

(1)pom.xml中增加依赖(负载均衡)

org.springframework.cloud spring-cloud-loadbalancer

(2)启动类添加注解

启动类增加域名访问对象

@LoadBalanced:达到负载均衡的能力

(3)新建controller软件包,新建ConsumerController

package com.consumer.code.controller;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;import org.springframework.web.client.RestTemplate;@RestControllerpublic class ConsumerController { private RestTemplate restTemplate; @Autowired public ConsumerController(RestTemplate restTemplate) { this.restTemplate = restTemplate; } @RequestMapping("/run") public String run(){ return restTemplate.getForObject("http://provider/run",String.class); }}

运行结果:

  

二、(消费者生产者)远程调用接口定义

现在的生产者(provider)是没有接收参数的,返回String类型的

所以现在我们要是生产者接收参数

1、生产者(provider)

①、实体类

首先,写一个用户实体类

建立pojo软件包,新建User实体类

package com.provider.code.pojo;import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;import lombok.experimental.Accessors;@AllArgsConstructor@NoArgsConstructor@Data//链式编程@Accessors(chain=true)public class User {// 账号和密码 private String account; private String password;}

②、提供接口让别人来操纵用户实体类

使用UserController来构建一些有参数的东西

(1)UserController:

package com.provider.code.controller;import com.provider.code.pojo.User;import org.springframework.web.bind.annotation.*;import sun.security.util.Password;import java.util.Map;@RestController@RequestMapping("/user")public class UserController {// 接收别人传过来的账号 路径传值 @RequestMapping("/{account}") public String getByPath(@PathVariable String account){ System.out.println("account" + account); return "provider say : yes"; }// 请求直接携带 传两个参数 @RequestMapping("/param") public String getParam(@RequestParam("account") String account,@RequestParam("password") String password){ System.out.println("account" + account+"tpassword"+password); return "provider say : yes"; }// 传json数据 @RequestMapping("/pojo") public String getPojo(@RequestBody User user){ System.out.println("pojo" + user); return "provider say : yes"; }// 传入map @RequestMapping("/more") public String getMore(@RequestBody Map map){ System.out.println("more" + map); return "provider say : yes"; }}

(2)测试查看结果

 说明传参能访问到数据了,

2、消费者(Consumer)

在网页上是能访问到数据的,但是我们需要在消费者(ConsumerController)里面访问到

 RestTemplate能直接访问路径,路径带参直接/,请求带参直接?,但是json数据不好带,

所以修改上面的RestTemplate访问路径方法,直接方法访问

RestTemplate是用于两边进行通信(远程通信),它属于web启动器里面的

①、新建pojo软件包,新建user(与生产者user一模一样)

package com.consumer.code.pojo;import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;import lombok.experimental.Accessors;@AllArgsConstructor@NoArgsConstructor@Data//链式编程@Accessors(chain=true)public class User {// 账号和密码 private String account; private String password;}

②、新建service软件包,新建FeignUserService接口

使消费者直接调用生产者里面的接口

在消费者里面直接把生产者的接口定义出来

@FeignClient:远程通信

package com.consumer.code.service;import com.consumer.code.pojo.User;import org.springframework.cloud.openfeign.FeignClient;import org.springframework.web.bind.annotation.*;import java.util.Map;//远程通信 与生产者进行远程通信@FeignClient("provider")@SuppressWarnings("all")public interface FeignUserService {// 接收别人传过来的账号 路径传值 @RequestMapping("/user/{account}") String getByPath(@PathVariable(value = "account") String account);// 请求直接携带 传两个参数 @RequestMapping("/user/param") String getParam(@RequestParam("account") String account,@RequestParam("password") String password);// 传json数据 @RequestMapping("/user/pojo") String getPojo(@RequestBody User user);// 传入map @RequestMapping("/user/more") String getMore(@RequestBody Map map);}

③、启动类添加注解开启远程通信

增加这个注解FeignUserService就被托管了,

@EnableFeignClients

 到现在为止,整个连接就写完了,直接调方法

只要参数是复杂对象,即使指定了是 GET 方法, feign 依然会以 POST 方法进行发送请求,同时生产者必须支持POST 请求并给参数添加 @RequestBody 注解

④、controller包下新建UserController

消费者调用UserService接口

FeignClient接口,不能使用@GettingMapping之类的组合注解 FeignClient接口中,如果使用到@PathVariable必须指定其value 当使用feign传参数的时候,需要加上@RequestParam注解,否则对方服务无法识别参数
并使用 Feign 表示其需要远程对接的服务名称 , 并使用 @RequestMapping 表示其映射的 路径

package com.consumer.code.controller;import com.consumer.code.pojo.User;import com.consumer.code.service.FeignUserService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;import java.util.HashMap;import java.util.Map;@RestController@RequestMapping("user")public class UserController { private FeignUserService service; @Autowired public UserController(FeignUserService service) { this.service = service; } @RequestMapping("test01") public String test01(String account){ service.getByPath(account); return "yes 调用成功"; } @RequestMapping("/{account}") public String test02(String account){ service.getByPath(account); return "yes 调用成功"; } @RequestMapping("test03") public String test03(String account,String password){ service.getParam(account,password); return "yes 调用成功"; } @RequestMapping("test04") public String test04(String account,String password){ service.getPojo(new User().setAccount(account).setPassword(password)); return "yes 调用成功"; } @RequestMapping("test05") public String test05(String account,String password){ Map map=new HashMap<>(); map.put("account",account); map.put("password",password); service.getMore(map); return "yes 调用成功"; }}

测试结果

 三、DTO层的构建
VO(View Object) :视图对象,用于展示层,它的作用是把某个指定页面(或组件)的所有数据封装起来。 DTO(Data Transfer Object):数据传输对象,这个概念来源于J2EE的设计模式,原来的目的是为了EJB的分布式应用提供粗粒度的数据实体,以减少分布式调用的次数,从而提高分布式调用的性能和降低网络负载,但在这里,我泛指用于展示层与服务层之间的数据传输对象。 DO(Domain Object) :领域对象,就是从现实世界中抽象出来的有形或无形的业务实体。 PO(Persistent Object) :持久化对象,它跟持久层(通常是关系型数据库)的数据结构形成一一对应的映射关系,如果持久层是关系型数据库,那么,数据表中的每个字段(或若干个)就对应PO的一个(或若干个)属性 消费者 远程调用 生产者 : 需要网络传输 , 使用 DTO 同一封装对象 原理与 SpringBoot 启动类相同 1. 将 DTO 对象封装到公共 DTO 模块 2. 为需要的项目引入公共 DTO 模块 注意点 1. 不需要继承父模块 ( 重复引用问题 ) 2. 打包方式为 jar 3. 不需要添加启动类的编译

消费者调用生产者接口的时候还需要调用相关实体类,因此生产者和消费者的实体类一模一样,如果实体类过多,就会出现代码大量重复,因此,解决这一问题

把这些重复的类放到一个公共模块中,做成类似与启动器(web启动器:把某些功能封装在里面,要的时候就调用)的,在导入到这个类中

消费者(consumer)调用生产者(provider)的接口,生产者(provider)的接口需要一个user对象,消费者(consumer)在进行远程调用的时候需要把user对象传过去,服务之间互相调用使用DTO

所以,写一个公共模块,把所有的DTO封装起来

1、新建启动器

父项目上新建

2、修改pom.xml

①、不要继承父项目

②、删除test包

<?xml version="1.0" encoding="UTF-8"?> 4.0.0 com.cloud01 code 0.0.1-SNAPSHOT commons Demo project for Spring Boot 1.8 UTF-8 UTF-8 2.4.1 org.springframework.boot spring-boot-starter org.projectlombok lombok org.springframework.boot spring-boot-dependencies ${spring-boot.version} pom import org.apache.maven.plugins maven-compiler-plugin 3.8.1 1.8 1.8 UTF-8

3、新建dto软件包

 把所有的实体类移上来

将User改为UserDto,为了区分 

package com.cloud01.code.dto;import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;import lombok.experimental.Accessors;@AllArgsConstructor@NoArgsConstructor@Data//链式编程@Accessors(chain=true)public class UserDto {// 账号和密码 private String account; private String password;}

4、引用Commons

因为provider和consumer都要引用Commons

①、将Commons导成jar

 ②、父项目中进行依赖引入

pom.xml

com.cloud01 code 0.0.1-SNAPSHOT

单方面认亲

③、查看provider和consumer是否都要DTO功能

consumer启动类查看是否有DTO功能:

 现在代码中实体类只需要写一次了,

生产者是要去数据库那数据的所有实体类不能删除,而消费者是与生产者进行远程通信的,因而删除

将消费者(consumer)中的pojo软件包删除

FeignUserService中的User改为UserDto

 测试是否出现问题:

两个实体类并不一致,但是并没有报错,因为是json接收,所以说前台与后台数据库并不一定保持一致

但是,我们的DTO并不完善,假如有一天DTO变了,因为Dto不可能只有账号密码这两个属性,假如增加了属性,User与DtoUser就会不匹配,所有修改生产者类的User改为UserDto

生产者类(provider)的User改为UserDto:

 但是这样,假如属性多的话,数据就会很长 所有我们学习Orika框架

5、Orika

Orika:Orika对象复制教程(完美笔记) - 付宗乐 - 博客园

Orika 是 java Bean 映射框架,可以实现从一个对象递归拷贝数据至另一个对象。 在开发多层应用程序中非常有用。在这些层之间交换数据时,通常为了适应不同 API 需要转换一个实例至 另一个实例。

①、生产者(provider)导入依赖

ma.glasnost.orika orika-core 1.4.6

我们现在需要做的是,将UserDto填到User中去,

②、生产者(provider)的启动类增加方法

由于每次使用MapperFactory都需要new出来,所有增加到启动类中去,

@Beanpublic MapperFactory mapperFactory(){ return new DefaultMapperFactory.Builder().build();}

 ③、生产者(provider)的UserController类进行注入

将UserDto填到User中去,将dto转成user对象

属性相同的情况:这个适应的是属性完全一模一样(UserDto和User属性完全一样的) 

User map = factory.getMapperFacade().map(dto, User.class);

属性不同的情况:

field:里面放属性不同的

假设:生产者的账号改为name,而消费者的是account

factory.classMap(UserDto.class, User.class) .field("name", "userName") .byDefault().register();User user = factory.getMapperFacade().map(dto, User.class);

怕影响到的类的MapperFacade,因此:

单链模式改成原型链模式:

修改启动类:

Copyright © 2016-2020 www.365daan.com All Rights Reserved. 365答案网 版权所有 备案号:

部分内容来自互联网,版权归原作者所有,如有冒犯请联系我们,我们将在三个工作时内妥善处理。