SpringCload搭建(二):使用Feign远程调用和参数,公共模块:传输对象dto,0X orika方便赋值
在上篇文章中,我们使用了@LoadBalanced //开启负载均衡大大简化了远程调用时的代码:
String forEntity = restTemplate.getForObject("http://provider/test/hello", String.class);
1.简介
Feign可以把Rest的请求进行隐藏,伪装成类似SpringMVC的Controller一样。你不用再自己拼接url,拼接参数等等操作,一切都交给Feign去做
2.consumer层使用feign替代RestTemplate去远程调用provider的流程
2.1 建立一个feign接口类(放需要远程调用的接口)
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @Author: LJX
* @DateTime: 2022/3/12 15:06
* @Description: TODO
*/
@Service
@FeignClient("provider")
public interface HelloFeign {
/**
* 这里配置生产者的接口
* @return
*/
@RequestMapping("/test/hello")
String hello();
}
2.2consumer去调用
@Resource
private HelloFeign helloFeign;
@RequestMapping("/hello")
public String hello(){
System.out.println("消费者");
//调用生产者,url + 返回类型
// String forEntity = restTemplate.getForObject("http://provider/test/hello", String.class);
String hello = helloFeign.hello();
return hello;
}
2.3调用生产者成功:消费者的启动类添加注解@EnableFeignClients
3.公共模块(maven项目,不需要启动类和继承父类):传输对象dto
3.1 为何公共模块可以跨模块调用:
因为在父类的pom文件中引入了依赖
<!-- 公共Vo模块-->
<dependency>
<groupId>com.xiu</groupId>
<artifactId>common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
3.2 消费者通过feign调用生产者,如果insert(Book book),那么消费者中也要有Book去传参,可是feign只是远程调用接口,那么实体类怎么跨模块呢?
传参形式:http://localhost:6101/book/insert?bookId=1&bookName=hhh&price=1.1&desc=这是啥书,到了消费者可以接收到值,但是消费者 -->生产者
{bookid: 1,bookName=hhh...},这种形式给生产者,生产者是识别不出来的,所以要加上注解:
@RequestBody
Feign综合示例
1~N个参数
@RequestParam Long bookId
1个复杂对象DTO
生产者接受参数时要添加@RequestBody
将DTO对象定义到公共模块
附录一:远程调用的相关注解
@PathVariable
--
@RequestMapping("show5/{id}/{name}")
public ModelAndView test5(@PathVariable("id") Long ids ,@PathVariable("name") String names){
ModelAndView mv = new ModelAndView();
mv.addObject("msg","占位符映射:id:"+ids+";name:"+names);
mv.setViewName("hello2");
return mv;
}
@RequestParam
@RequestBody
@RequestMapping
注解RequestMapping中produces属性可以设置返回数据的类型以及编码,可以是json或者xml:
@RequestMapping(value="/xxx",produces = {"application/json;charset=UTF-8"})
@RequestMapping(value="/xxx",produces = {"application/xml;charset=UTF-8"})
4.0X orika 方便dto对象赋值给po对象
1.从消费者到生产者传值方法:set

2.从消费者到生产者传值方法:直接使用dto对象传到service层
3.使用orika进行dto对po对象的赋值
3.1.导入依赖
<!-- https://mvnrepository.com/artifact/ma.glasnost.orika/orika-core -->
<dependency>
<groupId>ma.glasnost.orika</groupId>
<artifactId>orika-core</artifactId>
<version>1.5.4</version>
</dependency>
3.2 下配置
package com.xiu.provider.config;
import com.xiu.common.dto.BookDto;
import com.xiu.provider.model.Book;
import ma.glasnost.orika.MapperFactory;
import ma.glasnost.orika.impl.DefaultMapperFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @Author: LJX
* @DateTime: 2022/3/13 21:07
* @Description: TODO
*/
@Configuration
public class OrikaConfig {
@Bean
public MapperFactory mapperFactory() {
return new DefaultMapperFactory.Builder().build();
}
@Autowired//作用在方法上有参数,那么该参数注入到spring上下文中的时候调用此方法
public void mapper(MapperFactory mapperFactory) {
mapperFactory.classMap(BookDto.class, Book.class)
// .field("bookName","bname")//如果属性名不一样时需要
.byDefault()
.register();
//如果还有别的类继续往下面加
}
}
3.3使用方法,只需要两句
/**
* @Author: LJX
* @DateTime: 2022/3/12 22:03
* @Description: TODO
*/
@RestController
@RequestMapping("/book")
public class BookController {
@Resource
private IBookService ibookService;
//注入的时候会自动都要@Autoride配置方法
@Resource
private MapperFactory mapperFactory;
@PostMapping("/insert")
public Map<String ,Object> insert(@RequestBody BookDto bookDto){
System.out.println("这是生产者的insert方法");
MapperFacade mapperFacade = mapperFactory.getMapperFacade();
Book book = mapperFacade.map(bookDto,Book.class);
System.out.println("生产者BookDto"+bookDto);
Map map = new HashMap();
// book.setBookId(bookDto.getBookId());
// book.setBookName(bookDto.getBookName());
int insert = ibookService.insert(book);
map.put("msg","书本添加成功");
map.put("book",bookDto);
return map;
}
}
效果

orika番外篇
附录一:MapperFactory公共配置Bean映射DTO
@Configuration
public class ServerConfig {
@Autowired
public void config(MapperFactory mapperFactory) {
mapperFactory.getConverterFactory().registerConverter("orderStatusConvert", new OrderStatusConvert());
//添加一个Bean和Dto的映射就使用classMap,只要程序当中使用到的classMap包含的
//两个类进行转换,就会自动跳到该转换器来。
//classMap第一个参数是需要转换的参数实体
//classMap第二个参数是转换对应的参数实体
//field表示实体名称的字段不太一样,添加映射关系
//fieldMap表示字段值不一样,添加自定义转换器
//orderStatusConvert表示被mapperFactory注册过的id值,
//一个orderStatusConvert对应一个类,可以在当前类简建立一个内部类,当做自定义转换器
mapperFactory.classMap(Order.class, OrderDto.class)
.field("finallyTime", "lastTime")
.field("orderItems", "orderItemList")
.field("userAddrOrder", "orderAddress")
.fieldMap("status", "status").converter("orderStatusConvert")
.add()
.byDefault()
.register();
mapperFactory.classMap(MyOrderDto.class, OrderDto.class)
.field("orderItemDtos", "orderItemList")
.fieldMap("status", "status").converter("orderStatusConvert")
.add()
.byDefault()
.register();
mapperFactory.classMap(OrderParam.class, Order.class)
.fieldMap("status", "status").converter("orderStatusConvert")
.add()
.byDefault()
.register();
mapperFactory.classMap(NewOrderParam.class, Order.class)
.fieldMap("status", "status").converter("orderStatusConvert")
.add()
.byDefault()
.register();
// mapperFactory.classMap(String.class, Date.class);
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~