首页   注册   登录
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX  ›  程序员

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

  •  
  •   qwerthhusn · 3 天前 · 246 次点击

    首先需求,是做一个短网址的服务,之前用 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 就懵逼了 我是这方面的新人,而且没有人指导,全靠自己想和骨锅。可能是自己用错了,请大神指点迷津!
    目前尚无回复
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   783 人在线   最高记录 5043   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.3 · 22ms · UTC 18:32 · PVG 02:32 · LAX 11:32 · JFK 14:32
    ♥ Do have faith in what you're doing.