当前位置: 首页 > 知识库问答 >
问题:

微服务与可选参数请求的通信

朱承载
2023-03-14

我有一个客房服务,当我提出要求时,它会返回房间的详细信息http://localhost:8082/room/search/byRoomChar

    @GetMapping(path = "/search/byRoomChar")
    public @ResponseBody List<Room> byCapacity(@RequestParam(required = false) Integer capacity,
                                               @RequestParam(required = false) Boolean isUnderMaintenance,
                                               @RequestParam(required = false) String equipment) {
        return roomRepository.findByRoomChar(capacity, isUnderMaintenance, equipment);
    }

现在我想从预订服务请求这个@GetMapping,因为这是用户将使用http://localhost:8081/booking/search/byRoomChar.

    @GetMapping(path = "/search/byRoomChar")
    public @ResponseBody List<Room> byCapacity(@RequestParam(required = false) Integer capacity,
                                               @RequestParam(required = false) Boolean isUnderMaintenance,
                                               @RequestParam(required = false) String equipment) {
        ResponseEntity<Room[]> roomsResponse = restTemplate.getForEntity("http://localhost:8082/room/search/byRoomChar?capacity=" + capacity + "&isUnderMaintenance=" +
            isUnderMaintenance + "&equipment=" + equipment, Room[].class);
        return Arrays.asList(roomsResponse.getBody());
    }

房间实体代码:

package nl.tudelft.sem.template.entities;

import javax.persistence.Column;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "Room")
public class Room {
    @EmbeddedId
    private RoomId id;

    @Column(name = "capacity")
    private int capacity;

    @Column(name = "numberOfPeople")
    private int numberOfPeople;

    @Column(name = "isUnderMaintenance", nullable = false)
    private boolean isUnderMaintenance;

    @Column(name = "equipment")
    private String equipment;

    public Room() {
    }

    public Room(long roomNumber, long buildingNumber, int capacity,
                int numberOfPeople, boolean isUnderMaintenance, String equipment) {
        RoomId id = new RoomId(roomNumber, buildingNumber);
        this.id = id;
        this.capacity = capacity;
        this.numberOfPeople = numberOfPeople;
        this.isUnderMaintenance = isUnderMaintenance;
        this.equipment = equipment;
    }

    public RoomId getId() {
        return id;
    }

    public void setId(RoomId id) {
        this.id = id;
    }

    public int getCapacity() {
        return capacity;
    }

    public void setCapacity(int capacity) {
        this.capacity = capacity;
    }

    public int getNumberOfPeople() {
        return numberOfPeople;
    }

    public void setNumberOfPeople(int numberOfPeople) {
        this.numberOfPeople = numberOfPeople;
    }

    public boolean getIsUnderMaintenance() {
        return isUnderMaintenance;
    }

    public void setUnderMaintenance(boolean underMaintenance) {
        isUnderMaintenance = underMaintenance;
    }

    public String getEquipment() {
        return equipment;
    }

    public void setEquipment(String equipment) {
        this.equipment = equipment;
    }
}

房间存储库代码:

package nl.tudelft.sem.template.repositories;

import java.util.List;
import nl.tudelft.sem.template.entities.Room;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

@Repository
public interface RoomRepository extends JpaRepository<Room, Integer> {
    @Query("SELECT r FROM Room r WHERE (:number is null or r.id.number = :number)"
        + "and r.id.buildingNumber = :buildingNumber")
    List<Room> findByRoomNum(@Param("number") Long number,
                             @Param("buildingNumber") Long buildingNumber);

    @Query("SELECT r FROM Room r WHERE (:capacity is null or r.capacity = :capacity) and"
        + "(:isUnderMaintenance is null or r.isUnderMaintenance = :isUnderMaintenance) and"
        + "(:equipment is null or r.equipment = :equipment)")
    List<Room> findByRoomChar(@Param("capacity") Integer capacity,
                              @Param("isUnderMaintenance") Boolean isUnderMaintenance,
                              @Param("equipment") String equipment);

}

但是,这不起作用,因为当从预订服务调用getmapping时忽略参数时,由于required=false,所有参数值都将变为null。这被转换成硬编码url中的字符串。

2021-12-04 17:13:03.883  WARN 16920 --- [nio-8082-exec-1] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'java.lang.Boolean'; nested exception is java.lang.IllegalArgumentException: Invalid boolean value [null]]

如何使用代码中的可选参数提出超文本传输协议请求?

共有3个答案

江亮
2023-03-14

这是因为参数为null时生成的URI字符串如下所示:

http://localhost:8082/room/search/byRoomChar?isUnderMaintenance=null

由于“null”被附加为参数值,房间服务器无法尝试将其反序列化为其他类型。例如,在您给出的错误消息中,表示“isUnderMaintenance”应为布尔值,但为“null”字符串。

为了解决这个问题,我建议使用UriComponentBuilder

@Test
fun constructUriWithQueryParameter() {
    val uri = UriComponentsBuilder.newInstance()
        .scheme("http")
        .host("localhost")
        .port(8082)
        .path("/room/search/byRoomChar")
        .query("capacity={capa}")
        .query("isUnderMaintenance={isUnderMaintenance}")
        .query("equipment={equip}")
        .buildAndExpand(null, null, null)
        .toUriString()
    assertEquals(
        "http://localhost:8082/room/search/byRoomChar 
             capacity=&isUnderMaintenance=&equipment=",
        uri
    )
}
谭绍晖
2023-03-14

如果这些参数在房间API中不是强制性的,但在对数据库的调用中仍然使用它们,那么如果用户实际上没有提供这些参数,则可以使用合理的默认值。大致如下(在本例中,您实际上不需要明确定义required=false):

@GetMapping(path = "/search/byRoomChar")
public @ResponseBody List<Room> byCapacity(@RequestParam(defaultValue = "10") Integer capacity,
                                           @RequestParam(defaultValue = "false") Boolean isUnderMaintenance,
                                           @RequestParam(defaultValue = "default-equipment") String equipment) {
    return roomRepository.findByRoomChar(capacity, isUnderMaintenance, equipment);
}

或者定义一个没有额外参数的存储库方法,但这可能会更棘手,因为基本上需要所有可能的空参数和非空参数。

益阳平
2023-03-14

UriComponentsBuilder可以帮助构建URI。它正确地处理可为空的查询参数

String uri = UriComponentsBuilder.fromHttpUrl("http://localhost:8082/room/search/byRoomChar")
            .queryParam("capacity", capacity)
            .queryParam("isUnderMaintenance", isUnderMaintenance)
            .queryParam("equipment", equipment)
            .encode().toUriString();
ResponseEntity<Room[]> roomsResponse = restTemplate.getForEntity(uri, Room[].class);

此外,以下答案可能会有所帮助:https://stackoverflow.com/a/25434451/5990117

 类似资料:
  • 我实际上在研究微服务,我面临一个问题。 上下文 我正在开发两个微服务: 用户管理,基于spring,使用MySQL数据库 计划管理,基于ASP.NET与SQL Server数据库。此服务的唯一访问点是列出一些RESTFULendpoint的API,如 计费管理,基于MongoDB的node.js。 问题 > 我该怎么做才能只允许通过用户服务访问规划信息,而不耦合这两个服务?知道以后可以从其他地方访

  • 问题内容: 我在玩,我想知道是否有可能在向服务器发出的请求中包含“可选”参数。 我想成功访问这两种方法: 如您所见,我正在尝试使integer()参数成为可选参数。 我声明如下: 这有效: 这也有效: 但这 行不通 ,我也不明白为什么。它抛出一个错误: 您能为我指出正确的方向进行解决吗?我不希望在所有REST方法调用中都必须使用斜杠,并且希望在可能的情况下取消斜杠。 问题答案: 因此,在仔细研究了

  • 我正在构建一个基于Spring云的微服务ML管道。我有一个数据摄取服务,它(当前)从SQL接收数据,这些数据需要被预测服务使用。 普遍的共识是写入应该使用kafka/Rabbitmq使用基于异步消息的通信。 我不确定的是如何编排这些服务? 我是否应该使用API网关来调用启动管道的摄取?

  • 假客户端支持可选请求参数吗? 例如,我有一个endpoint,但我没有找到一种方法,可以使用feign client使param1成为可选的。

  • 我正在使用microservies Architect学习API。下面是关于设置的小描述 我有两个微服务应用程序和API网关 包括API网关在内的所有应用程序都是NodeJS-Express app。 Auth Logic-JWT,在API网关上处理 使用http-proxy将每个传入的API网关请求传递给每个微服务应用程序。 还将用户信息作为代理头传递。 客户端请求流: 客户端使用JWT令牌从m