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

使用Spring和反应器的API组合物(BFF)

傅峻
2023-03-14

假设我有两个微服务,我想在使用WebFlux的Spring REST控制器中实现BFF(前端的后端)模式。

来自2个远程服务的域对象是:

public class Comment {
    private Long id;
    private String text;
    private Long authorId;
    private Long editorId;
}

public class Person {
    private Long id;
    private String firstName;
    private String lastName;
}

并且API编写器必须返回以下类型的对象:

public class ComposedComment {
    private String text;
    private String authorFullName;
    private String editorFullName;
}

为了简洁起见,我编写了一个控制器,它将所有服务模拟在一个。

@RestController
@RequestMapping("/api")
public class Controller {

    private static final List<Comment> ALL_COMMENTS = Arrays.asList(//
            new Comment(1L, "Bla bla", 1L, null), //
            new Comment(2L, "lorem ipsum", 2L, 3L), //
            new Comment(3L, "a comment", 2L, 1L));
    private static final Map<Long, Person> PERSONS;

    static {
        PERSONS = new HashMap<>();
        PERSONS.put(1L, new Person(1L, "John", "Smith"));
        PERSONS.put(2L, new Person(2L, "Paul", "Black"));
        PERSONS.put(3L, new Person(3L, "Maggie", "Green"));
    }

    private WebClient clientCommentService = WebClient.create("http://localhost:8080/api");
    private WebClient clientPersonService = WebClient.create("http://localhost:8080/api");

    @GetMapping("/composed/comments")
    public Flux<ComposedComment> getComposedComments() {
     //This is the tricky part
    }

    private String extractFullName(Map<Long, Person> map, Long personId) {
        Person person = map.get(personId);
        return person == null ? null : person.getFirstName() + " " + person.getLastName();
    }

    @GetMapping("/comments")
    public ResponseEntity<List<Comment>> getAllComments() {
        return new ResponseEntity<List<Comment>>(ALL_COMMENTS, HttpStatus.OK);
    }

    @GetMapping("/persons/{personIds}")
    public ResponseEntity<List<Person>> getPersonsByIdIn(@PathVariable("personIds") Set<Long> personIds) {
        List<Person> persons = personIds.stream().map(id -> PERSONS.get(id)).filter(person -> person != null)
                .collect(Collectors.toList());
        return new ResponseEntity<List<Person>>(persons, HttpStatus.OK);
    }
}

我的问题是我刚刚开始与反应堆,我不是真的确定我在做什么…这是我的composer方法的当前版本:

@GetMapping("/composed/comments")
public Flux<ComposedComment> getComposedComments() {
    Flux<Comment> commentFlux = clientCommentService.get().uri("/comments").retrieve().bodyToFlux(Comment.class);
    Set<Long> personIds = commentFlux.toStream().map(comment -> Arrays.asList(comment.getAuthorId(), comment.getEditorId())).flatMap(Collection::stream).filter(Objects::nonNull).collect(Collectors.toSet());
    Map<Long, Person> personsById = clientPersonService.get().uri("/persons/{ids}", personIds.stream().map(Object::toString).collect(Collectors.joining(","))).retrieve().bodyToFlux(Person.class).collectMap(Person::getId).block();
    return commentFlux.map(
            comment -> new ComposedComment(
                    comment.getText(),
                    extractFullName(personsById, comment.getAuthorId()),
                    extractFullName(personsById, comment.getEditorId()))
    );
}

它可以工作,但是我知道我应该用map、flatMap和zip进行几个转换,而不是调用block()和toStream()...你能帮我正确地重写这个方法吗?:)

共有1个答案

酆阳煦
2023-03-14

您正在控制器中返回null。将其替换为返回反应流。

return commentFlux.flatMap(comment -> ....)
....

您的控制器签名返回

Flux<ComposedComment>

所以确保在最后一次返回中,您必须使用flatMap或map将它们转换为ComposedComment。您可以将其视为一个promise链,在该链中您可以在实现中执行许多flatMap、map,以转换为最终的数据集。

 类似资料:
  • 我正在尝试将Spring Cloud Contract应用于使用Spring WebFlux构建的反应API。基本上能够以以下方式从API发送通量和接收响应通量: 但是,我在网上或文档中找不到关于我是否可以使用Spring Cloud Contract实现这一点的信息。 甚至有可能为此写一份合同吗?它是否能够提供wiremock并生成适当的JUnit测试?

  • 我发现在Hyperledger composer playground中,任何人都可以删除当前的商业网络。我如何限制它,使只有管理员可以删除他们自己的业务网络?

  • 从我的角度来看,我认为可以有一种方法在代码中明确我的Rest API是反应性的,但可能是我不知道的。

  • 问题内容: 我创建了以下聚合物元素: 我这样做是在我的index.html中调用此方法: 我期望对于todo数组中返回的每个对象,都会打印出一个。但是,当我运行该应用程序时,我在控制台中得到以下输出: 未捕获的TypeError:无法读取未定义的属性“ todos” 在 我不确定这里发生了什么以及如何引用从ajax响应接收回的数据。 问题答案: 将头撞在墙上几个小时后,我设法解决了这个问题。我创建

  • 我用的是Spring助焊剂。我需要从不同的来源组装一个物体。如何确保两个流都返回了所需的数据? 比如:

  • 在前端使用React,后端使用RESTful API,并通过JSON Web令牌(JWT)进行授权,我们如何处理会话?例如,在登录之后,我从REST获得一个JWT令牌。如果我把它保存到localStorage中,我就容易受到XSS的攻击,如果我把它保存到cookie,除了我把cookie设置为HttpOnly,但是React不能读取HttpOnly cookie(我需要读取cookie以从中获取J