一、SpringCloud核心组件——Feign
①、实体类
首先,写一个用户实体类
建立pojo软件包,新建User实体类
user.java
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.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.websocket.server.PathParam; 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 getByParam(@PathParam("account") String account, @PathParam("account") String password){ System.out.println("account:"+account); return "provider say : yes"; } @RequestMapping("/pojo") public String getByPojo(@RequestBody User user){ System.out.println("pojo"+user); return "provider say : yes"; } @RequestMapping("/more") public String getByMore(@RequestBody Map<String,Object> map) { System.out.println("more" + map); return "provider say : yes"; } }
2、在消费者consumer中建立实体类和实现生产者方法的接口类
内容和生产者一样
接口FeignService:
package com.consumer.service; import com.consumer.pojo.User; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import javax.websocket.server.PathParam; import java.util.Map; @FeignClient("provider") @SuppressWarnings("all") public interface FeignUserService { //被接受传过来的账号 @RequestMapping("/user/{account}") public String getByPath(@PathVariable String account); //以请求的方式访问 @RequestMapping("/user/param") public String getByParam(@PathParam("account") String account, @PathParam("account") String password); @RequestMapping("/user/pojo") public String getByPojo(@RequestBody User user); @RequestMapping("/user/more") public String getByMore(@RequestBody Map<String,Object> map); }
注意:
@PathVariable中必须含有value()
@FeignClient("provider")消费者要与生产者进行通信,provider应为服务名
三种传参方式:
①.@PathVariable 路径传参
②.@RequestParam 请求参数传参
③.@RequestBody json传参
3、实现接口中的方法
package com.consumer.controller; import com.consumer.pojo.User; import com.consumer.service.FeignUserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PathVariable; 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(@PathVariable String account){ service.getByPath(account); return "yes"; } @RequestMapping("/test03") public String test03(String account,String password){ service.getByParam(account,password); return "yes"; } @RequestMapping("/test04") public String test04(String account,String password){ service.getByPojo(new User().setAccount(account).setPassword(password)); return "yes"; } @RequestMapping("/test05") public String test05(String account, String password) { Map<String, Object> map = new HashMap<String, Object>(); map.put("account", account); map.put("password", password); service.getByMore(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
①、不要继承父项目
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.hmf</groupId> <artifactId>code</artifactId> <version>0.0.1-SNAPSHOT</version> <name>commons</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <spring-boot.version>2.4.1</spring-boot.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring-boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> <configuration> <source>1.8</source> <target>1.8</target> <encoding>UTF-8</encoding> </configuration> </plugin> </plugins> </build> </project>
3、新建dto软件包
把所有的实体类移上来
package com.hmf.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
<dependency> <groupId>com.hmf</groupId> <artifactId>code</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency>
现在代码中实体类只需要写一次了,
生产者是要去数据库那数据的所有实体类不能删除,而消费者是与生产者进行远程通信的,因而删除
将消费者(consumer)中的pojo软件包删除
package com.consumer.service; import com.hmf.code.dto.UserDto; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import javax.websocket.server.PathParam; import java.util.Map; @FeignClient("provider") @SuppressWarnings("all") public interface FeignUserService { //被接受传过来的账号 @RequestMapping("/user/{account}") public String getByPath(@PathVariable String account); //以请求的方式访问 @RequestMapping("/user/param") public String getByParam(@PathParam("account") String account, @PathParam("account") String password); @RequestMapping("/user/pojo") public String getByPojo(@RequestBody UserDto user); @RequestMapping("/user/more") public String getByMore(@RequestBody Map<String,Object> map); }
FeignUserService中的User改为UserDto
两个实体类并不一致,但是并没有报错,因为是json接收,所以说前台与后台数据库并不一定保持一致
但是,我们的DTO并不完善,假如有一天DTO变了,因为Dto不可能只有账号密码这两个属性,假如增加了属性,User与DtoUser就会不匹配,所有修改生产者类的User改为UserDto
生产者类(provider)的User改为UserDto:
5、Orika
Orika:Orika对象复制教程(完美笔记) - 付宗乐 - 博客园
Orika 是 java Bean 映射框架,可以实现从一个对象递归拷贝数据至另一个对象。
在开发多层应用程序中非常有用。在这些层之间交换数据时,通常为了适应不同 API 需要转换一个实例至
另一个实例。
①、生产者(provider)导入依赖
<dependency> <groupId>ma.glasnost.orika</groupId> <artifactId>orika-core</artifactId> <version>1.4.6</version> </dependency>
我们现在需要做的是,将UserDto填到User中去,
②、生产者(provider)的启动类增加方法
由于每次使用MapperFactory都需要new出来,所有增加到启动类中去,
@Bean public MapperFactory mapperFactory(){ return new DefaultMapperFactory.Builder().build(); }
③、生产者(provider)的UserController类进行注入
将UserDto填到User中去,将dto转成user对象
User u = factuory.getMapperFacade().map(dto, User.class);
package com.provider.code.controller; import com.hmf.code.dto.UserDto; import com.provider.code.pojo.User; import ma.glasnost.orika.MapperFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.websocket.server.PathParam; import java.util.Map; @RestController @RequestMapping("/user") public class UserController { private MapperFactory factory; //被接受传过来的账号 @RequestMapping("/{account}") public String getByPath(@PathVariable String account){ System.out.println("account:" + account); return "provider say : yes"; } //以请求的方式访问 @RequestMapping("/param") public String getByParam(@PathParam("account") String account, @PathParam("account") String password){ System.out.println("account:"+account); return "provider say : yes"; } @RequestMapping("/pojo") public String getByPojo(@RequestBody UserDto dto){ // User u=new User(); //需要拿到的是实体类 根据实体类到数据库查询 // u.setAccount(dto.getAccount()).setPassword(dto.getPassword()); User u = factory.getMapperFacade().map(dto, User.class); System.out.println("pojo"+dto); return "provider say : yes"; } @RequestMapping("/more") public String getByMore(@RequestBody Map<String,Object> map) { System.out.println("more" + map); return "provider say : yes"; } }