Spring Cacheable, если условие не работает - PullRequest
1 голос
/ 16 января 2020

Я разработал конечную точку REST в Springboot, которая принимает String ID и отвечает ModelAndView. Эта конечная точка помечена @Cacheable аннотацией. Теперь есть две вещи, которые могут произойти в данной конечной точке.

Случай 1: Идентификатор запроса существует в БД и дает URL, на который должно произойти перенаправление. В этом случае ответ должен кэшироваться таким образом, чтобы при последовательных запросах одного и того же идентификатора результат мог передаваться из кэша

Случай 2. Запрашиваемый идентификатор не существует в БД и, следовательно, должно происходить перенаправление в этом сценарии должен быть указан c 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");
    }

Если я правильно понял из здесь , ключевое слово unless в @Cacheable применяется к возвращаемому типу , и для доступа к любой конкретной переменной-члену объекта возвращаемого типа мы должны ссылаться на него как #result.attributeName <comparison> <value>.

Так почему же в моем кэше Redis ничего не хранится? Если я уберу условие unless, все будет сохранено. Неправильно ли состояние?

Ответы [ 2 ]

0 голосов
/ 16 января 2020

Я нашел, где я ошибался, некоторое время играя с условным ключевым словом unless. #result внутри двойных кавычек (") ключевого слова unless означает буквально возвращаемый объект. Это означает, что вы можете вызывать любой метод, который можно вызвать для этого объекта.

Оператор "#result.view==\"redirect:/notfound\"" не удался, потому что объект не предоставил никакой переменной-члена с именем view. Использование выражения unless = "#result.getViewName().equals(\"redirect:/notfound\")" действительно помогло, потому что в объекте, который возвратил String, был метод getViewName() и вызов equals() для этого сделал реальное сравнение.

Я думаю, что застрял здесь, потому что я не был знаком с Spring Expression Language или SpEL

0 голосов
/ 16 января 2020

Я смотрел на ваше утверждение, если:

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

, так что это означает, что он НЕ БУДЕТ кэшироваться, если result.view НЕ перенаправлен: /notfound.

Мое предположение что вы хотите его кэшировать, кроме случаев, когда редирект: / notfound. Здесь есть «двойной отрицательный».

Так что вы, вероятно, должны использовать:

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

(поэтому используйте '==' вместо '! =')

Дайте мне знать, если это работает!

...