【问题标题】:Spring Cacheable unless condition doesn't workSpring Cacheable 除非条件不起作用
【发布时间】:2020-05-03 06:28:17
【问题描述】:

我在 Springboot 中开发了一个 REST 端点,它采用 String ID 并以 ModelAndView 响应。此端点标有@Cacheable 注释。现在在给定的端点上可能会发生两件事。

案例 1:请求 ID 存在于数据库中,并产生一个需要重定向到的 URL。在这种情况下,响应应该被缓存,以便在相同 ID 的连续请求时,可以从缓存中提供结果

案例 2:请求的 ID 在数据库中不存在,因此重定向应该发生在特定的 URL 上,并且在这种情况下不应该进行缓存。

下面是我的方法

@GetMapping("{id}")
    @Cacheable(value = "url-single", key = "#id", unless = "#result.view!=\"redirect:/notfound\"")
    public ModelAndView redirect(@PathVariable("id") String id, ServletRequest servletRequest,
            ServletResponse servletResponse) {
        HttpServletRequest request = HttpServletRequest.class.cast(servletRequest);
        LOG.info("Redirection request from: {} for Short URL Key: {}", request.getRemoteAddr(), id);
        try {
            Optional<String> originalUrlOptional = urlManagerService.retrieveOriginalUrl(id);
            if (originalUrlOptional.isPresent() && !StringUtils.isEmpty(originalUrlOptional.get())) {
                LOG.info("Found Original URL: {} for Short URL Key: {}", originalUrlOptional.get(), id);
                return new ModelAndView("redirect:https://" + originalUrlOptional.get());
            }

        } catch (NoSuchElementException e) {
            LOG.error("Error while redirecting: {}", e.getMessage(), e);
        }
        return new ModelAndView("redirect:/notfound");
    }

如果我从here 中正确理解,@Cacheable 中的关键字unless 适用于返回类型,并且为了访问返回类型对象的任何特定成员变量,我们必须将其称为#result.attributeName &lt;comparison&gt; &lt;value&gt;

那么为什么我的 Redis 缓存中没有存储任何内容?如果我删除 unless 条件,所有内容都会被存储。条件不正确吗?

【问题讨论】:

  • 你不能将重定向逻辑与缓存分开吗?

标签: java spring-boot caching redis spring-cache


【解决方案1】:

我一直在看你的除非声明:

unless = "#result.view!=\"redirect:/notfound\""

所以这意味着如果 result.view 没有重定向:/notfound,它将不会被缓存。

我的假设是你想要缓存它,除非重定向:/未找到。 这里有一个“双重否定”。

所以你可能应该使用:

unless = "#result.view==\"redirect:/notfound\""

(所以使用 '==' 而不是 '!=')

让我知道这是否有效!

【讨论】:

  • "#result.view=\"redirect:/notfound\"" 实际上是一个赋值。我已经尝试过"#result.view==\"redirect:/notfound\"" 并且 Redis 实际上继续并存储了它。我检查了日志以查看 Redis 中的 "HSET" "url-single" "\"123\"" "{\"@class\":\"org.springframework.web.servlet.ModelAndView\",\"cleared\":false,\"empty\":false,\"reference\":true,\"view\":\"redirect:/notfound\"}" 条目
  • 它没有。我试图实现的行为是 Redis 将忽略所有返回的 ModelAndView 对象,其 view 属性(这是一个 String 顺便说一句)等于字符串 redirect:/notfound。但是有了这个实现,它实际上会继续并存储所有内容
  • 我也有同样的问题。除非进程无法工作。这是我的代码@Cacheable(value = "employees", key = "#id", unless = "#result.get().phone.equals('111-222-3333')")。我该如何解决?
【解决方案2】:

在使用unless 条件关键字一段时间后,我发现了哪里出错了。 unless 关键字的双引号 (") 中的 #result 字面意思 是要返回的对象。这意味着,您可以调用可以在该对象上调用的任何方法。

语句"#result.view==\"redirect:/notfound\"" 失败,因为该对象没有公开任何名为view 的成员变量。使用表达式 unless = "#result.getViewName().equals(\"redirect:/notfound\")" 实际上可以解决问题,因为在返回 String 的对象上有一个方法 getViewName() 并在其上调用 equals() 进行实际比较。

我想我被困在这里是因为我不熟悉 Spring 表达式语言SpEL

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-22
    • 1970-01-01
    • 2021-07-14
    • 2015-04-05
    • 1970-01-01
    • 2017-06-01
    相关资源
    最近更新 更多