RuoYi-Cloud-Plus 使用 Apache Dubbo 3.X 作为 RPC 远程调用框架,替代传统的 Feign 调用。
| 概念 | 说明 |
|---|---|
| Provider | 服务提供者,暴露服务 |
| Consumer | 服务消费者,调用服务 |
| Interface | 服务接口定义 |
| Registry | 注册中心(Nacos) |
package org.dromara.backstage.api;
import org.dromara.backstage.api.domain.dto.RemoteRoomDto;
import org.dromara.backstage.api.domain.dto.RemoteRoomQueryDto;
import org.dromara.common.core.domain.R;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import java.util.List;
/**
* 房间信息远程调用接口
*/
public interface RemotePtRoomService {
/**
* 根据ID查询房间
*/
R<RemoteRoomDto> selectRoomById(Long roomId);
/**
* 查询房间列表
*/
List<RemoteRoomDto> selectRoomList();
/**
* 分页查询房间列表
*/
TableDataInfo<RemoteRoomDto> selectRoomPage(RemoteRoomQueryDto queryDto);
/**
* 新增房间
*/
R<Void> insertRoom(RemoteRoomDto dto);
/**
* 修改房间
*/
R<Void> updateRoom(RemoteRoomDto dto);
/**
* 删除房间
*/
R<Void> deleteRoomByIds(Long[] ids);
}
package org.dromara.backstage.api.domain.dto;
import lombok.Data;
import java.io.Serializable;
/**
* 房间信息DTO
*/
@Data
public class RemoteRoomDto implements Serializable {
private static final long serialVersionUID = 1L;
/** 房间ID */
private Long roomId;
/** 房间名称 */
private String roomName;
/** 房间编码 */
private String roomCode;
/** 所属区域ID */
private Long areaId;
/** 房间类型 */
private String roomType;
/** 容纳人数 */
private Integer capacity;
}
package org.dromara.backstage.api.domain.dto;
import lombok.Data;
import java.io.Serializable;
/**
* 房间查询DTO
*/
@Data
public class RemoteRoomQueryDto implements Serializable {
private static final long serialVersionUID = 1L;
/** 页码 */
private Integer pageNum = 1;
/** 每页条数 */
private Integer pageSize = 10;
/** 房间名称(模糊查询) */
private String roomName;
/** 房间编码(精确查询) */
private String roomCode;
/** 所属区域ID */
private Long areaId;
/** 房间类型 */
private String roomType;
}
package org.dromara.backstage.basics.dubbo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboService;
import org.dromara.backstage.api.RemotePtRoomService;
import org.dromara.backstage.api.domain.dto.RemoteRoomDto;
import org.dromara.backstage.api.domain.dto.RemoteRoomQueryDto;
import org.dromara.backstage.basics.domain.bo.PtRoomBo;
import org.dromara.backstage.basics.domain.vo.PtRoomVo;
import org.dromara.backstage.basics.service.IPtRoomService;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* 房间信息远程服务实现
*/
@Slf4j
@RequiredArgsConstructor
@Service
@DubboService
public class RemotePtRoomServiceImpl implements RemotePtRoomService {
private final IPtRoomService roomService;
@Override
public R<RemoteRoomDto> selectRoomById(Long roomId) {
PtRoomVo vo = roomService.queryById(roomId);
if (vo == null) {
return R.fail("房间不存在");
}
return R.ok(convertToDto(vo));
}
@Override
public List<RemoteRoomDto> selectRoomList() {
PtRoomBo bo = new PtRoomBo();
List<PtRoomVo> voList = roomService.queryList(bo);
return MapstructUtils.convert(voList, RemoteRoomDto.class);
}
@Override
public TableDataInfo<RemoteRoomDto> selectRoomPage(RemoteRoomQueryDto queryDto) {
// 1. 构建分页参数
PageQuery pageQuery = new PageQuery();
pageQuery.setPageNum(queryDto.getPageNum() != null ? Math.max(queryDto.getPageNum(), 1) : 1);
pageQuery.setPageSize(queryDto.getPageSize() != null ? Math.min(Math.max(queryDto.getPageSize(), 1), 500) : 10);
// 2. 构建查询条件
PtRoomBo bo = new PtRoomBo();
bo.setRoomName(queryDto.getRoomName());
bo.setRoomCode(queryDto.getRoomCode());
bo.setAreaId(queryDto.getAreaId());
bo.setRoomType(queryDto.getRoomType());
// 3. 执行查询
TableDataInfo<PtRoomVo> result = roomService.queryPageList(bo, pageQuery);
// 4. 转换结果
List<RemoteRoomDto> dtoList = MapstructUtils.convert(result.getRows(), RemoteRoomDto.class);
// 5. 构建返回
TableDataInfo<RemoteRoomDto> pageData = TableDataInfo.build();
pageData.setRows(dtoList);
pageData.setTotal(result.getTotal());
return pageData;
}
@Override
public R<Void> insertRoom(RemoteRoomDto dto) {
PtRoomBo bo = MapstructUtils.convert(dto, PtRoomBo.class);
roomService.insertByBo(bo);
return R.ok();
}
@Override
public R<Void> updateRoom(RemoteRoomDto dto) {
PtRoomBo bo = MapstructUtils.convert(dto, PtRoomBo.class);
roomService.updateByBo(bo);
return R.ok();
}
@Override
public R<Void> deleteRoomByIds(Long[] ids) {
roomService.deleteWithValidByIds(List.of(ids), false);
return R.ok();
}
/**
* 手动转换方法(复杂场景使用)
*/
private RemoteRoomDto convertToDto(PtRoomVo vo) {
if (vo == null) {
return null;
}
RemoteRoomDto dto = new RemoteRoomDto();
dto.setRoomId(vo.getRoomId());
dto.setRoomName(vo.getRoomName());
dto.setRoomCode(vo.getRoomCode());
dto.setAreaId(vo.getAreaId());
dto.setRoomType(vo.getRoomType());
dto.setCapacity(vo.getCapacity());
return dto;
}
}
package org.dromara.ecs.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import lombok.RequiredArgsConstructor;
import org.apache.dubbo.config.annotation.DubboReference;
import org.dromara.backstage.api.RemotePtRoomService;
import org.dromara.backstage.api.domain.dto.RemoteRoomDto;
import org.dromara.backstage.api.domain.dto.RemoteRoomQueryDto;
import org.dromara.common.core.domain.R;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.web.core.BaseController;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 房间信息控制器
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/ecs/room")
public class RoomController extends BaseController {
@DubboReference
private RemotePtRoomService remotePtRoomService;
/**
* 查询房间列表
*/
@SaCheckPermission("ecs:room:list")
@GetMapping("/list")
public TableDataInfo<RemoteRoomDto> list(RemoteRoomQueryDto queryDto) {
return remotePtRoomService.selectRoomPage(queryDto);
}
/**
* 获取房间详细信息
*/
@SaCheckPermission("ecs:room:list")
@GetMapping("/{roomId}")
public R<RemoteRoomDto> getInfo(@PathVariable Long roomId) {
return remotePtRoomService.selectRoomById(roomId);
}
/**
* 获取所有房间列表(不分页)
*/
@SaCheckPermission("ecs:room:list")
@GetMapping("/all")
public R<List<RemoteRoomDto>> all() {
return R.ok(remotePtRoomService.selectRoomList());
}
}
@DubboReference(async = true)
private RemotePtRoomService remotePtRoomService;
public void asyncCall() {
// 发起异步调用
remotePtRoomService.selectRoomById(1L);
// 获取异步结果
CompletableFuture<RemoteRoomDto> future = RpcContext.getContext().getCompletableFuture();
future.whenComplete((result, exception) -> {
if (exception != null) {
log.error("调用失败", exception);
} else {
log.info("调用成功:{}", result);
}
});
}
检查 @DubboService 注解是否正确添加,以及 Nacos 注册中心是否正常运行。
在 application.yml 中配置超时时间:
dubbo:
consumer:
timeout: 5000 # 5秒
避免模块间的循环依赖,通过接口层解耦。
确保所有服务的 Dubbo 版本一致。
R<T> 包装,统一错误处理