Как предварительно загрузить общий ресурс в Spring Boot RestController?

У меня есть контроллер с RequestMapping(foo/{fooId}/bar/}), FooEntity используется во всех методах, как я могу предварительно загрузить FooEntity для всех методов FooController?

@RestController
@RequestMapping("foo/{fooId}/bar")
public class FooController {

  public void prefetchFoo(@PathVariable Long fooId) {
   ...
  }
  
  @PostMapping("/")
  public ResponseEntity<void> createFooBar(FooEntity prefetchedFoo) {
   ...
  }

 
  @GetMapping("/{barId}")
  public ResponseEntity<void> getFooBar(FooEntity prefetchedFoo) {
   ...
  }

}

В своих исследованиях я нашел @ModelAttribute, но видел это только в контексте веб-представлений. Можно ли использовать его в контексте API JSON?

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
4
0
59
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вы можете использовать @ModelAttribute в контексте API JSON. Метод @ModelAttribute будет вызываться перед каждым методом обработчика запроса и может заполнить атрибут модели необходимыми данными. Это применимо независимо от того, создает ли ваш API представления или ответы JSON.

@RestController
@RequestMapping("foo/{fooId}/bar")
public class FooController {
@Autowired
private FooService fooService;

@ModelAttribute
public FooEntity prefetchFoo(@PathVariable Long fooId) {
    // Logic to fetch FooEntity based on fooId
    return fooService.findFooById(fooId);
}

@PostMapping("/")
public ResponseEntity<Void> createFooBar(@ModelAttribute FooEntity prefetchedFoo) {
    ...
    return ResponseEntity.ok().build();
}

@GetMapping("/{barId}")
public ResponseEntity<FooEntity> getFooBar(@PathVariable Long barId, @ModelAttribute FooEntity prefetchedFoo) {
   ...
    return ResponseEntity.ok(prefetchedFoo);
}
}

Простой способ

Используйте свой FooService

@RestController
@RequestMapping("/foo/{fooId}/bar")
public class FooController {

    @Autowired
    private FooService fooService;

    @PostMapping("/")
    public ResponseEntity<Void> createFooBar(
            @PathVariable Long fooId,
            @RequestBody(required = false) SomeRequest request
    ) {
        FooEntity prefetchedFoo = fooService.getFooById(fooId);
        System.out.println(prefetchedFoo);
        return ResponseEntity.ok().build();
    }

    @GetMapping("/{barId}")
    public ResponseEntity<Void> getFooBar(
            @PathVariable Long fooId,
            @PathVariable Long barId
    ) {
        FooEntity prefetchedFoo = fooService.getFooById(fooId);
        System.out.println("barId " + barId);
        System.out.println(prefetchedFoo);
        return ResponseEntity.ok().build();
    }
}

Гиковский путь

Шаг 1. Создайте аннотацию

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface PreloadedFoo {
}

Шаг 2. Реализуйте HandlerMethodArgumentResolver.

HandlerMethodArgumentResolver — это интерфейс стратегии для преобразования параметров метода в значения аргументов в контексте данного запроса.

supportsParameter() метод проверяет, поддерживается ли данный параметр метода этим преобразователем.

resolveArgument() метод преобразует параметр метода в значение аргумента из данного запроса.

@Component
public class FooEntityArgumentResolver implements HandlerMethodArgumentResolver {

    @Autowired
    private FooService fooService;

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.getParameterAnnotation(PreloadedFoo.class) != null
                && parameter.getParameterType().equals(FooEntity.class);
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
                                  NativeWebRequest webRequest, WebDataBinderFactory binderFactory
    ) throws Exception {
        // Extract path variable from the request attributes
        @SuppressWarnings("unchecked")
        Map<String, String> pathVariables = (Map<String, String>) webRequest.getAttribute(
                HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST);

        String fooIdParam = pathVariables != null ? pathVariables.get("fooId") : null;

        // use getParameter() if you want to pass the fooId as requestParam
        // webRequest.getParameter("requestParam");
        if (fooIdParam != null) {
            Long fooId = Long.parseLong(fooIdParam);
            return fooService.getFooById(fooId);
        }
        throw new IllegalArgumentException("fooId parameter is required");
    }
}

Шаг 3. Зарегистрируйте преобразователь

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Autowired
    private FooEntityArgumentResolver fooEntityArgumentResolver;

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        resolvers.add(fooEntityArgumentResolver);
    }
}

Добавьте в комментариях, если вам нужны дополнительные разъяснения.

Цель предварительной выборки заключается в том, что она будет использоваться во всех методах, поэтому я хочу избежать повторения кода. В чем будут отличия от варианта 2 и использования @ModelAttribute?

udduu 02.08.2024 15:08

Другие вопросы по теме