有熟悉 WebFlux 或其他任何响应式编程的 V 友么,有个问题需要帮忙!

2019-09-12 15:16:28 +08:00
 qwerthhusn

首先需求,是做一个短网址的服务,之前用 Spring MVC 的时候的代码,非常直观明了

@PostMapping("/generate")
public Map<String, String> generate(@RequestBody Map<String, String> map) {
    if (!"sdjsioadijosaoidsa".equals(map.get("token"))) {
        throw new RuntimeException("无权限");
    }

    String url = map.get("url");
    Assert.isTrue(!StringUtils.isEmpty(url), "url absent");
    byte[] sha256 = DigestUtils.sha256(url);
    String path = redisOpt.get(sha256);
    if (path == null) {
        path = RandomStringUtils.randomAlphanumeric(6);
        redisOpt.set(path.getBytes(StandardCharsets.ISO_8859_1), url, 365, TimeUnit.DAYS);
        redisOpt.set(sha256, path, 365, TimeUnit.DAYS);
    }

    return ImmutableMap.of("url", urlPrefix + path);
}

然后换了 WebFlux,尝试写一下比较 Reactive 风格的代码

public Mono<ServerResponse> generate(ServerRequest serverRequest) {
    return serverRequest.bodyToMono(String.class).map(JSON::parseObject)
            .flatMap(jsonObject -> {
                if (!"sdjsioadijosaoidsa".equals(jsonObject.get("token"))) {
                    return ServerResponse.status(HttpStatus.UNAUTHORIZED)
                            .contentType(MediaType.APPLICATION_JSON_UTF8)
                            .syncBody(ImmutableMap.of("errorMsg", "no privilege"));
                }
                String url = jsonObject.getString("url");
                if (StringUtils.isEmpty(url)) {
                    return ServerResponse.status(HttpStatus.BAD_REQUEST)
                            .contentType(MediaType.APPLICATION_JSON_UTF8)
                            .syncBody(ImmutableMap.of("errorMsg", "url is absent"));
                }
                byte[] sha256 = DigestUtils.sha256(url);
                return redisTemplate.opsForValue().get(sha256)
                        .flatMap(path -> ServerResponse.ok()
                                .contentType(MediaType.APPLICATION_JSON_UTF8)
                                .syncBody(ImmutableMap.of("url", urlPrefix + path)))
                        .switchIfEmpty(Mono.just(RandomStringUtils.randomAlphanumeric(6))
                                .filterWhen(newPath -> redisTemplate.opsForValue()
                                        .set(newPath.getBytes(), url, Duration.ofDays(365)))
                                .filterWhen(newPath -> redisTemplate.opsForValue()
                                        .set(sha256, newPath, Duration.ofDays(365)))
                                .flatMap(newPath -> ServerResponse.ok()
                                        .contentType(MediaType.APPLICATION_JSON_UTF8)
                                        .syncBody(ImmutableMap.of("url", urlPrefix + newPath)))
                                .switchIfEmpty(ServerResponse.status(HttpStatus.INTERNAL_SERVER_ERROR)
                                        .contentType(MediaType.APPLICATION_JSON_UTF8)
                                        .syncBody(ImmutableMap.of("errorMsg", "Internal Server Error"))));
            });
}

这个代码,说实话,一周后估计我自己都看不懂了。
其实我想问一下,针对逻辑稍微比较复杂的时候,响应式编程该怎么做,尤其是对这种条件分支比较多的时候。 这个代码该怎么优化?

现在我做的分支处理不外乎两种方式

  1. flatMap,拿到数据,然后就是写 if-else。这种方式有些不好用的地方,就是数据在上个流没下来,压根就进不了 flatMap (比如例子中的 redis 未命中数据)
  2. switchIfEmpty,在 switchIfEmpty 之前,分支使用 filter|filterWhen 这些,stream.filterWhen(if 条件).xxx(if 分支).switchIfEmpty(else 分支)。在这种情况下做 if-elseif 就懵逼了 我是这方面的新人,而且没有人指导,全靠自己想和骨锅。可能是自己用错了,请大神指点迷津!
1361 次点击
所在节点    程序员
0 条回复

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/600404

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX